db,view: split stopping view builder to drain+stop

In order to be able to avoid a deadlock when CQL server cannot be started,
the view builder shutdown procedure is now split to two parts -
- drain and stop. Drain is performed before storage proxy shutdown,
but stop() will be called even before drain is scheduled.
The deadlock is as follows:
 - view builder creates a reader permit in order to be able
   to read from system tables
 - CQL server fails to start, shutdown procedure begins
 - view builder stop() is not called (because it was not scheduled
   yet), so it holds onto its reader permit
 - database shutdown procedure waits for all permits to be destroyed,
   and it hangs indefinitely because view builder keeps holding
   its permit.
This commit is contained in:
Piotr Sarna
2021-09-08 10:48:33 +02:00
parent 9a77a03ea1
commit 5d7c765422
2 changed files with 15 additions and 2 deletions

View File

@@ -1473,8 +1473,11 @@ future<> view_builder::start(service::migration_manager& mm) {
return make_ready_future<>();
}
future<> view_builder::stop() {
vlogger.info("Stopping view builder");
future<> view_builder::drain() {
if (_as.abort_requested()) {
return make_ready_future();
}
vlogger.info("Draining view builder");
_as.request_abort();
return _started.then([this] {
return _mnotifier.unregister_listener(this).then([this] {
@@ -1494,6 +1497,11 @@ future<> view_builder::stop() {
});
}
future<> view_builder::stop() {
vlogger.info("Stopping view builder");
return drain();
}
view_builder::build_step& view_builder::get_or_create_build_step(utils::UUID base_id) {
auto it = _base_to_build_step.find(base_id);
if (it == _base_to_build_step.end()) {

View File

@@ -205,6 +205,11 @@ public:
*/
future<> start(service::migration_manager&);
/**
* Drains view building in order to prepare it for shutdown.
*/
future<> drain();
/**
* Stops the view building process.
*/