From 7e61b9f6985934cd84108549be6e2746475bb8ca Mon Sep 17 00:00:00 2001 From: hvlad Date: Tue, 13 Oct 2020 15:20:13 +0300 Subject: [PATCH] Reworked Config: correct work with 64-bit integer in 32-bit code, refactor config values checks and defaults, remove some type casts. Introduce new virtual table RDB$CONFIG. Implement CORE-6332 : Get rid of FileSystemCacheThreshold parameter new boolean setting UseFileSystemCache overrides legacy FileSystemCacheThreshold, FileSystemCacheThreshold will be removed in the next major Firebird release. --- builds/win32/msvc15/engine.vcxproj | 2 + builds/win32/msvc15/engine.vcxproj.filters | 6 + src/common/config/config.cpp | 612 +++++++++++++-------- src/common/config/config.h | 102 +++- src/jrd/FBConfigTable.cpp | 120 ++++ src/jrd/FBConfigTable.h | 79 +++ src/jrd/fields.h | 6 + src/jrd/names.h | 7 + src/jrd/opt.cpp | 5 + src/jrd/pag.cpp | 11 +- src/jrd/relations.h | 9 + 11 files changed, 707 insertions(+), 252 deletions(-) create mode 100644 src/jrd/FBConfigTable.cpp create mode 100644 src/jrd/FBConfigTable.h diff --git a/builds/win32/msvc15/engine.vcxproj b/builds/win32/msvc15/engine.vcxproj index 29d9b49ad4..dbfb4684a1 100644 --- a/builds/win32/msvc15/engine.vcxproj +++ b/builds/win32/msvc15/engine.vcxproj @@ -79,6 +79,7 @@ + @@ -248,6 +249,7 @@ + diff --git a/builds/win32/msvc15/engine.vcxproj.filters b/builds/win32/msvc15/engine.vcxproj.filters index d9826af494..296c8ec97e 100644 --- a/builds/win32/msvc15/engine.vcxproj.filters +++ b/builds/win32/msvc15/engine.vcxproj.filters @@ -498,6 +498,9 @@ JRD files + + JRD files + @@ -1037,6 +1040,9 @@ Header files + + Header files + diff --git a/src/common/config/config.cpp b/src/common/config/config.cpp index 7afc76dc0d..5690483518 100644 --- a/src/common/config/config.cpp +++ b/src/common/config/config.cpp @@ -142,97 +142,98 @@ const char* GCPolicyBackground = "background"; const char* GCPolicyCombined = "combined"; -const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] = +Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] = { - {TYPE_INTEGER, "TempBlockSize", (ConfigValue) 1048576}, // bytes - {TYPE_INTEGER, "TempCacheLimit", (ConfigValue) -1}, // bytes - {TYPE_BOOLEAN, "RemoteFileOpenAbility", (ConfigValue) false}, - {TYPE_INTEGER, "GuardianOption", (ConfigValue) 1}, - {TYPE_INTEGER, "CpuAffinityMask", (ConfigValue) 0}, - {TYPE_INTEGER, "TcpRemoteBufferSize", (ConfigValue) 8192}, // bytes - {TYPE_BOOLEAN, "TcpNoNagle", (ConfigValue) true}, - {TYPE_BOOLEAN, "TcpLoopbackFastPath", (ConfigValue) true}, - {TYPE_INTEGER, "DefaultDbCachePages", (ConfigValue) -1}, // pages - {TYPE_INTEGER, "ConnectionTimeout", (ConfigValue) 180}, // seconds - {TYPE_INTEGER, "DummyPacketInterval", (ConfigValue) 0}, // seconds - {TYPE_STRING, "DefaultTimeZone", (ConfigValue) ""}, - {TYPE_INTEGER, "LockMemSize", (ConfigValue) 1048576}, // bytes - {TYPE_INTEGER, "LockHashSlots", (ConfigValue) 8191}, // slots - {TYPE_INTEGER, "LockAcquireSpins", (ConfigValue) 0}, - {TYPE_INTEGER, "EventMemSize", (ConfigValue) 65536}, // bytes - {TYPE_INTEGER, "DeadlockTimeout", (ConfigValue) 10}, // seconds - {TYPE_STRING, "RemoteServiceName", (ConfigValue) FB_SERVICE_NAME}, - {TYPE_INTEGER, "RemoteServicePort", (ConfigValue) 0}, - {TYPE_STRING, "RemotePipeName", (ConfigValue) FB_PIPE_NAME}, - {TYPE_STRING, "IpcName", (ConfigValue) FB_IPC_NAME}, + {TYPE_INTEGER, "TempBlockSize", 1048576}, // bytes + {TYPE_INTEGER, "TempCacheLimit", -1}, // bytes + {TYPE_BOOLEAN, "RemoteFileOpenAbility", false}, + {TYPE_INTEGER, "GuardianOption", 1}, + {TYPE_INTEGER, "CpuAffinityMask", 0}, + {TYPE_INTEGER, "TcpRemoteBufferSize", 8192}, // bytes + {TYPE_BOOLEAN, "TcpNoNagle", true}, + {TYPE_BOOLEAN, "TcpLoopbackFastPath", true}, + {TYPE_INTEGER, "DefaultDbCachePages", -1}, // pages + {TYPE_INTEGER, "ConnectionTimeout", 180}, // seconds + {TYPE_INTEGER, "DummyPacketInterval", 0}, // seconds + {TYPE_STRING, "DefaultTimeZone", NULL}, + {TYPE_INTEGER, "LockMemSize", 1048576}, // bytes + {TYPE_INTEGER, "LockHashSlots", 8191}, // slots + {TYPE_INTEGER, "LockAcquireSpins", 0}, + {TYPE_INTEGER, "EventMemSize", 65536}, // bytes + {TYPE_INTEGER, "DeadlockTimeout", 10}, // seconds + {TYPE_STRING, "RemoteServiceName", FB_SERVICE_NAME}, + {TYPE_INTEGER, "RemoteServicePort", 0}, + {TYPE_STRING, "RemotePipeName", FB_PIPE_NAME}, + {TYPE_STRING, "IpcName", FB_IPC_NAME}, #ifdef WIN_NT - {TYPE_INTEGER, "MaxUnflushedWrites", (ConfigValue) 100}, - {TYPE_INTEGER, "MaxUnflushedWriteTime", (ConfigValue) 5}, + {TYPE_INTEGER, "MaxUnflushedWrites", 100}, + {TYPE_INTEGER, "MaxUnflushedWriteTime", 5}, #else - {TYPE_INTEGER, "MaxUnflushedWrites", (ConfigValue) -1}, - {TYPE_INTEGER, "MaxUnflushedWriteTime", (ConfigValue) -1}, + {TYPE_INTEGER, "MaxUnflushedWrites", -1}, + {TYPE_INTEGER, "MaxUnflushedWriteTime", -1}, #endif - {TYPE_INTEGER, "ProcessPriorityLevel", (ConfigValue) 0}, - {TYPE_INTEGER, "RemoteAuxPort", (ConfigValue) 0}, - {TYPE_STRING, "RemoteBindAddress", (ConfigValue) 0}, - {TYPE_STRING, "ExternalFileAccess", (ConfigValue) "None"}, // location(s) of external files for tables - {TYPE_STRING, "DatabaseAccess", (ConfigValue) "Full"}, // location(s) of databases - {TYPE_STRING, "UdfAccess", (ConfigValue) "None"}, // location(s) of UDFs - {TYPE_STRING, "TempDirectories", (ConfigValue) 0}, + {TYPE_INTEGER, "ProcessPriorityLevel", 0}, + {TYPE_INTEGER, "RemoteAuxPort", 0}, + {TYPE_STRING, "RemoteBindAddress", 0}, + {TYPE_STRING, "ExternalFileAccess", "None"}, // location(s) of external files for tables + {TYPE_STRING, "DatabaseAccess", "Full"}, // location(s) of databases + {TYPE_STRING, "UdfAccess", "None"}, // location(s) of UDFs + {TYPE_STRING, "TempDirectories", 0}, #ifdef DEV_BUILD - {TYPE_BOOLEAN, "BugcheckAbort", (ConfigValue) true}, // whether to abort() engine when internal error is found + {TYPE_BOOLEAN, "BugcheckAbort", true}, // whether to abort() engine when internal error is found #else - {TYPE_BOOLEAN, "BugcheckAbort", (ConfigValue) false}, // whether to abort() engine when internal error is found + {TYPE_BOOLEAN, "BugcheckAbort", false}, // whether to abort() engine when internal error is found #endif - {TYPE_INTEGER, "TraceDSQL", (ConfigValue) 0}, // bitmask - {TYPE_BOOLEAN, "LegacyHash", (ConfigValue) true}, // let use old passwd hash verification - {TYPE_STRING, "GCPolicy", (ConfigValue) NULL}, // garbage collection policy - {TYPE_BOOLEAN, "Redirection", (ConfigValue) false}, - {TYPE_INTEGER, "DatabaseGrowthIncrement", (ConfigValue) 128 * 1048576}, // bytes - {TYPE_INTEGER, "FileSystemCacheThreshold", (ConfigValue) 65536}, // page buffers - {TYPE_BOOLEAN, "RelaxedAliasChecking", (ConfigValue) false}, // if true relax strict alias checking rules in DSQL a bit - {TYPE_STRING, "AuditTraceConfigFile", (ConfigValue) ""}, // location of audit trace configuration file - {TYPE_INTEGER, "MaxUserTraceLogSize", (ConfigValue) 10}, // maximum size of user session trace log - {TYPE_INTEGER, "FileSystemCacheSize", (ConfigValue) 0}, // percent - {TYPE_STRING, "Providers", (ConfigValue) "Remote, " CURRENT_ENGINE ", Loopback"}, - {TYPE_STRING, "AuthServer", (ConfigValue) "Srp256"}, + {TYPE_INTEGER, "TraceDSQL", 0}, // bitmask + {TYPE_BOOLEAN, "LegacyHash", true}, // let use old passwd hash verification + {TYPE_STRING, "GCPolicy", NULL}, // garbage collection policy + {TYPE_BOOLEAN, "Redirection", false}, + {TYPE_INTEGER, "DatabaseGrowthIncrement", 128 * 1048576}, // bytes + {TYPE_INTEGER, "FileSystemCacheThreshold", 65536}, // page buffers + {TYPE_BOOLEAN, "RelaxedAliasChecking", false}, // if true relax strict alias checking rules in DSQL a bit + {TYPE_STRING, "AuditTraceConfigFile", ""}, // location of audit trace configuration file + {TYPE_INTEGER, "MaxUserTraceLogSize", 10}, // maximum size of user session trace log + {TYPE_INTEGER, "FileSystemCacheSize", 0}, // percent + {TYPE_STRING, "Providers", "Remote, " CURRENT_ENGINE ", Loopback"}, + {TYPE_STRING, "AuthServer", "Srp256"}, #ifdef WIN_NT - {TYPE_STRING, "AuthClient", (ConfigValue) "Srp256, Srp, Win_Sspi, Legacy_Auth"}, + {TYPE_STRING, "AuthClient", "Srp256, Srp, Win_Sspi, Legacy_Auth"}, #else - {TYPE_STRING, "AuthClient", (ConfigValue) "Srp256, Srp, Legacy_Auth"}, + {TYPE_STRING, "AuthClient", "Srp256, Srp, Legacy_Auth"}, #endif - {TYPE_STRING, "UserManager", (ConfigValue) "Srp"}, - {TYPE_STRING, "TracePlugin", (ConfigValue) "fbtrace"}, - {TYPE_STRING, "SecurityDatabase", (ConfigValue) NULL}, // sec/db alias - rely on ConfigManager::getDefaultSecurityDb() - {TYPE_STRING, "ServerMode", (ConfigValue) ""}, // actual value differs in boot/regular cases - {TYPE_STRING, "WireCrypt", (ConfigValue) NULL}, - {TYPE_STRING, "WireCryptPlugin", (ConfigValue) "ChaCha, Arc4"}, - {TYPE_STRING, "KeyHolderPlugin", (ConfigValue) ""}, - {TYPE_BOOLEAN, "RemoteAccess", (ConfigValue) true}, - {TYPE_BOOLEAN, "IPv6V6Only", (ConfigValue) false}, - {TYPE_BOOLEAN, "WireCompression", (ConfigValue) false}, - {TYPE_INTEGER, "MaxIdentifierByteLength", (ConfigValue) -1}, - {TYPE_INTEGER, "MaxIdentifierCharLength", (ConfigValue) -1}, - {TYPE_BOOLEAN, "AllowEncryptedSecurityDatabase", (ConfigValue) false}, - {TYPE_INTEGER, "StatementTimeout", (ConfigValue) 0}, - {TYPE_INTEGER, "ConnectionIdleTimeout", (ConfigValue) 0}, - {TYPE_INTEGER, "ClientBatchBuffer", (ConfigValue) (128 * 1024)}, + {TYPE_STRING, "UserManager", "Srp"}, + {TYPE_STRING, "TracePlugin", "fbtrace"}, + {TYPE_STRING, "SecurityDatabase", NULL}, // sec/db alias - rely on ConfigManager::getDefaultSecurityDb() + {TYPE_STRING, "ServerMode", NULL}, // actual value differs in boot/regular cases and set at setupDefaultConfig() + {TYPE_STRING, "WireCrypt", NULL}, + {TYPE_STRING, "WireCryptPlugin", "ChaCha, Arc4"}, + {TYPE_STRING, "KeyHolderPlugin", ""}, + {TYPE_BOOLEAN, "RemoteAccess", true}, + {TYPE_BOOLEAN, "IPv6V6Only", false}, + {TYPE_BOOLEAN, "WireCompression", false}, + {TYPE_INTEGER, "MaxIdentifierByteLength", -1}, + {TYPE_INTEGER, "MaxIdentifierCharLength", -1}, + {TYPE_BOOLEAN, "AllowEncryptedSecurityDatabase", false}, + {TYPE_INTEGER, "StatementTimeout", 0}, + {TYPE_INTEGER, "ConnectionIdleTimeout", 0}, + {TYPE_INTEGER, "ClientBatchBuffer", (128 * 1024)}, #ifdef DEV_BUILD - {TYPE_STRING, "OutputRedirectionFile", (ConfigValue) "-"}, + {TYPE_STRING, "OutputRedirectionFile", "-"}, #else #ifdef WIN_NT - {TYPE_STRING, "OutputRedirectionFile", (ConfigValue) "nul"}, + {TYPE_STRING, "OutputRedirectionFile", "nul"}, #else - {TYPE_STRING, "OutputRedirectionFile", (ConfigValue) "/dev/null"}, + {TYPE_STRING, "OutputRedirectionFile", "/dev/null"}, #endif #endif - {TYPE_INTEGER, "ExtConnPoolSize", (ConfigValue) 0}, - {TYPE_INTEGER, "ExtConnPoolLifeTime", (ConfigValue) 7200}, - {TYPE_INTEGER, "SnapshotsMemSize", (ConfigValue) 65536}, // bytes - {TYPE_INTEGER, "TipCacheBlockSize", (ConfigValue) 4194304}, // bytes - {TYPE_BOOLEAN, "ReadConsistency", (ConfigValue) true}, - {TYPE_BOOLEAN, "ClearGTTAtRetaining", (ConfigValue) false}, - {TYPE_STRING, "DataTypeCompatibility", (ConfigValue) NULL} + {TYPE_INTEGER, "ExtConnPoolSize", 0}, + {TYPE_INTEGER, "ExtConnPoolLifeTime", 7200}, + {TYPE_INTEGER, "SnapshotsMemSize", 65536}, // bytes + {TYPE_INTEGER, "TipCacheBlockSize", 4194304}, // bytes + {TYPE_BOOLEAN, "ReadConsistency", true}, + {TYPE_BOOLEAN, "ClearGTTAtRetaining", false}, + {TYPE_STRING, "DataTypeCompatibility", NULL}, + {TYPE_BOOLEAN, "UseFileSystemCache", true} }; /****************************************************************************** @@ -241,8 +242,13 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] = */ Config::Config(const ConfigFile& file) - : notifyDatabase(*getDefaultMemoryPool()) + : notifyDatabase(*getDefaultMemoryPool()), + serverMode(-1) { + memset(bits, 0, sizeof(bits)); + + setupDefaultConfig(); + // Array to save string temporarily // Will be finally saved by loadValues() in the end of ctor ObjectsArray tempStrings(getPool()); @@ -251,10 +257,10 @@ Config::Config(const ConfigFile& file) for (unsigned int i = 0; i < MAX_CONFIG_KEY; i++) { values[i] = entries[i].default_value; - if (entries[i].data_type == TYPE_STRING && values[i]) + if (entries[i].data_type == TYPE_STRING && values[i].strVal) { - ConfigFile::String expand((const char*)values[i]); - if (file.macroParse(expand, NULL) && expand != (const char*) values[i]) + ConfigFile::String expand(values[i].strVal); + if (file.macroParse(expand, NULL) && expand != values[i].strVal) { ConfigFile::String& saved(tempStrings.add()); saved = expand; @@ -267,26 +273,36 @@ Config::Config(const ConfigFile& file) } Config::Config(const ConfigFile& file, const Config& base) - : notifyDatabase(*getDefaultMemoryPool()) + : notifyDatabase(*getDefaultMemoryPool()), + serverMode(-1) { + memset(bits, 0, sizeof(bits)); + // Iterate through the known configuration entries for (unsigned int i = 0; i < MAX_CONFIG_KEY; i++) { values[i] = base.values[i]; + if (base.testKey(i)) + setKey(i); } loadValues(file); } Config::Config(const ConfigFile& file, const Config& base, const PathName& notify) - : notifyDatabase(*getDefaultMemoryPool()) + : notifyDatabase(*getDefaultMemoryPool()), + serverMode(-1) { + memset(bits, 0, sizeof(bits)); + // Iterate through the known configuration entries for (unsigned int i = 0; i < MAX_CONFIG_KEY; i++) { values[i] = base.values[i]; + if (base.testKey(i)) + setKey(i); } loadValues(file); @@ -338,18 +354,146 @@ void Config::loadValues(const ConfigFile& file) //case TYPE_STRING_VECTOR: // break; } + + setKey(i); } if (entry.data_type == TYPE_STRING && values[i] != entry.default_value) { - const char* src = (const char*) values[i]; + const char* src = values[i].strVal; char* dst = FB_NEW_POOL(getPool()) char[strlen(src) + 1]; strcpy(dst, src); values[i] = (ConfigValue) dst; } } + + checkValues(); } +static const char* txtServerModes[6] = +{ + "Super", "ThreadedDedicated", + "SuperClassic", "ThreadedShared", + "Classic", "MultiProcess" +}; + +void Config::setupDefaultConfig() +{ + const bool bootBuild = fb_utils::bootBuild(); + + ConfigValue* pDefault = &entries[KEY_SERVER_MODE].default_value; + serverMode = bootBuild ? MODE_CLASSIC : MODE_SUPER; + pDefault->strVal = txtServerModes[2 * serverMode]; + + pDefault = &entries[KEY_TEMP_CACHE_LIMIT].default_value; + if (pDefault->intVal < 0) + pDefault->intVal = (serverMode != MODE_SUPER) ? 8388608 : 67108864; // bytes + + entries[KEY_REMOTE_FILE_OPEN_ABILITY].default_value.boolVal = bootBuild; + + pDefault = &entries[KEY_DEFAULT_DB_CACHE_PAGES].default_value; + if (pDefault->intVal < 0) + pDefault->intVal = (serverMode != MODE_SUPER) ? 256 : 2048; // pages + + pDefault = &entries[KEY_GC_POLICY].default_value; + if (!pDefault->strVal) + { + pDefault->strVal = (serverMode == MODE_SUPER) ? GCPolicyCombined : GCPolicyCooperative; + } + + + //pDefault = &entries[KEY_SECURITY_DATABASE].default_value; + + //pDefault = &entries[KEY_WIRE_CRYPT].default_value; +// if (!*pDefault) +// *pDefault == (ConfigValue) (xxx == WC_CLIENT) ? WIRE_CRYPT_ENABLED : WIRE_CRYPT_REQUIRED; + +} + +void Config::checkIntForLoBound(ConfigKey key, SINT64 loBound, bool setDefault) +{ + fb_assert(entries[key].data_type == TYPE_INTEGER); + if (values[key].intVal < loBound) + values[key].intVal = setDefault ? entries[key].default_value.intVal : loBound; +} + +void Config::checkIntForHiBound(ConfigKey key, SINT64 hiBound, bool setDefault) +{ + fb_assert(entries[key].data_type == TYPE_INTEGER); + if (values[key].intVal > hiBound) + values[key].intVal = setDefault ? entries[key].default_value.intVal : hiBound; +} + +void Config::checkValues() +{ + checkIntForLoBound(KEY_TEMP_CACHE_LIMIT, 0, true); + + checkIntForLoBound(KEY_TCP_REMOTE_BUFFER_SIZE, 1448, false); + checkIntForHiBound(KEY_TCP_REMOTE_BUFFER_SIZE, MAX_SSHORT, false); + + checkIntForLoBound(KEY_DEFAULT_DB_CACHE_PAGES, 0, true); + + checkIntForLoBound(KEY_LOCK_MEM_SIZE, 64 * 1024, false); + + const char* strVal = values[KEY_GC_POLICY].strVal; + if (strVal) + { + NoCaseString gcPolicy(strVal); + if (gcPolicy != GCPolicyCooperative && + gcPolicy != GCPolicyBackground && + gcPolicy != GCPolicyCombined) + { + // user-provided value is invalid - fail to default + values[KEY_GC_POLICY] = entries[KEY_GC_POLICY].default_value; + } + } + + strVal = values[KEY_WIRE_CRYPT].strVal; + if (strVal) + { + NoCaseString wireCrypt(strVal); + if (wireCrypt != "DISABLED" && wireCrypt != "ENABLED" && wireCrypt != "REQUIRED") + { + // user-provided value is invalid - fail to default + values[KEY_WIRE_CRYPT] = entries[KEY_WIRE_CRYPT].default_value; + } + } + + strVal = values[KEY_SERVER_MODE].strVal; + if (strVal && !fb_utils::bootBuild()) + { + bool found = false; + NoCaseString mode(strVal); + for (int x = 0; x < 6; ++x) + { + if (mode == txtServerModes[x]) + { + serverMode = x / 2; + found = true; + break; + } + } + + if (!found) + values[KEY_SERVER_MODE] = entries[KEY_SERVER_MODE].default_value; + } + + checkIntForLoBound(KEY_FILESYSTEM_CACHE_THRESHOLD, 0, true); + + checkIntForLoBound(KEY_MAX_IDENTIFIER_BYTE_LENGTH, 1, true); + checkIntForHiBound(KEY_MAX_IDENTIFIER_BYTE_LENGTH, MAX_SQL_IDENTIFIER_LEN, true); + + checkIntForLoBound(KEY_MAX_IDENTIFIER_CHAR_LENGTH, 1, true); + checkIntForHiBound(KEY_MAX_IDENTIFIER_CHAR_LENGTH, METADATA_IDENTIFIER_CHAR_LEN, true); + + checkIntForLoBound(KEY_SNAPSHOTS_MEM_SIZE, 1, true); + checkIntForHiBound(KEY_SNAPSHOTS_MEM_SIZE, MAX_ULONG, true); + + checkIntForLoBound(KEY_TIP_CACHE_BLOCK_SIZE, 1, true); + checkIntForHiBound(KEY_TIP_CACHE_BLOCK_SIZE, MAX_ULONG, true); +} + + Config::~Config() { // Free allocated memory @@ -362,7 +506,7 @@ Config::~Config() switch (entries[i].data_type) { case TYPE_STRING: - delete[] (char*) values[i]; + delete[] values[i].strVal; break; //case TYPE_STRING_VECTOR: // break; @@ -435,7 +579,7 @@ SINT64 Config::getInt(unsigned int key) const { if (key >= MAX_CONFIG_KEY) return 0; - return get(static_cast(key)); + return getInt(static_cast(key)); } const char* Config::getString(unsigned int key) const @@ -450,330 +594,315 @@ const char* Config::getString(unsigned int key) const return getSecurityDatabase(); } - return get(static_cast(key)); + return getStr(static_cast(key)); } bool Config::getBoolean(unsigned int key) const { if (key >= MAX_CONFIG_KEY) return false; - return get(static_cast(key)); + return getBool(static_cast(key)); +} + +bool Config::valueAsString(ConfigValue val, ConfigType type, string& str) +{ + switch (type) + { + case Config::TYPE_INTEGER: + str.printf("%" SQUADFORMAT, val.intVal); + break; + + case Config::TYPE_STRING: + { + if (val == 0) + return false; + + str = val.strVal; + } + break; + + case Config::TYPE_BOOLEAN: + str = val.boolVal ? "true" : "false"; + break; + } + + return true; +} + +bool Config::getValue(unsigned int key, string& str) const +{ + if (key >= MAX_CONFIG_KEY) + return false; + + return valueAsString(values[key], entries[key].data_type, str); +} + +bool Config::getDefaultValue(unsigned int key, string& str) +{ + if (key >= MAX_CONFIG_KEY) + return false; + + return valueAsString(entries[key].default_value, entries[key].data_type, str); } int Config::getTempBlockSize() { - return (int) getDefaultConfig()->values[KEY_TEMP_BLOCK_SIZE]; + return (int) getDefaultConfig()->values[KEY_TEMP_BLOCK_SIZE].intVal; } FB_UINT64 Config::getTempCacheLimit() const { - SINT64 v = get(KEY_TEMP_CACHE_LIMIT); - if (v < 0) - { - v = getServerMode() != MODE_SUPER ? 8388608 : 67108864; // bytes - } - return v; + return getInt(KEY_TEMP_CACHE_LIMIT); } bool Config::getRemoteFileOpenAbility() { - return fb_utils::bootBuild() ? true : ((bool) getDefaultConfig()->values[KEY_REMOTE_FILE_OPEN_ABILITY]); + return getDefaultConfig()->getBool(KEY_REMOTE_FILE_OPEN_ABILITY); } int Config::getGuardianOption() { - return (int) getDefaultConfig()->values[KEY_GUARDIAN_OPTION]; + return getDefaultConfig()->getInt(KEY_GUARDIAN_OPTION); } -int Config::getCpuAffinityMask() +FB_UINT64 Config::getCpuAffinityMask() { - return (int) getDefaultConfig()->values[KEY_CPU_AFFINITY_MASK]; + return getDefaultConfig()->getInt(KEY_CPU_AFFINITY_MASK); } int Config::getTcpRemoteBufferSize() { - int rc = (int) getDefaultConfig()->values[KEY_TCP_REMOTE_BUFFER_SIZE]; - if (rc < 1448) - rc = 1448; - if (rc > MAX_SSHORT) - rc = MAX_SSHORT; - return rc; + return getDefaultConfig()->getInt(KEY_TCP_REMOTE_BUFFER_SIZE); } bool Config::getTcpNoNagle() const { - return get(KEY_TCP_NO_NAGLE); + return getBool(KEY_TCP_NO_NAGLE); } bool Config::getTcpLoopbackFastPath() const { - return get(KEY_TCP_LOOPBACK_FAST_PATH); + return getBool(KEY_TCP_LOOPBACK_FAST_PATH); } bool Config::getIPv6V6Only() const { - return get(KEY_IPV6_V6ONLY); + return getBool(KEY_IPV6_V6ONLY); } int Config::getDefaultDbCachePages() const { - int rc = get(KEY_DEFAULT_DB_CACHE_PAGES); - if (rc < 0) - { - rc = getServerMode() != MODE_SUPER ? 256 : 2048; // pages - } - return rc; + return getInt(KEY_DEFAULT_DB_CACHE_PAGES); } int Config::getConnectionTimeout() const { - return get(KEY_CONNECTION_TIMEOUT); + return getInt(KEY_CONNECTION_TIMEOUT); } int Config::getDummyPacketInterval() const { - return get(KEY_DUMMY_PACKET_INTERVAL); + return getInt(KEY_DUMMY_PACKET_INTERVAL); } const char* Config::getDefaultTimeZone() { - return getDefaultConfig()->get(KEY_DEFAULT_TIME_ZONE); + return getDefaultConfig()->getStr(KEY_DEFAULT_TIME_ZONE); } int Config::getLockMemSize() const { - int size = get(KEY_LOCK_MEM_SIZE); - if (size < 64 * 1024) - size = 64 * 1024; - return size; + return getInt(KEY_LOCK_MEM_SIZE); } int Config::getLockHashSlots() const { - return get(KEY_LOCK_HASH_SLOTS); + return getInt(KEY_LOCK_HASH_SLOTS); } int Config::getLockAcquireSpins() const { - return get(KEY_LOCK_ACQUIRE_SPINS); + return getInt(KEY_LOCK_ACQUIRE_SPINS); } int Config::getEventMemSize() const { - return get(KEY_EVENT_MEM_SIZE); + return getInt(KEY_EVENT_MEM_SIZE); } int Config::getDeadlockTimeout() const { - return get(KEY_DEADLOCK_TIMEOUT); + return getInt(KEY_DEADLOCK_TIMEOUT); } const char *Config::getRemoteServiceName() const { - return get(KEY_REMOTE_SERVICE_NAME); + return getStr(KEY_REMOTE_SERVICE_NAME); } unsigned short Config::getRemoteServicePort() const { - return get(KEY_REMOTE_SERVICE_PORT); + return getInt(KEY_REMOTE_SERVICE_PORT); } const char *Config::getRemotePipeName() const { - return get(KEY_REMOTE_PIPE_NAME); + return getStr(KEY_REMOTE_PIPE_NAME); } const char *Config::getIpcName() const { - return get(KEY_IPC_NAME); + return getStr(KEY_IPC_NAME); } int Config::getMaxUnflushedWrites() const { - return get(KEY_MAX_UNFLUSHED_WRITES); + return getInt(KEY_MAX_UNFLUSHED_WRITES); } int Config::getMaxUnflushedWriteTime() const { - return get(KEY_MAX_UNFLUSHED_WRITE_TIME); + return getInt(KEY_MAX_UNFLUSHED_WRITE_TIME); } int Config::getProcessPriorityLevel() { - return (int) getDefaultConfig()->values[KEY_PROCESS_PRIORITY_LEVEL]; + return getDefaultConfig()->getInt(KEY_PROCESS_PRIORITY_LEVEL); } int Config::getRemoteAuxPort() const { - return get(KEY_REMOTE_AUX_PORT); + return getInt(KEY_REMOTE_AUX_PORT); } const char *Config::getRemoteBindAddress() { - return (const char*) getDefaultConfig()->values[KEY_REMOTE_BIND_ADDRESS]; + return getDefaultConfig()->getStr(KEY_REMOTE_BIND_ADDRESS); } const char *Config::getExternalFileAccess() const { - return get(KEY_EXTERNAL_FILE_ACCESS); + return getStr(KEY_EXTERNAL_FILE_ACCESS); } const char *Config::getDatabaseAccess() { - return (const char*) getDefaultConfig()->values[KEY_DATABASE_ACCESS]; + return getDefaultConfig()->getStr(KEY_DATABASE_ACCESS); } const char *Config::getUdfAccess() { - return (const char*) getDefaultConfig()->values[KEY_UDF_ACCESS]; + return getDefaultConfig()->getStr(KEY_UDF_ACCESS); } const char *Config::getTempDirectories() { - return (const char*) getDefaultConfig()->values[KEY_TEMP_DIRECTORIES]; + return getDefaultConfig()->getStr(KEY_TEMP_DIRECTORIES); } bool Config::getBugcheckAbort() { - return (bool) getDefaultConfig()->values[KEY_BUGCHECK_ABORT]; + return getDefaultConfig()->getBool(KEY_BUGCHECK_ABORT); } int Config::getTraceDSQL() { - return (int) getDefaultConfig()->values[KEY_TRACE_DSQL]; + return getDefaultConfig()->getInt(KEY_TRACE_DSQL); } bool Config::getLegacyHash() { - return (bool) getDefaultConfig()->values[KEY_LEGACY_HASH]; + return getDefaultConfig()->getBool(KEY_LEGACY_HASH); } const char *Config::getGCPolicy() const { - const char* rc = get(KEY_GC_POLICY); - - if (rc) - { - if (strcmp(rc, GCPolicyCooperative) != 0 && - strcmp(rc, GCPolicyBackground) != 0 && - strcmp(rc, GCPolicyCombined) != 0) - { - // user-provided value is invalid - fail to default - rc = NULL; - } - } - - if (! rc) - { - rc = getServerMode() == MODE_SUPER ? GCPolicyCombined : GCPolicyCooperative; - } - - return rc; + return getStr(KEY_GC_POLICY); } bool Config::getRedirection() { - return (bool) getDefaultConfig()->values[KEY_REDIRECTION]; + return getDefaultConfig()->getBool(KEY_REDIRECTION); } int Config::getDatabaseGrowthIncrement() const { - return get(KEY_DATABASE_GROWTH_INCREMENT); + return getInt(KEY_DATABASE_GROWTH_INCREMENT); } int Config::getFileSystemCacheThreshold() const { - int rc = get(KEY_FILESYSTEM_CACHE_THRESHOLD); - return rc < 0 ? 0 : rc; + return getInt(KEY_FILESYSTEM_CACHE_THRESHOLD); } bool Config::getRelaxedAliasChecking() { - return (bool) getDefaultConfig()->values[KEY_RELAXED_ALIAS_CHECKING]; + return getDefaultConfig()->getBool(KEY_RELAXED_ALIAS_CHECKING); } FB_UINT64 Config::getFileSystemCacheSize() { - return (FB_UINT64)(SINT64) getDefaultConfig()->values[KEY_FILESYSTEM_CACHE_SIZE]; + return (FB_UINT64) getDefaultConfig()->getInt(KEY_FILESYSTEM_CACHE_SIZE); } const char *Config::getAuditTraceConfigFile() { - return (const char*) getDefaultConfig()->values[KEY_TRACE_CONFIG]; + return getDefaultConfig()->getStr(KEY_TRACE_CONFIG); } FB_UINT64 Config::getMaxUserTraceLogSize() { - return (FB_UINT64)(SINT64) getDefaultConfig()->values[KEY_MAX_TRACELOG_SIZE]; + return (FB_UINT64) getDefaultConfig()->getInt(KEY_MAX_TRACELOG_SIZE); } int Config::getServerMode() { - static int rc = -1; - if (rc >= 0) - return rc; - - const char* textMode = (const char*) (getDefaultConfig()->values[KEY_SERVER_MODE]); - const char* modes[6] = - {"Super", "ThreadedDedicated", "SuperClassic", "ThreadedShared", "Classic", "MultiProcess"}; - - for (int x = 0; x < 6; ++x) - { - if (fb_utils::stricmp(textMode, modes[x]) == 0) - { - rc = x / 2; - return rc; - } - } - - // use default - rc = fb_utils::bootBuild() ? MODE_CLASSIC : MODE_SUPER; - return rc; + return getDefaultConfig()->serverMode; } ULONG Config::getSnapshotsMemSize() const { - SINT64 rc = get(KEY_SNAPSHOTS_MEM_SIZE); - if (rc <= 0 || rc > MAX_ULONG) - { - rc = 65536; - } - return rc; + return getInt(KEY_SNAPSHOTS_MEM_SIZE); } ULONG Config::getTipCacheBlockSize() const { - SINT64 rc = get(KEY_TIP_CACHE_BLOCK_SIZE); - if (rc <= 0 || rc > MAX_ULONG) - { - rc = 4194304; - } - return rc; + return getInt(KEY_TIP_CACHE_BLOCK_SIZE); } const char* Config::getPlugins(unsigned int type) const { + ConfigKey key; switch (type) { case IPluginManager::TYPE_PROVIDER: - return (const char*) values[KEY_PLUG_PROVIDERS]; + key = KEY_PLUG_PROVIDERS; + break; case IPluginManager::TYPE_AUTH_SERVER: - return (const char*) values[KEY_PLUG_AUTH_SERVER]; + key = KEY_PLUG_AUTH_SERVER; + break; case IPluginManager::TYPE_AUTH_CLIENT: - return (const char*) values[KEY_PLUG_AUTH_CLIENT]; + key = KEY_PLUG_AUTH_CLIENT; + break; case IPluginManager::TYPE_AUTH_USER_MANAGEMENT: - return (const char*) values[KEY_PLUG_AUTH_MANAGE]; + key = KEY_PLUG_AUTH_MANAGE; + break; case IPluginManager::TYPE_TRACE: - return (const char*) values[KEY_PLUG_TRACE]; + key = KEY_PLUG_TRACE; + break; case IPluginManager::TYPE_WIRE_CRYPT: - return (const char*) values[KEY_PLUG_WIRE_CRYPT]; + key = KEY_PLUG_WIRE_CRYPT; + break; case IPluginManager::TYPE_KEY_HOLDER: - return (const char*) values[KEY_PLUG_KEY_HOLDER]; + key = KEY_PLUG_KEY_HOLDER; + break; + + default: + (Arg::Gds(isc_random) << "Internal error in Config::getPlugins(): unknown plugin type requested").raise(); } - (Arg::Gds(isc_random) << "Internal error in Config::getPlugins(): unknown plugin type requested").raise(); - return NULL; // compiler warning silencer + return getStr(key); } @@ -844,7 +973,7 @@ int FirebirdConf::release() const char* Config::getSecurityDatabase() const { - const char* strVal = get(KEY_SECURITY_DATABASE); + const char* strVal = getStr(KEY_SECURITY_DATABASE); if (!strVal) { strVal = MasterInterfacePtr()->getConfigManager()->getDefaultSecurityDb(); @@ -857,101 +986,96 @@ const char* Config::getSecurityDatabase() const int Config::getWireCrypt(WireCryptMode wcMode) const { - const char* wc = get(KEY_WIRE_CRYPT); - if (!wc) + bool present; + const char* wc = getStr(KEY_WIRE_CRYPT, &present); + if (present && wc) { - return wcMode == WC_CLIENT ? WIRE_CRYPT_ENABLED : WIRE_CRYPT_REQUIRED; + NoCaseString wireCrypt(wc); + if (wireCrypt == "DISABLED") + return WIRE_CRYPT_DISABLED; + if (wireCrypt == "ENABLED") + return WIRE_CRYPT_ENABLED; + + // the safest choice + return WIRE_CRYPT_REQUIRED; } - NoCaseString wireCrypt(wc); - if (wireCrypt == "DISABLED") - return WIRE_CRYPT_DISABLED; - if (wireCrypt == "ENABLED") - return WIRE_CRYPT_ENABLED; - - // the safest choice - return WIRE_CRYPT_REQUIRED; + return wcMode == WC_CLIENT ? WIRE_CRYPT_ENABLED : WIRE_CRYPT_REQUIRED; } bool Config::getRemoteAccess() const { - return get(KEY_REMOTE_ACCESS); + return getBool(KEY_REMOTE_ACCESS); } bool Config::getWireCompression() const { - return get(KEY_WIRE_COMPRESSION); + return getBool(KEY_WIRE_COMPRESSION); } int Config::getMaxIdentifierByteLength() const { - int rc = get(KEY_MAX_IDENTIFIER_BYTE_LENGTH); - - if (rc < 0) - rc = MAX_SQL_IDENTIFIER_LEN; - - return MIN(MAX(rc, 1), MAX_SQL_IDENTIFIER_LEN); + return getInt(KEY_MAX_IDENTIFIER_BYTE_LENGTH); } int Config::getMaxIdentifierCharLength() const { - int rc = get(KEY_MAX_IDENTIFIER_CHAR_LENGTH); - - if (rc < 0) - rc = METADATA_IDENTIFIER_CHAR_LEN; - - return MIN(MAX(rc, 1), METADATA_IDENTIFIER_CHAR_LEN); + return getInt(KEY_MAX_IDENTIFIER_CHAR_LENGTH); } bool Config::getCryptSecurityDatabase() const { - return get(KEY_ENCRYPT_SECURITY_DATABASE); + return getBool(KEY_ENCRYPT_SECURITY_DATABASE); } unsigned int Config::getStatementTimeout() const { - return get(KEY_STMT_TIMEOUT); + return getInt(KEY_STMT_TIMEOUT); } unsigned int Config::getConnIdleTimeout() const { - return get(KEY_CONN_IDLE_TIMEOUT); + return getInt(KEY_CONN_IDLE_TIMEOUT); } unsigned int Config::getClientBatchBuffer() const { - return get(KEY_CLIENT_BATCH_BUFFER); + return getInt(KEY_CLIENT_BATCH_BUFFER); } const char* Config::getOutputRedirectionFile() { - const char* file = (const char*) (getDefaultConfig()->values[KEY_OUTPUT_REDIRECTION_FILE]); - return file; + return getDefaultConfig()->getStr(KEY_OUTPUT_REDIRECTION_FILE); } int Config::getExtConnPoolSize() { - return getDefaultConfig()->get(KEY_EXT_CONN_POOL_SIZE); + return getDefaultConfig()->getInt(KEY_EXT_CONN_POOL_SIZE); } int Config::getExtConnPoolLifeTime() { - return getDefaultConfig()->get(KEY_EXT_CONN_POOL_LIFETIME); + return getDefaultConfig()->getInt(KEY_EXT_CONN_POOL_LIFETIME); } bool Config::getReadConsistency() const { - return get(KEY_READ_CONSISTENCY); + return getBool(KEY_READ_CONSISTENCY); } bool Config::getClearGTTAtRetaining() const { - return get(KEY_CLEAR_GTT_RETAINING); + return getBool(KEY_CLEAR_GTT_RETAINING); } const char* Config::getDataTypeCompatibility() const { - return get(KEY_DATA_TYPE_COMPATIBILITY); + return getStr(KEY_DATA_TYPE_COMPATIBILITY); +} + +bool Config::getUseFileSystemCache(bool* pPresent) const +{ + return getBool(KEY_USE_FILESYSTEM_CACHE, pPresent); } } // namespace Firebird diff --git a/src/common/config/config.h b/src/common/config/config.h index 4d99bf20f3..ff72eff389 100644 --- a/src/common/config/config.h +++ b/src/common/config/config.h @@ -87,7 +87,33 @@ const char* const CONFIG_FILE = "firebird.conf"; class Config : public RefCounted, public GlobalStorage { public: - typedef IPTR ConfigValue; + //typedef IPTR ConfigValue; + struct ConfigValue + { + ConfigValue() : intVal(0) {}; + ConfigValue(const char* val) : strVal(val) {}; + ConfigValue(bool val) : boolVal(val) {}; + ConfigValue(SINT64 val) : intVal(val) {}; + ConfigValue(int val) : intVal(val) {}; + + union + { + const char* strVal; + bool boolVal; + SINT64 intVal; + }; + + // simple bitwise comparison + bool operator== (const ConfigValue& other) const + { + return this->intVal == other.intVal; + } + + bool operator!= (const ConfigValue& other) const + { + return !(*this == other); + } + }; enum ConfigKey { @@ -159,6 +185,7 @@ public: KEY_READ_CONSISTENCY, KEY_CLEAR_GTT_RETAINING, KEY_DATA_TYPE_COMPATIBILITY, + KEY_USE_FILESYSTEM_CACHE, MAX_CONFIG_KEY // keep it last }; @@ -182,21 +209,67 @@ private: }; void loadValues(const ConfigFile& file); + void setupDefaultConfig(); + void checkValues(); - template T get(Config::ConfigKey key) const + // helper check-value functions + void checkIntForLoBound(ConfigKey key, SINT64 loBound, bool setDefault); + void checkIntForHiBound(ConfigKey key, SINT64 hiBound, bool setDefault); + + const char* getStr(ConfigKey key, bool* pPresent = nullptr) const { - return (T) values[key]; + if (pPresent) + *pPresent = testKey(key); + + return values[key].strVal; } - static const ConfigEntry entries[MAX_CONFIG_KEY]; + bool getBool(ConfigKey key, bool* pPresent = nullptr) const + { + if (pPresent) + *pPresent = testKey(key); + + return values[key].boolVal; + } + + SINT64 getInt(ConfigKey key, bool* pPresent = nullptr) const + { + if (pPresent) + *pPresent = testKey(key); + + return values[key].intVal; + } + + static bool valueAsString(ConfigValue val, ConfigType type, string& str); + + static ConfigEntry entries[MAX_CONFIG_KEY]; ConfigValue values[MAX_CONFIG_KEY]; + + // One bit per key: bit is set if corresponding key value was set in config + ULONG bits[MAX_CONFIG_KEY / BITS_PER_LONG + 1]; + + // test if given key value was set in config + bool testKey(unsigned int key) const + { + return bits[key / BITS_PER_LONG] & (1ul << key % BITS_PER_LONG); + } + + // set bit of given key that was set in config + void setKey(unsigned int key) + { + bits[key / BITS_PER_LONG] |= (1ul << key % BITS_PER_LONG); + } + mutable PathName notifyDatabase; + // set in default config only + int serverMode; + public: explicit Config(const ConfigFile& file); // use to build default config Config(const ConfigFile& file, const Config& base); // use to build db-specific config - Config(const ConfigFile& file, const Config& base, const PathName& notify); // use to build db-specific config with notifucation + Config(const ConfigFile& file, const Config& base, const PathName& notify); // use to build db-specific config with notification ~Config(); // Call it when database with given config is created @@ -228,6 +301,21 @@ public: const char* getString(unsigned int key) const; bool getBoolean(unsigned int key) const; + // Number of known keys + static unsigned int getKeyCount() { return MAX_CONFIG_KEY; }; + static const char* getKeyName(unsigned int key) + { + if (key >= MAX_CONFIG_KEY) + return nullptr; + + return entries[key].key; + } + // false if value is null or key is not exists + bool getValue(unsigned int key, string& str) const; + static bool getDefaultValue(unsigned int key, string& str); + // return true if value is set at some level + bool getIsSet(unsigned int key) const { return testKey(key); } + // Static functions apply to instance-wide values, // non-static may be specified per database. @@ -250,7 +338,7 @@ public: static int getGuardianOption(); // CPU affinity mask - static int getCpuAffinityMask(); + static FB_UINT64 getCpuAffinityMask(); // XDR buffer size static int getTcpRemoteBufferSize(); @@ -396,6 +484,8 @@ public: bool getClearGTTAtRetaining() const; const char* getDataTypeCompatibility() const; + + bool getUseFileSystemCache(bool* pPresent = nullptr) const; }; // Implementation of interface to access master configuration file diff --git a/src/jrd/FBConfigTable.cpp b/src/jrd/FBConfigTable.cpp new file mode 100644 index 0000000000..eceb66d91e --- /dev/null +++ b/src/jrd/FBConfigTable.cpp @@ -0,0 +1,120 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Vladyslav Khorsun + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2020 Vladyslav Khorsun + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#include "../jrd/FBConfigTable.h" +#include "../jrd/ini.h" +#include "../jrd/ids.h" + +using namespace Jrd; +using namespace Firebird; + + +/// class FBConfigTable + +FBConfigTable::FBConfigTable(MemoryPool& pool, const Config* conf) : + SnapshotData(pool), + m_conf(conf) +{ +} + +RecordBuffer* FBConfigTable::getRecords(thread_db* tdbb, jrd_rel* relation) +{ + fb_assert(relation); + fb_assert(relation->rel_id == rel_cfg_table); + + RecordBuffer* recordBuffer = getData(relation); + if (recordBuffer) + return recordBuffer; + + recordBuffer = allocBuffer(tdbb, *tdbb->getDefaultPool(), relation->rel_id); + + // Check privileges to see RDB$CONFIG + const Attachment* att = tdbb->getAttachment(); + if (!att->att_user->locksmith(tdbb, SELECT_ANY_OBJECT_IN_DATABASE)) + return recordBuffer; + + for (unsigned int key = 0; key < Config::getKeyCount(); key++) + { + Record* rec = recordBuffer->getTempRecord(); + rec->nullify(); + + putField(tdbb, rec, DumpField(f_cfg_id, VALUE_INTEGER, sizeof(key), &key)); + + const char* name = Config::getKeyName(key); + putField(tdbb, rec, DumpField(f_cfg_name, VALUE_STRING, strlen(name), name)); + + string str; + if (m_conf->getValue(key, str)) + putField(tdbb, rec, DumpField(f_cfg_value, VALUE_STRING, str.length(), str.c_str())); + + if (m_conf->getDefaultValue(key, str)) + putField(tdbb, rec, DumpField(f_cfg_default, VALUE_STRING, str.length(), str.c_str())); + + char set = m_conf->getIsSet(key) ? 1 : 0; + putField(tdbb, rec, DumpField(f_cfg_is_set, VALUE_BOOLEAN, 1, &set)); + + recordBuffer->store(rec); + } + + return recordBuffer; +} + + +/// class FBConfigTableScan + +void FBConfigTableScan::close(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure(m_impure); + + delete impure->table; + impure->table = nullptr; + + VirtualTableScan::close(tdbb); +} + +const Format* FBConfigTableScan::getFormat(thread_db* tdbb, jrd_rel* relation) const +{ + RecordBuffer* records = getRecords(tdbb, relation); + return records->getFormat(); +} + +bool FBConfigTableScan::retrieveRecord(thread_db* tdbb, jrd_rel* relation, + FB_UINT64 position, Record* record) const +{ + RecordBuffer* records = getRecords(tdbb, relation); + return records->fetch(position, record); +} + +RecordBuffer* FBConfigTableScan::getRecords(thread_db* tdbb, jrd_rel* relation) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure(m_impure); + + if (!impure->table) + { + MemoryPool* pool = tdbb->getDefaultPool(); + impure->table = FB_NEW_POOL(*pool) FBConfigTable(*pool, tdbb->getDatabase()->dbb_config); + } + + return impure->table->getRecords(tdbb, relation); +} diff --git a/src/jrd/FBConfigTable.h b/src/jrd/FBConfigTable.h new file mode 100644 index 0000000000..7d073065c3 --- /dev/null +++ b/src/jrd/FBConfigTable.h @@ -0,0 +1,79 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Vladyslav Khorsun + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2020 Vladyslav Khorsun + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#ifndef JRD_FBCONFIG_TABLE_H +#define JRD_FBCONFIG_TABLE_H + +#include "firebird.h" +#include "../common/classes/fb_string.h" +#include "../jrd/Monitoring.h" +#include "../jrd/recsrc/RecordSource.h" + + +namespace Jrd +{ + +class FBConfigTable : public SnapshotData +{ +public: + FBConfigTable(MemoryPool& pool, const Firebird::Config* conf); + + // return data for RDB$CONFIG + RecordBuffer* getRecords(thread_db* tdbb, jrd_rel* relation); + +private: + const Firebird::Config* m_conf; +}; + + +class FBConfigTableScan : public VirtualTableScan +{ +public: + FBConfigTableScan(CompilerScratch* csb, const Firebird::string& alias, + StreamType stream, jrd_rel* relation) + : VirtualTableScan(csb, alias, stream, relation) + { + m_impure = csb->allocImpure(); + } + + void close(thread_db* tdbb) const override; + +protected: + const Format* getFormat(thread_db* tdbb, jrd_rel* relation) const override; + + bool retrieveRecord(thread_db* tdbb, jrd_rel* relation, FB_UINT64 position, + Record* record) const override; + +private: + struct Impure + { + FBConfigTable* table; + }; + + RecordBuffer* getRecords(thread_db* tdbb, jrd_rel* relation) const; + + ULONG m_impure; +}; + +} // namespace Jrd + +#endif // JRD_FBCONFIG_TABLE_H diff --git a/src/jrd/fields.h b/src/jrd/fields.h index 39dd40d30a..ca7bf96eaa 100644 --- a/src/jrd/fields.h +++ b/src/jrd/fields.h @@ -213,3 +213,9 @@ FIELD(fld_pub_name , nam_pub_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false) FIELD(fld_file_id , nam_file_id , dtype_varying , 255 , dsc_text_type_ascii , NULL , false) + + FIELD(fld_cfg_id , nam_cfg_id , dtype_long , sizeof(SLONG) , 0 , NULL , false) + FIELD(fld_cfg_name , nam_cfg_name , dtype_varying , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false) + FIELD(fld_cfg_value , nam_cfg_value , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) + FIELD(fld_cfg_default , nam_cfg_default , dtype_varying , 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata , NULL , true) + FIELD(fld_cfg_is_set , nam_cfg_is_set , dtype_boolean , 1 , 0 , NULL , false) diff --git a/src/jrd/names.h b/src/jrd/names.h index 7e57158993..1aea7e9f9b 100644 --- a/src/jrd/names.h +++ b/src/jrd/names.h @@ -441,3 +441,10 @@ NAME("MON$FILE_ID", nam_mon_file_id) NAME("MON$GUID", nam_mon_guid) NAME("MON$NEXT_ATTACHMENT", nam_mon_na) NAME("MON$NEXT_STATEMENT", nam_mon_ns) + +NAME("RDB$CONFIG", nam_cfg_table) +NAME("RDB$CONFIG_ID", nam_cfg_id) +NAME("RDB$CONFIG_NAME", nam_cfg_name) +NAME("RDB$CONFIG_VALUE", nam_cfg_value) +NAME("RDB$CONFIG_DEFAULT", nam_cfg_default) +NAME("RDB$CONFIG_IS_SET", nam_cfg_is_set) diff --git a/src/jrd/opt.cpp b/src/jrd/opt.cpp index 202285da26..824fe4d345 100644 --- a/src/jrd/opt.cpp +++ b/src/jrd/opt.cpp @@ -92,6 +92,7 @@ #include "../dsql/BoolNodes.h" #include "../dsql/ExprNodes.h" #include "../dsql/StmtNodes.h" +#include "../jrd/FBConfigTable.h" using namespace Jrd; using namespace Firebird; @@ -2297,6 +2298,10 @@ static RecordSource* gen_retrieval(thread_db* tdbb, rsb = FB_NEW_POOL(*tdbb->getDefaultPool()) TimeZonesTableScan(csb, alias, stream, relation); break; + case rel_cfg_table: + rsb = FB_NEW_POOL(*tdbb->getDefaultPool()) FBConfigTableScan(csb, alias, stream, relation); + break; + default: rsb = FB_NEW_POOL(*tdbb->getDefaultPool()) MonitoringTableScan(csb, alias, stream, relation); break; diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 3a4a6dc307..12d85234cc 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -1164,8 +1164,15 @@ void PAG_header(thread_db* tdbb, bool info) Arg::Str(attachment->att_filename)); } - const bool useFSCache = dbb->dbb_bcb->bcb_count < - ULONG(dbb->dbb_config->getFileSystemCacheThreshold()); + + bool present; + bool useFSCache = dbb->dbb_config->getUseFileSystemCache(&present); + + if (!present) + { + useFSCache = dbb->dbb_bcb->bcb_count < + ULONG(dbb->dbb_config->getFileSystemCacheThreshold()); + } if ((header->hdr_flags & hdr_force_write) || !useFSCache) { diff --git a/src/jrd/relations.h b/src/jrd/relations.h index b348819bc3..c21fe602f4 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -723,3 +723,12 @@ RELATION(nam_pub_tables, rel_pub_tables, ODS_13_0, rel_persistent) FIELD(f_pubtab_pub_name, nam_pub_name, fld_pub_name, 1, ODS_13_0) FIELD(f_pubtab_tab_name, nam_tab_name, fld_r_name, 1, ODS_13_0) END_RELATION + +// Relation 53 (RDB$CONFIG) +RELATION(nam_cfg_table, rel_cfg_table, ODS_13_0, rel_virtual) +FIELD(f_cfg_id, nam_cfg_id, fld_cfg_id, 0, ODS_13_0) +FIELD(f_cfg_name, nam_cfg_name, fld_cfg_name, 0, ODS_13_0) +FIELD(f_cfg_value, nam_cfg_value, fld_cfg_value, 0, ODS_13_0) +FIELD(f_cfg_default, nam_cfg_default, fld_cfg_default, 0, ODS_13_0) +FIELD(f_cfg_is_set, nam_cfg_is_set, fld_cfg_is_set, 0, ODS_13_0) +END_RELATION