Skip to content
This repository was archived by the owner on Jan 7, 2022. It is now read-only.

Commit 91455ca

Browse files
Vijaykumar Padmanabanfacebook-github-bot
authored andcommitted
Ensure LCM receives ServerConfig updates
Summary: Internal logs config is available from two places - ServerConfig and LocalLogsConfig. Configuration.cpp used to look up the ServerConfig where as a number other callsites look up on the LocalLogsConfig. These versions could diverge since LocalLogsConfig is only updated whenever LogsConfigStateMachine publishes a new state. This divergence could lead to number of problems if one subcomponent sees a log and another subcomponent does not. For example, recovery of a new internal log could get stuck, replication property changes to internal logs are not propogated, writes to metadata log of a newly added log failing etc. This diff fixes the problem by ensuring that LCM subscribes to ServerConfig updates and publishes a new LocalLogsConfig with updated internal_logs if a change is detected. Also updates Configuration.cpp to always lookup log properties using LocalLogsConfig irrespective of whether log id is internal or not. Reviewed By: AhmedSoliman Differential Revision: D17752931 fbshipit-source-id: 00428373a2539c51202744b1aba7fdbc7b16fe1b
1 parent cb7f4ec commit 91455ca

9 files changed

Lines changed: 157 additions & 15 deletions

File tree

logdevice/common/Worker.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ void Worker::onServerConfigUpdated() {
329329

330330
sender().noteConfigurationChanged(getNodesConfiguration());
331331

332+
if (logsconfig_manager_) {
333+
logsconfig_manager_->onServerConfigUpdated();
334+
}
335+
332336
clientReadStreams().noteConfigurationChanged();
333337
// propagate the config change to metadata sequencer
334338
runningWriteMetaDataRecords().noteConfigurationChanged();

logdevice/common/configuration/Configuration.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ std::shared_ptr<LogsConfig::LogGroupNode>
4545
Configuration::getLogGroupByIDShared(logid_t id) const {
4646
if (MetaDataLog::isMetaDataLog(id)) {
4747
return server_config_->getMetaDataLogGroup();
48-
} else if (configuration::InternalLogs::isInternal(id)) {
49-
const auto raw_directory =
50-
server_config_->getInternalLogsConfig().getLogGroupByID(id);
51-
return raw_directory != nullptr ? raw_directory->log_group : nullptr;
5248
} else {
5349
return logs_config_->getLogGroupByIDShared(id);
5450
}
@@ -60,8 +56,6 @@ Configuration::getLogGroupInDirectoryByIDRaw(logid_t id) const {
6056
ld_check(logs_config_->isLocal());
6157
if (MetaDataLog::isMetaDataLog(id)) {
6258
return &server_config_->getMetaDataLogGroupInDir();
63-
} else if (configuration::InternalLogs::isInternal(id)) {
64-
return server_config_->getInternalLogsConfig().getLogGroupByID(id);
6559
} else {
6660
return localLogsConfig()->getLogGroupInDirectoryByIDRaw(id);
6761
}
@@ -72,12 +66,6 @@ void Configuration::getLogGroupByIDAsync(
7266
std::function<void(std::shared_ptr<LogsConfig::LogGroupNode>)> cb) const {
7367
if (MetaDataLog::isMetaDataLog(id)) {
7468
cb(server_config_->getMetaDataLogGroup());
75-
return;
76-
} else if (configuration::InternalLogs::isInternal(id)) {
77-
const auto raw_directory =
78-
server_config_->getInternalLogsConfig().getLogGroupByID(id);
79-
cb(raw_directory != nullptr ? raw_directory->log_group : nullptr);
80-
return;
8169
} else {
8270
logs_config_->getLogGroupByIDAsync(id, cb);
8371
}

logdevice/common/configuration/InternalLogs.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,39 @@ folly::dynamic InternalLogs::toDynamic() const {
176176
return logs;
177177
}
178178

179+
bool InternalLogs::operator!=(const InternalLogs& other) const {
180+
return !(*this == other);
181+
}
182+
183+
bool InternalLogs::operator==(const InternalLogs& other) const {
184+
// If sizes don't match, they are not equal
185+
if (size() != other.size()) {
186+
return false;
187+
}
188+
189+
for (const auto& kv : nameLookup()) {
190+
auto log_id = kv.second;
191+
// Check if the log exists in both configs and that their attrs match
192+
auto this_config_attr =
193+
logExists(log_id) ? getLogGroupByID(log_id)->log_group : nullptr;
194+
auto other_config_attr = other.logExists(log_id)
195+
? other.getLogGroupByID(log_id)->log_group
196+
: nullptr;
197+
// Log not configured in both configs.
198+
if (this_config_attr == nullptr && other_config_attr == nullptr) {
199+
continue;
200+
}
201+
// Log is present in one config but not the other
202+
if (this_config_attr == nullptr || other_config_attr == nullptr) {
203+
return false;
204+
}
205+
// Log id present in both configs but the attributes don't match
206+
if (!(*this_config_attr == *other_config_attr)) {
207+
return false;
208+
}
209+
}
210+
211+
return true;
212+
}
213+
179214
}}} // namespace facebook::logdevice::configuration

logdevice/common/configuration/InternalLogs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ class InternalLogs {
130130
*/
131131
folly::dynamic toDynamic() const;
132132

133+
bool operator!=(const InternalLogs& other) const;
134+
bool operator==(const InternalLogs& other) const;
135+
133136
private:
134137
void reset();
135138

logdevice/common/configuration/logs/LogsConfigManager.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,34 @@ void LogsConfigManager::onSettingsUpdated() {
109109
}
110110
}
111111

112+
void LogsConfigManager::onServerConfigUpdated() {
113+
auto server_config = updateable_config_->getServerConfig();
114+
const auto& server_config_internal_log =
115+
server_config->getInternalLogsConfig();
116+
auto logs_config = updateable_config_->getLocalLogsConfig();
117+
const auto& logs_config_internal_log = logs_config->getInternalLogs();
118+
119+
if (server_config_internal_log != logs_config_internal_log) {
120+
// Make a new copy of the existing config
121+
std::shared_ptr<LocalLogsConfig> new_logs_config =
122+
std::make_shared<LocalLogsConfig>(
123+
*updateable_config_->getLocalLogsConfig());
124+
// Setting the InternalLogs from ServerConfig
125+
new_logs_config->setInternalLogsConfig(server_config_internal_log);
126+
// We want the latest namespace delimiter to be set for this config.
127+
new_logs_config->setNamespaceDelimiter(
128+
server_config->getNamespaceDelimiter());
129+
updateable_config_->updateableLogsConfig()->update(new_logs_config);
130+
ld_info("Published new LogsConfig (fully loaded? %s) version (%lu) from "
131+
"LogsConfigManager because ServerConfig was updated to version:%s",
132+
new_logs_config->isFullyLoaded() ? "yes" : "no",
133+
new_logs_config->getVersion(),
134+
toString(server_config->getVersion()).c_str());
135+
// increment the counter of number of published updates
136+
STAT_INCR(getStats(), logsconfig_manager_published_server_config_update);
137+
}
138+
}
139+
112140
void LogsConfigManager::start() {
113141
if (is_running_) {
114142
return;

logdevice/common/configuration/logs/LogsConfigManager.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ class LogsConfigManager {
127127
*/
128128
void onSettingsUpdated();
129129

130+
/**
131+
* Callback that gets called when the ServerConfig is updated. Must be called
132+
* on the same worker on which this manager is running as a new
133+
* LocalLogsConfig may be published
134+
*/
135+
void onServerConfigUpdated();
136+
130137
/**
131138
* Decides on which worker the LogsConfigManager and LogsConfigStateMachine
132139
* should bind to.

logdevice/common/stats/common_stats.inc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
/* can be included multiple times */
99

1010
#ifndef STAT_DEFINE
11-
#error STAT_DEFINE() macro not defined
12-
#define STAT_DEFINE(...)
11+
#error STAT_DEFINE() macro not defined
12+
#define STAT_DEFINE(...)
1313
#endif
1414

1515
// Stats shared between server and client
@@ -48,7 +48,6 @@ STAT_DEFINE(metadata_log_read_failed_corruption, SUM)
4848
STAT_DEFINE(metadata_log_read_dataloss, SUM)
4949
STAT_DEFINE(metadata_log_read_failed_other, SUM)
5050

51-
5251
// Number of CONFIG_CHANGED_Messages received with Action::Reload.
5352
STAT_DEFINE(config_changed_reload, SUM)
5453
// Number of CONFIG_CHANGED_Messages ignored because the config is already
@@ -88,6 +87,9 @@ STAT_DEFINE(nodeset_finder_fallback_to_metadata_log, SUM)
8887
// LogsConfigManager
8988
// Number of updates sent to UpdateableLogsConfig by LogsConfigManager
9089
STAT_DEFINE(logsconfig_manager_published_update, SUM)
90+
// Number of times a new LocalLogsConfig was published because
91+
// server config was updated
92+
STAT_DEFINE(logsconfig_manager_published_server_config_update, SUM)
9193
// LogsConfig manager receiving updates from the state machine
9294
STAT_DEFINE(logsconfig_manager_received_update, SUM)
9395
// The version of the last processed delta/snapshot on this node

logdevice/common/test/RandomNodeSetSelectorTest.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ TEST(WeightAwareNodeSetSelectorTest, InternalLogs) {
770770
ASSERT_NE(nullptr, log_group_node);
771771
log_group_node = il.insert("maintenance_log_deltas", log_attrs);
772772
ASSERT_NE(nullptr, log_group_node);
773+
logs_config->setInternalLogsConfig(il);
773774

774775
ShapingConfig shaping_cfg(
775776
std::set<NodeLocationScope>{NodeLocationScope::NODE},
@@ -1108,6 +1109,7 @@ TEST(WeightAwareNodeSetSelectorTest, InternalLogsConfiguredTooSmall) {
11081109
log_attrs.set_replicateAcross(replication.getDistinctReplicationFactors());
11091110
auto log_group_node = il.insert("event_log_snapshots", log_attrs);
11101111
ASSERT_NE(nullptr, log_group_node);
1112+
logs_config->setInternalLogsConfig(il);
11111113

11121114
ShapingConfig shaping_cfg(
11131115
std::set<NodeLocationScope>{NodeLocationScope::NODE},

logdevice/test/ServerConfigSourceIntegrationTest.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,76 @@ TEST_F(ServerConfigSourceIntegrationTest, StaleServerConfigFetchFromSource) {
212212
EXPECT_LT(
213213
0, cluster->getNode(0).stats()["config_changed_ignored_not_trusted"]);
214214
}
215+
216+
TEST_F(ServerConfigSourceIntegrationTest, ServerConfigInternalLogUpdate) {
217+
auto cluster =
218+
IntegrationTestUtils::ClusterFactory()
219+
.enableLogsConfigManager()
220+
.setInternalLogsReplicationFactor(1)
221+
.eventLogMode(
222+
IntegrationTestUtils::ClusterFactory::EventLogMode::SNAPSHOTTED)
223+
.create(1);
224+
225+
// The default version for the cluster is 1
226+
std::shared_ptr<Configuration> cluster_config = cluster->getConfig()->get();
227+
EXPECT_EQ(config_version_t(1), cluster_config->serverConfig()->getVersion());
228+
229+
// Bump version of server config
230+
auto new_server_config =
231+
cluster_config->serverConfig()->withVersion(config_version_t(2));
232+
cluster->writeConfig(
233+
new_server_config.get(), cluster_config->logsConfig().get());
234+
235+
// Wait until the node picks up the updated config
236+
wait_until([&]() -> bool {
237+
std::string reply = cluster->getNode(0).sendCommand("info config");
238+
auto updated_config = Configuration::fromJson(reply, nullptr, nullptr);
239+
ld_check(updated_config);
240+
241+
return new_server_config->getVersion() ==
242+
updated_config->serverConfig()->getVersion();
243+
});
244+
245+
// We should not have published a new LogsConfig
246+
EXPECT_EQ(0,
247+
cluster->getNode(0)
248+
.stats()["logsconfig_manager_published_server_config_update"]);
249+
250+
// Now update the internal logs section of the config.
251+
logsconfig::LogAttributes log_attrs;
252+
log_attrs.set_replicationFactor(1);
253+
log_attrs.set_extraCopies(0);
254+
log_attrs.set_syncedCopies(0);
255+
log_attrs.set_maxWritesInFlight(2);
256+
configuration::InternalLogs internalLogs;
257+
internalLogs.insert("config_log_deltas", log_attrs);
258+
internalLogs.insert("config_log_snapshots", log_attrs);
259+
internalLogs.insert("event_log_deltas", log_attrs);
260+
internalLogs.insert("event_log_snapshots", log_attrs);
261+
internalLogs.insert("maintenance_log_deltas", log_attrs);
262+
internalLogs.insert("maintenance_log_snapshots", log_attrs);
263+
264+
auto server_config_updated_internal_logs =
265+
ServerConfig::fromDataTest(new_server_config->getClusterName(),
266+
new_server_config->getNodesConfig(),
267+
new_server_config->getMetaDataLogsConfig(),
268+
ServerConfig::PrincipalsConfig(),
269+
new_server_config->getSecurityConfig(),
270+
ServerConfig::TraceLoggerConfig(),
271+
new_server_config->getTrafficShapingConfig(),
272+
new_server_config->getReadIOShapingConfig(),
273+
new_server_config->getServerSettingsConfig(),
274+
new_server_config->getClientSettingsConfig(),
275+
internalLogs);
276+
cluster->writeConfig(
277+
server_config_updated_internal_logs->withVersion(config_version_t(3))
278+
.get(),
279+
cluster_config->logsConfig().get());
280+
281+
// Wait till logs config gets updated
282+
wait_until([&]() -> bool {
283+
return cluster->getNode(0)
284+
.stats()["logsconfig_manager_published_server_config_update"] ==
285+
1;
286+
});
287+
}

0 commit comments

Comments
 (0)