Commit 2a60cc12 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

enable 'Optimized for transactions'configuration checkbox if innodb is compiled in

parent ad7b636d
...@@ -99,6 +99,9 @@ GET_TARGET_PROPERTY(upgrade_wizard_location mysql_upgrade_wizard LOCATION) ...@@ -99,6 +99,9 @@ GET_TARGET_PROPERTY(upgrade_wizard_location mysql_upgrade_wizard LOCATION)
IF(NOT upgrade_wizard_location) IF(NOT upgrade_wizard_location)
SET(EXTRA_WIX_PREPROCESSOR_FLAGS "-dHaveUpgradeWizard=0") SET(EXTRA_WIX_PREPROCESSOR_FLAGS "-dHaveUpgradeWizard=0")
ENDIF() ENDIF()
IF(WITH_INNOBASE_STORAGE_ENGINE OR WITH_INNODB_STORAGE_ENGINE OR WITH_XTRADB_STORAGE_ENGINE)
SET(EXTRA_WIX_PREPROCESSOR_FLAGS ${EXTRA_WIX_PREPROCESSOR_FLAGS} "-dHaveInnodb=1")
ENDIF()
IF(NOT CPACK_WIX_UI) IF(NOT CPACK_WIX_UI)
SET(CPACK_WIX_UI "MyWixUI_Mondo") SET(CPACK_WIX_UI "MyWixUI_Mondo")
......
...@@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ ...@@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <winservice.h> #include <winservice.h>
#define ONE_MB 1048576
UINT ExecRemoveDataDirectory(wchar_t *dir) UINT ExecRemoveDataDirectory(wchar_t *dir)
{ {
/* Strip stray backslash */ /* Strip stray backslash */
...@@ -436,16 +437,49 @@ LExit: ...@@ -436,16 +437,49 @@ LExit:
return WcaFinalize(er); return WcaFinalize(er);
} }
/*
Get maximum size of the buffer process can allocate.
this is calculated as min(RAM,virtualmemorylimit)
For 32bit processes, virtual address memory is 2GB (x86 OS)
or 4GB(x64 OS).
Fragmentation due to loaded modules, heap and stack
limit maximum size of continous memory block further,
so that limit for 32 bit process is about 1200 on 32 bit OS
or 2000 MB on 64 bit OS(found experimentally).
*/
unsigned long long GetMaxBufferSize(unsigned long long totalPhys)
{
#ifdef _M_IX86
BOOL wow64;
if (IsWow64Process(GetCurrentProcess(), &wow64))
return min(totalPhys, 2000ULL*ONE_MB);
else
return min(totalPhys, 1200ULL*ONE_MB);
#else
return totalPhys;
#endif
}
/*
Checks SERVICENAME, PORT and BUFFERSIZE parameters
*/
extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall) extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall)
{ {
wchar_t ServiceName[MAX_PATH]={0}; wchar_t ServiceName[MAX_PATH]={0};
wchar_t SkipNetworking[MAX_PATH]={0}; wchar_t SkipNetworking[MAX_PATH]={0};
wchar_t QuickConfig[MAX_PATH]={0};
wchar_t Port[6]; wchar_t Port[6];
wchar_t BufferPoolSize[16];
DWORD PortLen=6; DWORD PortLen=6;
bool haveInvalidPort=false; bool haveInvalidPort=false;
const wchar_t *ErrorMsg=0; const wchar_t *ErrorMsg=0;
HRESULT hr= S_OK;
UINT er= ERROR_SUCCESS;
hr = WcaInitialize(hInstall, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized.");
DWORD ServiceNameLen = MAX_PATH; DWORD ServiceNameLen = MAX_PATH;
MsiGetPropertyW (hInstall, L"SERVICENAME", ServiceName, &ServiceNameLen); MsiGetPropertyW (hInstall, L"SERVICENAME", ServiceName, &ServiceNameLen);
...@@ -454,7 +488,7 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall) ...@@ -454,7 +488,7 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall)
if(ServiceNameLen > 256) if(ServiceNameLen > 256)
{ {
ErrorMsg= L"Invalid service name. The maximum length is 256 characters."; ErrorMsg= L"Invalid service name. The maximum length is 256 characters.";
goto err; goto LExit;
} }
for(DWORD i=0; i< ServiceNameLen;i++) for(DWORD i=0; i< ServiceNameLen;i++)
{ {
...@@ -464,7 +498,7 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall) ...@@ -464,7 +498,7 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall)
ErrorMsg = ErrorMsg =
L"Invalid service name. Forward slash and back slash are forbidden." L"Invalid service name. Forward slash and back slash are forbidden."
L"Single and double quotes are also not permitted."; L"Single and double quotes are also not permitted.";
goto err; goto LExit;
} }
} }
if(CheckServiceExists(ServiceName)) if(CheckServiceExists(ServiceName))
...@@ -472,7 +506,7 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall) ...@@ -472,7 +506,7 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall)
ErrorMsg= ErrorMsg=
L"A service with the same name already exists. " L"A service with the same name already exists. "
L"Please use a different name."; L"Please use a different name.";
goto err; goto LExit;
} }
} }
...@@ -508,7 +542,7 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall) ...@@ -508,7 +542,7 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall)
{ {
ErrorMsg = ErrorMsg =
L"Invalid port number. Please use a number between 1025 and 65535."; L"Invalid port number. Please use a number between 1025 and 65535.";
goto err; goto LExit;
} }
short port = (short)_wtoi(Port); short port = (short)_wtoi(Port);
...@@ -517,15 +551,133 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall) ...@@ -517,15 +551,133 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall)
ErrorMsg = ErrorMsg =
L"The TCP Port you selected is already in use. " L"The TCP Port you selected is already in use. "
L"Please choose a different port."; L"Please choose a different port.";
goto err; goto LExit;
} }
} }
err:
DWORD QuickConfigLen = MAX_PATH;
MsiGetPropertyW (hInstall, L"STDCONFIG", QuickConfig, &QuickConfigLen);
if(QuickConfig[0] !=0)
{
MEMORYSTATUSEX memstatus;
memstatus.dwLength =sizeof(memstatus);
wchar_t invalidValueMsg[256];
if (!GlobalMemoryStatusEx(&memstatus))
{
WcaLog(LOGMSG_STANDARD, "Error %u from GlobalMemoryStatusEx",
GetLastError());
er= ERROR_INSTALL_FAILURE;
goto LExit;
}
DWORD BufferPoolSizeLen= 16;
MsiGetPropertyW(hInstall, L"BUFFERPOOLSIZE", BufferPoolSize, &BufferPoolSizeLen);
/* Strip spaces */
for(DWORD i=BufferPoolSizeLen-1; i > 0; i--)
{
if(BufferPoolSize[i]== ' ')
BufferPoolSize[i] = 0;
}
unsigned long long availableMemory=
GetMaxBufferSize(memstatus.ullTotalPhys)/ONE_MB;
swprintf_s(invalidValueMsg,
L"Invalid buffer pool size. Please use a number between 1 and %llu",
availableMemory);
if(BufferPoolSizeLen == 0 || BufferPoolSizeLen > 15)
{
ErrorMsg= invalidValueMsg;
goto LExit;
}
for (DWORD i=0; i < BufferPoolSizeLen && BufferPoolSize[BufferPoolSizeLen];
i++)
{
if(BufferPoolSize[i]< '0' || BufferPoolSize[i] > '9')
{
ErrorMsg= invalidValueMsg;
goto LExit;
}
}
BufferPoolSize[BufferPoolSizeLen]=0;
MsiSetPropertyW(hInstall, L"BUFFERPOOLSIZE", BufferPoolSize);
long long sz = _wtoi64(BufferPoolSize);
if(sz <= 0 || sz > (long long)availableMemory)
{
if(sz > 0)
{
swprintf_s(invalidValueMsg,
L"Value for buffer pool size is too large."
L"Only approximately %llu MB is available for allocation."
L"Please use a number between 1 and %llu.",
availableMemory, availableMemory);
}
ErrorMsg= invalidValueMsg;
goto LExit;
}
}
LExit:
MsiSetPropertyW (hInstall, L"WarningText", ErrorMsg); MsiSetPropertyW (hInstall, L"WarningText", ErrorMsg);
return ERROR_SUCCESS; return WcaFinalize(er);
} }
/*
Sets Innodb buffer pool size (1/8 of RAM by default), if not already specified
via command line.
Calculates innodb log file size as min(50, innodb buffer pool size/8)
*/
extern "C" UINT __stdcall PresetDatabaseProperties(MSIHANDLE hInstall)
{
unsigned long long InnodbBufferPoolSize= 256;
unsigned long long InnodbLogFileSize= 50;
wchar_t buff[MAX_PATH];
UINT er = ERROR_SUCCESS;
HRESULT hr= S_OK;
MEMORYSTATUSEX memstatus;
hr = WcaInitialize(hInstall, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized.");
/* Check if bufferpoolsize parameter was given on the command line*/
DWORD BufferPoolsizeParamLen = MAX_PATH;
MsiGetPropertyW(hInstall, L"BUFFERPOOLSIZE", buff, &BufferPoolsizeParamLen);
if (BufferPoolsizeParamLen && buff[0])
{
WcaLog(LOGMSG_STANDARD, "BUFFERPOOLSIZE=%s, len=%u",buff, BufferPoolsizeParamLen);
InnodbBufferPoolSize= _wtoi64(buff);
}
else
{
memstatus.dwLength = sizeof(memstatus);
if (!GlobalMemoryStatusEx(&memstatus))
{
WcaLog(LOGMSG_STANDARD, "Error %u from GlobalMemoryStatusEx",
GetLastError());
er= ERROR_INSTALL_FAILURE;
goto LExit;
}
unsigned long long totalPhys= memstatus.ullTotalPhys;
/* Give innodb 12.5% of available physical memory. */
InnodbBufferPoolSize= totalPhys/ONE_MB/8;
#ifdef _M_IX86
/*
For 32 bit processes, take virtual address space limitation into account.
Do not try to use more than 3/4 of virtual address space, even if there
is plenty of physical memory.
*/
InnodbBufferPoolSize= min(GetMaxBufferSize(totalPhys)/ONE_MB*3/4,
InnodbBufferPoolSize);
#endif
swprintf_s(buff, L"%llu",InnodbBufferPoolSize);
MsiSetPropertyW(hInstall, L"BUFFERPOOLSIZE", buff);
}
InnodbLogFileSize = min(50, InnodbBufferPoolSize);
swprintf_s(buff, L"%llu",InnodbLogFileSize);
MsiSetPropertyW(hInstall, L"LOGFILESIZE", buff);
LExit:
return WcaFinalize(er);
}
/* Remove service and data directory created by CreateDatabase operation */ /* Remove service and data directory created by CreateDatabase operation */
extern "C" UINT __stdcall CreateDatabaseRollback(MSIHANDLE hInstall) extern "C" UINT __stdcall CreateDatabaseRollback(MSIHANDLE hInstall)
{ {
......
LIBRARY "wixca" LIBRARY "wixca"
VERSION 1.0 VERSION 1.0
EXPORTS EXPORTS
PresetDatabaseProperties
RemoveDataDirectory RemoveDataDirectory
CreateDatabaseRollback CreateDatabaseRollback
CheckDatabaseProperties CheckDatabaseProperties
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Fragment> <Fragment>
<Property Id="PortTemplate" Value="#####" /> <!--
Check, if upgrade wizard was built
It currently requires MFC, which is not in SDK
neither in express edítions of VS.
-->
<?ifndef HaveUpgradeWizard ?>
<?define HaveUpgradeWizard="1"?>
<?endif?>
<!-- If Innodb is compiled in, enable "optimize for transactions" checkbox -->
<?ifndef HaveInnodb ?>
<?define HaveInnodb="0"?>
<?endif?>
<Property Id="PortTemplate" Value="#####" />
<?if $(var.HaveInnodb) = "1" ?>
<Property Id="BufferPoolSizeTemplate" Value="#######" />
<?endif?>
<!-- <!--
Installation parameters that can be passed via msiexec command line Installation parameters that can be passed via msiexec command line
For "booleans" (like skip networking), just providing any value means property set to "yes". For "booleans" (like skip networking), just providing any value means property set to "yes".
...@@ -30,14 +46,13 @@ ...@@ -30,14 +46,13 @@
<Property Id="CLEANUPDATA" Secure="yes" Value="1"/> <Property Id="CLEANUPDATA" Secure="yes" Value="1"/>
<!-- Force per machine installation --> <!-- Force per machine installation -->
<Property Id="ALLUSERS" Secure="yes" Value="1"/> <Property Id="ALLUSERS" Secure="yes" Value="1"/>
<!-- <?if $(var.HaveInnodb) = "1" ?>
Check, if upgrade wizard was built <!-- Quick configuration : set default storage engine to innodb, use strict sql_mode -->
It currently requires MFC, which is not in SDK <Property Id="STDCONFIG" Secure="yes" Value="1"/>
neither in express edítions of VS.
-->
<?ifndef HaveUpgradeWizard ?>
<?define HaveUpgradeWizard="1"?>
<?endif?> <?endif?>
<!-- Innodb Buffer pool size in MB-->
<Property Id="BUFFERPOOLSIZE" Secure="yes"/>
<!-- <!--
User interface dialogs User interface dialogs
...@@ -142,6 +157,8 @@ ...@@ -142,6 +157,8 @@
<!-- Error popup dialog --> <!-- Error popup dialog -->
<Dialog Id="WarningDlg" Width="320" Height="85" Title="[ProductName] Setup" NoMinimize="yes"> <Dialog Id="WarningDlg" Width="320" Height="85" Title="[ProductName] Setup" NoMinimize="yes">
<Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24"
ToolTip="Information icon" FixedSize="yes" IconSize="32" Text="WixUI_Ico_Info" />
<Control Id="Ok" Type="PushButton" X="132" Y="57" Width="56" Height="17" <Control Id="Ok" Type="PushButton" X="132" Y="57" Width="56" Height="17"
Default="yes" Cancel="yes" Text="OK"> Default="yes" Cancel="yes" Text="OK">
<Publish Property="WarningText">1</Publish> <Publish Property="WarningText">1</Publish>
...@@ -261,6 +278,31 @@ ...@@ -261,6 +278,31 @@
<Condition Action="enable" >EnableNetworking</Condition> <Condition Action="enable" >EnableNetworking</Condition>
<Condition Action="disable">Not EnableNetworking</Condition> <Condition Action="disable">Not EnableNetworking</Condition>
</Control> </Control>
<?if $(var.HaveInnodb) = "1" ?>
<Control Id="CheckBoxStandardConfig" Type="CheckBox" Height="18" Width="220" X="9" Y="171" Property="STDCONFIG" CheckBoxValue="1">
<Text>{\Font1}Optimize for transactions</Text>
</Control>
<Control Id="StandardConfigExplain" Type="Text" X="25" Y="190" Width="270" Height="14" TabSkip="yes">
<Text>(Uses transactional storage engine and "strict" SQL mode)</Text>
<Condition Action="enable" >STDCONFIG</Condition>
<Condition Action="disable">Not STDCONFIG</Condition>
</Control>
<Control Id="LabelInnodbBufferpool" Type="Text" Height="17" Width="77" X="25" Y="210" Text="Buffer pool size:" >
<Condition Action="enable" >STDCONFIG</Condition>
<Condition Action="disable">Not STDCONFIG</Condition>
</Control>
<Control Id="BPSize" Type="MaskedEdit" X="104" Y="208" Width="40" Height="15" Property="BUFFERPOOLSIZE" Sunken="yes" Text="[BufferPoolSizeTemplate]">
<Condition Action="enable" >STDCONFIG</Condition>
<Condition Action="disable">Not STDCONFIG</Condition>
</Control>
<Control Id="LabelMB" Type="Text" Height="17" Width="15" X="150" Y="210" Text="MB" >
<Condition Action="enable" >STDCONFIG</Condition>
<Condition Action="disable">Not STDCONFIG</Condition>
</Control>
<?endif?>
<!-- Navigation buttons--> <!-- Navigation buttons-->
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&amp;Back"> <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&amp;Back">
<Publish Event="NewDialog" Value="UserSettingsDlg">1</Publish> <Publish Event="NewDialog" Value="UserSettingsDlg">1</Publish>
...@@ -379,7 +421,42 @@ ...@@ -379,7 +421,42 @@
<ServiceControl Id='DBInstanceServiceStop' Name='[SERVICENAME]' Stop='both' Remove='uninstall' Wait='yes'/> <ServiceControl Id='DBInstanceServiceStop' Name='[SERVICENAME]' Stop='both' Remove='uninstall' Wait='yes'/>
<ServiceControl Id='DBInstanceServiceStart' Name='[SERVICENAME]' Start='install' Wait='yes'/> <ServiceControl Id='DBInstanceServiceStart' Name='[SERVICENAME]' Start='install' Wait='yes'/>
</Component> </Component>
<?if $(var.HaveInnodb) = "1" ?>
<Component Id="C.myiniconfig" Guid="*" Directory="DATADIR">
<Condition>STDCONFIG</Condition>
<RegistryValue Root='HKLM'
Key='SOFTWARE\@MANUFACTURER@\@CPACK_WIX_PACKAGE_NAME@'
Name='STDCONFIG' Value='1' Type='string' KeyPath='yes'/>
<IniFile Id="Ini1"
Action="createLine"
Directory="DATADIR"
Section="mysqld"
Name="my.ini"
Key="sql_mode"
Value="&quot;STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION&quot;" />
<IniFile Id="Ini2"
Action="createLine"
Directory="DATADIR"
Section="mysqld"
Name="my.ini"
Key="default_storage_engine"
Value="innodb" />
<IniFile Id="Ini3"
Action="createLine"
Directory="DATADIR"
Section="mysqld"
Name="my.ini"
Key="innodb_buffer_pool_size"
Value="[BUFFERPOOLSIZE]M" />
<IniFile Id="Ini4"
Action="createLine"
Directory="DATADIR"
Section="mysqld"
Name="my.ini"
Key="innodb_log_file_size"
Value="[LOGFILESIZE]M" />
</Component>
<?endif?>
<!--- Grant service account permission to the database folder (Windows 7 and later) --> <!--- Grant service account permission to the database folder (Windows 7 and later) -->
<Component Id="C.serviceaccount.permission" Guid="*" Directory='DATADIR' Transitive='yes'> <Component Id="C.serviceaccount.permission" Guid="*" Directory='DATADIR' Transitive='yes'>
<Condition><![CDATA[SERVICENAME AND (VersionNT > 600)]]></Condition> <Condition><![CDATA[SERVICENAME AND (VersionNT > 600)]]></Condition>
...@@ -484,7 +561,8 @@ ...@@ -484,7 +561,8 @@
Name="Upgrade Wizard (@CPACK_WIX_PACKAGE_NAME@)" Name="Upgrade Wizard (@CPACK_WIX_PACKAGE_NAME@)"
Target="[INSTALLDIR]bin\mysql_upgrade_wizard.exe" Target="[INSTALLDIR]bin\mysql_upgrade_wizard.exe"
Directory="ShortcutFolder" Directory="ShortcutFolder"
Description="Upgrades older instances of MariaDB/MySQL services to version @MAJOR_VERSION@.@MINOR_VERSION@" /> Description="Upgrades older instances of MariaDB/MySQL services to version @MAJOR_VERSION@.@MINOR_VERSION@"
Advertise="no"/>
</Component> </Component>
<?endif?> <?endif?>
</Feature> </Feature>
...@@ -494,6 +572,7 @@ ...@@ -494,6 +572,7 @@
<SetProperty Sequence='execute' Before='CreateDatabaseCommand' Id="ALLOWREMOTEROOTACCESS" Value="--allow-remote-root-access">ALLOWREMOTEROOTACCESS</SetProperty> <SetProperty Sequence='execute' Before='CreateDatabaseCommand' Id="ALLOWREMOTEROOTACCESS" Value="--allow-remote-root-access">ALLOWREMOTEROOTACCESS</SetProperty>
<SetProperty Sequence='execute' Before='CreateDatabaseCommand' Id="DEFAULTUSER" Value="--default-user">DEFAULTUSER</SetProperty> <SetProperty Sequence='execute' Before='CreateDatabaseCommand' Id="DEFAULTUSER" Value="--default-user">DEFAULTUSER</SetProperty>
<CustomAction Id='CheckDatabaseProperties' BinaryKey='wixca.dll' DllEntry='CheckDatabaseProperties' /> <CustomAction Id='CheckDatabaseProperties' BinaryKey='wixca.dll' DllEntry='CheckDatabaseProperties' />
<CustomAction Id='PresetDatabaseProperties' BinaryKey='wixca.dll' DllEntry='PresetDatabaseProperties' />
<CustomAction Id="CreateDatabaseCommand" Property="CreateDatabase" <CustomAction Id="CreateDatabaseCommand" Property="CreateDatabase"
Value= Value=
"&quot;[#F.bin.mysql_install_db.exe]&quot; &quot;--service=[SERVICENAME]&quot; --port=[PORT] &quot;--password=[PASSWORD]&quot; &quot;--datadir=[DATADIR]\&quot; [SKIPNETWORKING] [ALLOWREMOTEROOTACCESS] [DEFAULTUSER]" "&quot;[#F.bin.mysql_install_db.exe]&quot; &quot;--service=[SERVICENAME]&quot; --port=[PORT] &quot;--password=[PASSWORD]&quot; &quot;--datadir=[DATADIR]\&quot; [SKIPNETWORKING] [ALLOWREMOTEROOTACCESS] [DEFAULTUSER]"
...@@ -576,9 +655,11 @@ ...@@ -576,9 +655,11 @@
BinaryKey="wixca.dll" DllEntry="CheckDBInUse" Execute="firstSequence"/> BinaryKey="wixca.dll" DllEntry="CheckDBInUse" Execute="firstSequence"/>
<InstallExecuteSequence> <InstallExecuteSequence>
<Custom Action="CheckDBInUse" Before="LaunchConditions">Installed</Custom> <Custom Action="CheckDBInUse" Before="LaunchConditions">Installed</Custom>
<Custom Action="PresetDatabaseProperties" After="CheckDBInUse"></Custom>
</InstallExecuteSequence> </InstallExecuteSequence>
<InstallUISequence> <InstallUISequence>
<Custom Action="CheckDBInUse" Before="LaunchConditions">Installed</Custom> <Custom Action="CheckDBInUse" Before="LaunchConditions">Installed</Custom>
<Custom Action="PresetDatabaseProperties" After="CheckDBInUse"></Custom>
</InstallUISequence> </InstallUISequence>
<!-- Store some properties persistently in registry, mainly for upgrades --> <!-- Store some properties persistently in registry, mainly for upgrades -->
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment