mirror of
https://github.com/apple/foundationdb.git
synced 2025-05-14 09:58:50 +08:00
Store global config data on heap
This commit is contained in:
parent
1c60653c2a
commit
7ba7257cd2
@ -55,16 +55,16 @@ Key GlobalConfig::prefixedKey(KeyRef key) {
|
||||
return key.withPrefix(SpecialKeySpace::getModuleRange(SpecialKeySpace::MODULE::GLOBALCONFIG).begin);
|
||||
}
|
||||
|
||||
const ConfigValue GlobalConfig::get(KeyRef name) {
|
||||
const Reference<ConfigValue> GlobalConfig::get(KeyRef name) {
|
||||
auto it = data.find(name);
|
||||
if (it == data.end()) {
|
||||
return ConfigValue{ Arena(), std::any{} };
|
||||
return Reference<ConfigValue>();
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const std::map<KeyRef, ConfigValue> GlobalConfig::get(KeyRangeRef range) {
|
||||
std::map<KeyRef, ConfigValue> results;
|
||||
const std::map<KeyRef, Reference<ConfigValue>> GlobalConfig::get(KeyRangeRef range) {
|
||||
std::map<KeyRef, Reference<ConfigValue>> results;
|
||||
for (const auto& [key, value] : data) {
|
||||
if (range.contains(key)) {
|
||||
results[key] = value;
|
||||
@ -78,21 +78,25 @@ Future<Void> GlobalConfig::onInitialized() {
|
||||
}
|
||||
|
||||
void GlobalConfig::insert(KeyRef key, ValueRef value) {
|
||||
data.erase(key);
|
||||
|
||||
Arena arena(key.expectedSize() + value.expectedSize());
|
||||
KeyRef stableKey = KeyRef(arena, key);
|
||||
try {
|
||||
std::any any;
|
||||
Tuple t = Tuple::unpack(value);
|
||||
if (t.getType(0) == Tuple::ElementType::UTF8) {
|
||||
data[stableKey] = ConfigValue{ arena, StringRef(arena, t.getString(0).contents()) };
|
||||
any = StringRef(arena, t.getString(0).contents());
|
||||
} else if (t.getType(0) == Tuple::ElementType::INT) {
|
||||
data[stableKey] = ConfigValue{ arena, t.getInt(0) };
|
||||
any = t.getInt(0);
|
||||
} else if (t.getType(0) == Tuple::ElementType::FLOAT) {
|
||||
data[stableKey] = ConfigValue{ arena, t.getFloat(0) };
|
||||
any = t.getFloat(0);
|
||||
} else if (t.getType(0) == Tuple::ElementType::DOUBLE) {
|
||||
data[stableKey] = ConfigValue{ arena, t.getDouble(0) };
|
||||
any = t.getDouble(0);
|
||||
} else {
|
||||
ASSERT(false);
|
||||
}
|
||||
data[stableKey] = makeReference<ConfigValue>(std::move(arena), std::move(any));
|
||||
} catch (Error& e) {
|
||||
TraceEvent("GlobalConfigTupleError").detail("What", e.what());
|
||||
}
|
||||
@ -135,12 +139,12 @@ ACTOR Future<Void> GlobalConfig::updater(GlobalConfig* self, Reference<AsyncVar<
|
||||
try {
|
||||
wait(dbInfo->onChange());
|
||||
|
||||
if (dbInfo->get().id.second() != 123456789) {
|
||||
auto& history = dbInfo->get().history;
|
||||
if (history.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& history = dbInfo->get().history;
|
||||
if (history.size() == 0 || (self->lastUpdate < history[0].version && self->lastUpdate != 0)) {
|
||||
if (self->lastUpdate < history[0].version) {
|
||||
// This process missed too many global configuration
|
||||
// history updates or the protocol version changed, so it
|
||||
// must re-read the entire configuration range.
|
||||
|
@ -48,9 +48,12 @@ extern const KeyRef fdbClientInfoTxnSizeLimit;
|
||||
extern const KeyRef transactionTagSampleRate;
|
||||
extern const KeyRef transactionTagSampleCost;
|
||||
|
||||
struct ConfigValue {
|
||||
struct ConfigValue : ReferenceCounted<ConfigValue> {
|
||||
Arena arena;
|
||||
std::any value;
|
||||
|
||||
ConfigValue() {}
|
||||
ConfigValue(Arena&& a, std::any&& v) : arena(a), value(v) {}
|
||||
};
|
||||
|
||||
class GlobalConfig {
|
||||
@ -67,13 +70,12 @@ public:
|
||||
// For example, given "config/a", returns "\xff\xff/global_config/config/a".
|
||||
static Key prefixedKey(KeyRef key);
|
||||
|
||||
// Get a value from the framework. Values are returned in a ConfigValue
|
||||
// struct which also contains a reference to the arena containing the
|
||||
// memory for the object. As long as the caller keeps a reference to the
|
||||
// returned ConfigValue, the value is guaranteed to be readable (if it
|
||||
// exists).
|
||||
const ConfigValue get(KeyRef name);
|
||||
const std::map<KeyRef, ConfigValue> get(KeyRangeRef range);
|
||||
// Get a value from the framework. Values are returned as a ConfigValue
|
||||
// reference which also contains the arena holding the object. As long as
|
||||
// the caller keeps the ConfigValue reference, the value is guaranteed to
|
||||
// be readable. An empty reference is returned if the value does not exist.
|
||||
const Reference<ConfigValue> get(KeyRef name);
|
||||
const std::map<KeyRef, Reference<ConfigValue>> get(KeyRangeRef range);
|
||||
|
||||
// For arithmetic value types, returns a copy of the value for the given
|
||||
// key, or the supplied default value if the framework does not know about
|
||||
@ -81,9 +83,11 @@ public:
|
||||
template <typename T, typename std::enable_if<std::is_arithmetic<T>{}, bool>::type = true>
|
||||
const T get(KeyRef name, T defaultVal) {
|
||||
try {
|
||||
auto any = get(name).value;
|
||||
if (any.has_value()) {
|
||||
return std::any_cast<T>(any);
|
||||
auto configValue = get(name);
|
||||
if (configValue.isValid()) {
|
||||
if (configValue->value.has_value()) {
|
||||
return std::any_cast<T>(configValue->value);
|
||||
}
|
||||
}
|
||||
|
||||
return defaultVal;
|
||||
@ -114,7 +118,7 @@ private:
|
||||
Database cx;
|
||||
Future<Void> _updater;
|
||||
Promise<Void> initialized;
|
||||
std::unordered_map<StringRef, ConfigValue> data;
|
||||
std::unordered_map<StringRef, Reference<ConfigValue>> data;
|
||||
Version lastUpdate;
|
||||
};
|
||||
|
||||
|
@ -28,6 +28,9 @@
|
||||
struct VersionHistory {
|
||||
constexpr static FileIdentifier file_identifier = 5863456;
|
||||
|
||||
VersionHistory() {}
|
||||
VersionHistory(Version v) : version(v) {}
|
||||
|
||||
Version version;
|
||||
Standalone<VectorRef<MutationRef>> mutations;
|
||||
|
||||
|
@ -1380,22 +1380,22 @@ Future<Standalone<RangeResultRef>> GlobalConfigImpl::getRange(ReadYourWritesTran
|
||||
auto& globalConfig = GlobalConfig::globalConfig();
|
||||
KeyRangeRef modified =
|
||||
KeyRangeRef(kr.begin.removePrefix(getKeyRange().begin), kr.end.removePrefix(getKeyRange().begin));
|
||||
std::map<KeyRef, ConfigValue> values = globalConfig.get(modified);
|
||||
std::map<KeyRef, Reference<ConfigValue>> values = globalConfig.get(modified);
|
||||
for (const auto& [key, config] : values) {
|
||||
Key prefixedKey = key.withPrefix(getKeyRange().begin);
|
||||
if (config.value.has_value()) {
|
||||
if (config.value.type() == typeid(StringRef)) {
|
||||
if (config.isValid() && config->value.has_value()) {
|
||||
if (config->value.type() == typeid(StringRef)) {
|
||||
result.push_back_deep(result.arena(),
|
||||
KeyValueRef(prefixedKey, std::any_cast<StringRef>(config.value).toString()));
|
||||
} else if (config.value.type() == typeid(int64_t)) {
|
||||
KeyValueRef(prefixedKey, std::any_cast<StringRef>(config->value).toString()));
|
||||
} else if (config->value.type() == typeid(int64_t)) {
|
||||
result.push_back_deep(result.arena(),
|
||||
KeyValueRef(prefixedKey, std::to_string(std::any_cast<int64_t>(config.value))));
|
||||
} else if (config.value.type() == typeid(float)) {
|
||||
KeyValueRef(prefixedKey, std::to_string(std::any_cast<int64_t>(config->value))));
|
||||
} else if (config->value.type() == typeid(float)) {
|
||||
result.push_back_deep(result.arena(),
|
||||
KeyValueRef(prefixedKey, std::to_string(std::any_cast<float>(config.value))));
|
||||
} else if (config.value.type() == typeid(double)) {
|
||||
KeyValueRef(prefixedKey, std::to_string(std::any_cast<float>(config->value))));
|
||||
} else if (config->value.type() == typeid(double)) {
|
||||
result.push_back_deep(result.arena(),
|
||||
KeyValueRef(prefixedKey, std::to_string(std::any_cast<double>(config.value))));
|
||||
KeyValueRef(prefixedKey, std::to_string(std::any_cast<double>(config->value))));
|
||||
} else {
|
||||
ASSERT(false);
|
||||
}
|
||||
|
@ -3212,17 +3212,21 @@ ACTOR Future<Void> monitorGlobalConfig(ClusterControllerData::DBInfo* db) {
|
||||
clientInfo.history.clear();
|
||||
|
||||
for (const auto& kv : globalConfigHistory) {
|
||||
VersionHistory vh;
|
||||
ObjectReader reader(kv.value.begin(), IncludeVersion());
|
||||
if (reader.protocolVersion() != g_network->protocolVersion()) {
|
||||
// If the protocol version has changed, the
|
||||
// GlobalConfig actor should refresh its view by
|
||||
// reading the entire global configuration key
|
||||
// range. An empty mutation list will signal the
|
||||
// actor to refresh.
|
||||
// range. Setting the version to the max int64_t
|
||||
// will always cause the global configuration
|
||||
// updater to refresh its view of the configuration
|
||||
// keyspace.
|
||||
clientInfo.history.clear();
|
||||
clientInfo.history.emplace_back(std::numeric_limits<Version>::max());
|
||||
break;
|
||||
}
|
||||
|
||||
VersionHistory vh;
|
||||
reader.deserialize(vh);
|
||||
|
||||
// Read commit version out of versionstamp at end of key.
|
||||
@ -3236,7 +3240,7 @@ ACTOR Future<Void> monitorGlobalConfig(ClusterControllerData::DBInfo* db) {
|
||||
clientInfo.history.push_back(std::move(vh));
|
||||
}
|
||||
|
||||
clientInfo.id = UID(deterministicRandom()->randomUniqueID().first(), 123456789);
|
||||
clientInfo.id = deterministicRandom()->randomUniqueID();
|
||||
db->clientInfo->set(clientInfo);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user