Serve no-op configuration database interface when disabled

By continuing to serve the configuration database interface used by
clients even when disabled, clients no longer need to specify a special
`--no-config-db` option when running commands which talk to the
configuration database.
This commit is contained in:
Lukas Joswiak 2024-07-08 13:56:03 -07:00
parent 462c164bbd
commit 890e7610ad
4 changed files with 60 additions and 7 deletions

View File

@ -175,10 +175,15 @@ for *every* ``fdbserver`` process.
The only client change from the configuration database is as part of the change
coordinators command. The change coordinators command is not considered
successful until the configuration database is readable on the new
coordinators. This will cause the change coordinators command to hang if run
against a database with dynamic knobs disabled. To disable the client side
configuration database liveness check, specify the ``--no-config-db`` flag when
changing coordinators. For example:
coordinators. If the configuration database has been disabled server-side via
the ``-no-config-db`` command line option, the coordinators will continue to
serve the configuration interface, but will reply to each request with an empty
response. Client-side changes are no longer necessary when disabling the
configuration database.
Optionally, the client liveness check of the configuration database can be
prevented by specifying the ``-no-config-db`` flag when changing the
coordinators. For example:
```
fdbcli> coordinators auto --no-config-db

View File

@ -821,6 +821,33 @@ class ConfigNodeImpl {
return Void();
}
ACTOR static Future<Void> serveDisabled(ConfigNodeImpl* self,
ConfigTransactionInterface const* cti,
ConfigFollowerInterface const* cfi) {
loop {
choose {
when(ConfigTransactionGetGenerationRequest req = waitNext(cti->getGeneration.getFuture())) {
req.reply.send(ConfigTransactionGetGenerationReply{ ConfigGeneration() });
}
when(ConfigTransactionGetRequest req = waitNext(cti->get.getFuture())) {
req.reply.send(ConfigTransactionGetReply());
}
when(ConfigTransactionCommitRequest req = waitNext(cti->commit.getFuture())) {
req.reply.send(Void());
}
when(ConfigTransactionGetConfigClassesRequest req = waitNext(cti->getClasses.getFuture())) {
req.reply.send(ConfigTransactionGetConfigClassesReply());
}
when(ConfigTransactionGetKnobsRequest req = waitNext(cti->getKnobs.getFuture())) {
req.reply.send(ConfigTransactionGetKnobsReply());
}
when(state ConfigFollowerLockRequest req = waitNext(cfi->lock.getFuture())) {
req.reply.send(Void());
}
}
}
}
ACTOR static Future<bool> registered(ConfigNodeImpl* self) {
Optional<Value> value = wait(self->kvStore->readValue(registeredKey));
return value.present();
@ -846,6 +873,10 @@ public:
return serve(this, &cbi, &cti, &cfi);
}
Future<Void> serveDisabled(ConfigTransactionInterface const& cti, ConfigFollowerInterface const& cfi) {
return serveDisabled(this, &cti, &cfi);
}
Future<Void> serve(ConfigBroadcastInterface const& cbi) { return serve(this, &cbi, true); }
Future<Void> serve(ConfigTransactionInterface const& cti) { return serve(this, &cti); }
@ -869,6 +900,10 @@ Future<Void> ConfigNode::serve(ConfigBroadcastInterface const& cbi,
return impl->serve(cbi, cti, cfi);
}
Future<Void> ConfigNode::serveDisabled(ConfigTransactionInterface const& cti, ConfigFollowerInterface const& cfi) {
return impl->serveDisabled(cti, cfi);
}
Future<Void> ConfigNode::serve(ConfigBroadcastInterface const& cbi) {
return impl->serve(cbi);
}

View File

@ -773,11 +773,21 @@ ACTOR Future<Void> coordinationServer(std::string dataFolder,
.detail("Folder", dataFolder)
.detail("ConfigNodeValid", configNode.isValid());
if (configNode.isValid()) {
configTransactionInterface.setupWellKnownEndpoints();
configFollowerInterface.setupWellKnownEndpoints();
// Serve some of the config node interface even if it is disabled. This
// allows clients to get responses to requests and avoid hanging when
// running commands such as a coordinator change.
bool configNodeValid = configNode.isValid();
if (!configNodeValid) {
configNode = makeReference<ConfigNode>(dataFolder);
}
configTransactionInterface.setupWellKnownEndpoints();
configFollowerInterface.setupWellKnownEndpoints();
if (configNodeValid) {
configDatabaseServer =
brokenPromiseToNever(configNode->serve(cbi, configTransactionInterface, configFollowerInterface));
} else {
configDatabaseServer =
brokenPromiseToNever(configNode->serveDisabled(configTransactionInterface, configFollowerInterface));
}
try {

View File

@ -37,6 +37,9 @@ public:
Future<Void> serve(ConfigBroadcastInterface const&,
ConfigTransactionInterface const&,
ConfigFollowerInterface const&);
// Serves some interfaces even when the configuration database is disabled,
// to prevent client requests from hanging.
Future<Void> serveDisabled(ConfigTransactionInterface const&, ConfigFollowerInterface const&);
public: // Testing
Future<Void> serve(ConfigBroadcastInterface const&);