Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shutting down database hangs in dtest-debug #7331

Closed
bhalevy opened this issue Oct 5, 2020 · 7 comments · Fixed by #7334
Closed

Shutting down database hangs in dtest-debug #7331

bhalevy opened this issue Oct 5, 2020 · 7 comments · Fixed by #7334
Assignees
Milestone

Comments

@bhalevy
Copy link
Member

bhalevy commented Oct 5, 2020

Seen consistently since https://jenkins.scylladb.com/view/master/job/scylla-master/job/dtest-debug/604/testReport
Scylla version f1fcf4f

https://jenkins.scylladb.com/view/master/job/scylla-master/job/dtest-debug/604/artifact/logs-debug.2/1601137898758_repair_additional_test.RepairAdditionalTest.repair_option_pr_dc_host_test/node1.log

INFO  2020-09-26 16:14:03,637 [shard 0] init - Shutting down database
Scylla version 666.development-0.20200924.f1fcf4f13 with build-id 1b71d370bdf7e15b911b8e16e18b291737d79b35 starting ...
...
INFO  2020-09-26 16:25:46,848 [shard 0] init - Shutting down database
Scylla version 666.development-0.20200924.f1fcf4f13 with build-id 1b71d370bdf7e15b911b8e16e18b291737d79b35 starting ...

https://jenkins.scylladb.com/view/master/job/scylla-master/job/dtest-debug/604/artifact/logs-debug.2/1601139448436_repair_additional_test.RepairAdditionalTest.repair_option_pr_multi_dc_test/node1.log

INFO  2020-09-26 16:32:42,395 [shard 0] init - Shutting down database
Scylla version 666.development-0.20200924.f1fcf4f13 with build-id 1b71d370bdf7e15b911b8e16e18b291737d79b35 starting ...

But not only in those dtests, for example:
https://jenkins.scylladb.com/view/master/job/scylla-master/job/dtest-debug/610/artifact/logs-debug.2/1601850222686_bootstrap_test.TestBootstrap.start_stop_test/node1.log

INFO  2020-10-04 22:21:36,140 [shard 0] init - Shutting down database
<EOF>

Note that this looks similar, but different than #7183

@bhalevy
Copy link
Member Author

bhalevy commented Oct 5, 2020

@avikivity this might be related to your sstables manager changes

@bhalevy
Copy link
Member Author

bhalevy commented Oct 5, 2020

I reproduced the hang locally with the following additional debug printouts:

diff --git a/database.cc b/database.cc
index c03bd3dca4..35a8f45be7 100644
--- a/database.cc
+++ b/database.cc
@@ -1799,7 +1799,9 @@ database::stop() {
 
     // try to ensure that CL has done disk flushing
     future<> maybe_shutdown_commitlog = _commitlog != nullptr ? _commitlog->shutdown() : make_ready_future<>();
+    dblog.debug("Shutting down commitlog");
     return maybe_shutdown_commitlog.then([this] {
+        dblog.debug("Waiting for view updates");
         return _view_update_concurrency_sem.wait(max_memory_pending_view_updates());
     }).then([this] {
         if (_commitlog != nullptr) {
@@ -1807,16 +1809,22 @@ database::stop() {
         }
         return make_ready_future<>();
     }).then([this] {
+        dblog.debug("Shutting down system dirty memory manager");
         return _system_dirty_memory_manager.shutdown();
     }).then([this] {
+        dblog.debug("Shutting down dirty memory manager");
         return _dirty_memory_manager.shutdown();
     }).then([this] {
+        dblog.debug("Shutting down streaming dirty memory manager");
         return _streaming_dirty_memory_manager.shutdown();
     }).then([this] {
+        dblog.debug("Shutting down memtable controller");
         return _memtable_controller.shutdown();
     }).then([this] {
+        dblog.debug("Shutting down user sstables manager");
         return _user_sstables_manager->close();
     }).then([this] {
+        dblog.debug("Shutting down system sstables manager");
         return _system_sstables_manager->close();
     });
 }
diff --git a/db/commitlog/commitlog.cc b/db/commitlog/commitlog.cc
index c2a34db182..8a6e995e83 100644
--- a/db/commitlog/commitlog.cc
+++ b/db/commitlog/commitlog.cc
@@ -1565,11 +1565,15 @@ future<> db::commitlog::segment_manager::shutdown() {
             discard_unused_segments();
             // Now that the gate is closed and requests completed we are sure nobody else will pop()
             return clear_reserve_segments().finally([this] {
+                clogger.debug("Waiting on reserve_replenisher");
                 return std::move(_reserve_replenisher).then_wrapped([this] (auto f) {
                     // Could be cleaner with proper seastar support
                     if (f.failed()) {
-                        _shutdown_promise->set_exception(f.get_exception());
+                        auto ep = f.get_exception();
+                        clogger.debug("Shutdown failed: {}", ep);
+                        _shutdown_promise->set_exception(std::move(ep));
                     } else {
+                        clogger.debug("Shutdown completed successfully");
                         _shutdown_promise->set_value();
                     }
                 });

dtest command line:

DEBUG=true PRINT_DEBUG=true KEEP_TEST_DIR=true CASSANDRA_DIR=../scylla/build/debug nosetests -s -v --process-timeout=7200 repair_additional_test:RepairAdditionalTest.repair_option_pr_multi_dc_test

I'm seeing the following pattern in the logs:

INFO  2020-10-05 13:30:19,344 [shard 0] init - Shutting down database
DEBUG 2020-10-05 13:30:19,540 [shard 0] database - Shutting down commitlog
DEBUG 2020-10-05 13:30:19,540 [shard 0] database - Waiting for view updates
DEBUG 2020-10-05 13:30:19,541 [shard 0] database - Shutting down system dirty memory manager
DEBUG 2020-10-05 13:30:19,541 [shard 0] database - Shutting down dirty memory manager
DEBUG 2020-10-05 13:30:19,541 [shard 0] database - Shutting down streaming dirty memory manager
DEBUG 2020-10-05 13:30:19,542 [shard 0] database - Shutting down memtable controller
DEBUG 2020-10-05 13:30:19,542 [shard 0] database - Shutting down user sstables manager
DEBUG 2020-10-05 13:30:23,034 [shard 0] batchlog_manager - Batchlog replay on shard 0: starts
DEBUG 2020-10-05 13:30:23,034 [shard 0] batchlog_manager - Started replayAllFailedBatches (cpu 0)
DEBUG 2020-10-05 13:30:23,035 [shard 0] storage_proxy - Estimated result rows per range: 0; requested rows: 128, concurrent range requests: 1
DEBUG 2020-10-05 13:30:23,041 [shard 0] batchlog_manager - Finished replayAllFailedBatches
DEBUG 2020-10-05 13:30:23,041 [shard 0] batchlog_manager - Batchlog replay on shard 0: done
DEBUG 2020-10-05 13:31:23,037 [shard 0] batchlog_manager - Batchlog replay on shard 0: starts
DEBUG 2020-10-05 13:31:23,037 [shard 0] batchlog_manager - Started replayAllFailedBatches (cpu 0)
DEBUG 2020-10-05 13:31:23,038 [shard 0] storage_proxy - Estimated result rows per range: 0; requested rows: 128, concurrent range requests: 1
DEBUG 2020-10-05 13:31:23,041 [shard 0] batchlog_manager - Finished replayAllFailedBatches
DEBUG 2020-10-05 13:31:23,041 [shard 0] batchlog_manager - Batchlog replay on shard 0: done
DEBUG 2020-10-05 13:32:23,046 [shard 0] batchlog_manager - Batchlog replay on shard 0: starts
DEBUG 2020-10-05 13:32:23,047 [shard 0] batchlog_manager - Started replayAllFailedBatches (cpu 0)
DEBUG 2020-10-05 13:32:23,047 [shard 0] storage_proxy - Estimated result rows per range: 0; requested rows: 128, concurrent range requests: 1
DEBUG 2020-10-05 13:32:23,051 [shard 0] batchlog_manager - Finished replayAllFailedBatches
DEBUG 2020-10-05 13:32:23,051 [shard 0] batchlog_manager - Batchlog replay on shard 0: done
DEBUG 2020-10-05 13:33:23,054 [shard 0] batchlog_manager - Batchlog replay on shard 0: starts
DEBUG 2020-10-05 13:33:23,054 [shard 0] batchlog_manager - Started replayAllFailedBatches (cpu 0)
DEBUG 2020-10-05 13:33:23,054 [shard 0] storage_proxy - Estimated result rows per range: 0; requested rows: 128, concurrent range requests: 1
DEBUG 2020-10-05 13:33:23,057 [shard 0] batchlog_manager - Finished replayAllFailedBatches
DEBUG 2020-10-05 13:33:23,057 [shard 0] batchlog_manager - Batchlog replay on shard 0: done
DEBUG 2020-10-05 13:34:23,059 [shard 0] batchlog_manager - Batchlog replay on shard 0: starts
DEBUG 2020-10-05 13:34:23,059 [shard 0] batchlog_manager - Started replayAllFailedBatches (cpu 0)
DEBUG 2020-10-05 13:34:23,059 [shard 0] storage_proxy - Estimated result rows per range: 0; requested rows: 128, concurrent range requests: 1
DEBUG 2020-10-05 13:34:23,062 [shard 0] batchlog_manager - Finished replayAllFailedBatches
DEBUG 2020-10-05 13:34:23,062 [shard 0] batchlog_manager - Batchlog replay on shard 0: done
DEBUG 2020-10-05 13:35:23,063 [shard 0] batchlog_manager - Batchlog replay on shard 0: starts
DEBUG 2020-10-05 13:35:23,063 [shard 0] batchlog_manager - Started replayAllFailedBatches (cpu 0)
DEBUG 2020-10-05 13:35:23,078 [shard 0] storage_proxy - Estimated result rows per range: 0; requested rows: 128, concurrent range requests: 1
DEBUG 2020-10-05 13:35:23,081 [shard 0] batchlog_manager - Finished replayAllFailedBatches
DEBUG 2020-10-05 13:35:23,081 [shard 0] batchlog_manager - Batchlog replay on shard 0: done
DEBUG 2020-10-05 13:36:23,079 [shard 0] batchlog_manager - Batchlog replay on shard 0: starts
DEBUG 2020-10-05 13:36:23,080 [shard 0] batchlog_manager - Started replayAllFailedBatches (cpu 0)
DEBUG 2020-10-05 13:36:23,080 [shard 0] storage_proxy - Estimated result rows per range: 0; requested rows: 128, concurrent range requests: 1
DEBUG 2020-10-05 13:36:23,083 [shard 0] batchlog_manager - Finished replayAllFailedBatches
DEBUG 2020-10-05 13:36:23,083 [shard 0] batchlog_manager - Batchlog replay on shard 0: done

Here is the full log:
node5.log.gz

@bhalevy
Copy link
Member Author

bhalevy commented Oct 5, 2020

Cc @xemul

@bhalevy
Copy link
Member Author

bhalevy commented Oct 5, 2020

Similarly, in database_test test_database_with_data_in_sstables_is_a_mutation_source:

DEBUG 2020-10-05 14:01:22,720 [shard 0] database - Shutting down commitlog
DEBUG 2020-10-05 14:01:22,722 [shard 0] commitlog - Synced segment CommitLog-1-2.log
DEBUG 2020-10-05 14:01:22,722 [shard 0] commitlog - Issuing shutdown for all segments
DEBUG 2020-10-05 14:01:22,725 [shard 0] commitlog - Shutdown segment CommitLog-1-2.log
DEBUG 2020-10-05 14:01:22,725 [shard 0] commitlog - Segment CommitLog-1-2.log is unused
DEBUG 2020-10-05 14:01:22,725 [shard 0] commitlog - Segment CommitLog-1-2.log is no longer active and will submitted for delete now
DEBUG 2020-10-05 14:01:22,725 [shard 0] commitlog - Segment CommitLog-1-3.log is no longer active and will submitted for delete now
DEBUG 2020-10-05 14:01:22,726 [shard 0] commitlog - Deleting segment file /tmp/scylla-4179d0e8-067b-465e-a1ec-42b7e47a6117/commitlog.dir/CommitLog-1-2.log
DEBUG 2020-10-05 14:01:22,727 [shard 0] commitlog - Deleting segment file /tmp/scylla-4179d0e8-067b-465e-a1ec-42b7e47a6117/commitlog.dir/CommitLog-1-3.log
DEBUG 2020-10-05 14:01:22,734 [shard 1] commitlog - Issuing sync for all segments
DEBUG 2020-10-05 14:01:22,734 [shard 1] database - Shutting down commitlog
DEBUG 2020-10-05 14:01:22,735 [shard 1] commitlog - Synced segment CommitLog-1-18014398509481987.log
DEBUG 2020-10-05 14:01:22,735 [shard 1] commitlog - Issuing shutdown for all segments
DEBUG 2020-10-05 14:01:22,737 [shard 0] commitlog - Waiting on reserve_replenisher
DEBUG 2020-10-05 14:01:22,738 [shard 0] commitlog - Shutdown completed successfully
DEBUG 2020-10-05 14:01:22,738 [shard 0] database - Waiting for view updates
DEBUG 2020-10-05 14:01:22,738 [shard 0] database - Shutting down system dirty memory manager
DEBUG 2020-10-05 14:01:22,739 [shard 0] database - Shutting down dirty memory manager
DEBUG 2020-10-05 14:01:22,740 [shard 0] database - Shutting down streaming dirty memory manager
DEBUG 2020-10-05 14:01:22,740 [shard 0] database - Shutting down memtable controller
DEBUG 2020-10-05 14:01:22,740 [shard 0] database - Shutting down user sstables manager
DEBUG 2020-10-05 14:01:22,741 [shard 0] database - Shutting down system sstables manager
DEBUG 2020-10-05 14:01:22,741 [shard 1] commitlog - Shutdown segment CommitLog-1-18014398509481987.log
DEBUG 2020-10-05 14:01:22,742 [shard 1] commitlog - Segment CommitLog-1-18014398509481987.log is unused
DEBUG 2020-10-05 14:01:22,742 [shard 1] commitlog - Segment CommitLog-1-18014398509481987.log is no longer active and will submitted for delete now
DEBUG 2020-10-05 14:01:22,742 [shard 1] commitlog - Segment CommitLog-1-18014398509481988.log is no longer active and will submitted for delete now
DEBUG 2020-10-05 14:01:22,743 [shard 1] commitlog - Deleting segment file /tmp/scylla-4179d0e8-067b-465e-a1ec-42b7e47a6117/commitlog.dir/CommitLog-1-18014398509481987.log
DEBUG 2020-10-05 14:01:22,744 [shard 1] commitlog - Deleting segment file /tmp/scylla-4179d0e8-067b-465e-a1ec-42b7e47a6117/commitlog.dir/CommitLog-1-18014398509481988.log
DEBUG 2020-10-05 14:01:22,744 [shard 1] commitlog - Waiting on reserve_replenisher
DEBUG 2020-10-05 14:01:22,744 [shard 1] commitlog - Shutdown completed successfully
DEBUG 2020-10-05 14:01:22,744 [shard 1] database - Waiting for view updates
DEBUG 2020-10-05 14:01:22,745 [shard 1] database - Shutting down system dirty memory manager
DEBUG 2020-10-05 14:01:22,745 [shard 1] database - Shutting down dirty memory manager
DEBUG 2020-10-05 14:01:22,746 [shard 1] database - Shutting down streaming dirty memory manager
DEBUG 2020-10-05 14:01:22,747 [shard 1] database - Shutting down memtable controller
DEBUG 2020-10-05 14:01:22,747 [shard 1] database - Shutting down user sstables manager
DEBUG 2020-10-05 14:01:22,747 [shard 1] database - Shutting down system sstables manager

database_test.log.gz

@slivne slivne added this to the 4.3 milestone Oct 5, 2020
nyh added a commit that referenced this issue Oct 7, 2020
…tion()' from Avi Kivity

Fix a race condition in on_compaction_completion() that can prevent shutdown,
as well as an exception handling error. See individual patches for details.

Fixes #7331.

Closes #7334

* github.com:scylladb/scylla:
  table: fix mishandled _sstable_deleted_gate exception in on_compaction_completion
  table: fix on_compaction_completion corrupting _sstables_compacted_but_not_deleted during self-race
avikivity pushed a commit that referenced this issue Oct 7, 2020
…tion()' from Avi Kivity

Fix a race condition in on_compaction_completion() that can prevent shutdown,
as well as an exception handling error. See individual patches for details.

Fixes #7331.

Closes #7334

* github.com:scylladb/scylla:
  table: fix mishandled _sstable_deleted_gate exception in on_compaction_completion
  table: fix on_compaction_completion corrupting _sstables_compacted_but_not_deleted during self-race
@avikivity
Copy link
Member

This fixes a bug that wasn't in any released branch (broken in a536988), so no need to backport.

@raphaelsc
Copy link
Member

"Before a536988, this was a benign race (only resulting in
deleted file space not being reclaimed until the service is shut
down),"

turns out this is not a benign race. #8038

if a deleted sstable remains around, it may potentially prevent expired sstables from being purged. i'll prepare a backport of it to 4.2.1

avikivity added a commit that referenced this issue Feb 14, 2021
…t_not_deleted during self-race

on_compaction_completion() updates _sstables_compacted_but_not_deleted
through a temporary to avoid an exception causing a partial update:

  1. copy _sstables_compacted_but_not_deleted to a temporary
  2. update temporary
  3. do dangerous stuff
  4. move temporary to _sstables_compacted_but_not_deleted

This is racy when we have parallel compactions, since step 3 yields.
We can have two invocations running in parallel, taking snapshots
of the same _sstables_compacted_but_not_deleted in step 1, each
modifying it in different ways, and only one of them winning the
race and assigning in step 4. With the right timing we can end
with extra sstables in _sstables_compacted_but_not_deleted.

Before a536988, this was a benign race (only resulting in
deleted file space not being reclaimed until the service is shut
down), but afterwards, extra sstable references result in the service
refusing to shut down. This was observed in database_test in debug
mode, where the race more or less reliably happens for system.truncated.

Fix by using a different method to protect
_sstables_compacted_but_not_deleted. We unconditionally update it,
and also unconditionally fix it up (on success or failure) using
seastar::defer(). The fixup includes a call to rebuild_statistics()
which must happen every time we touch the sstable list.

Ref #7331.
Fixes #8038.

BACKPORT NOTES:
- Turns out this race prevented deletion of expired sstables because the leaked
deleted sstables would be accounted when checking if an expired sstable can
be purged.
- Switch to unordered_set<>::count() as it's not supported by older compilers.

(cherry picked from commit a43d507)
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20210212203832.45846-1-raphaelsc@scylladb.com>
@avikivity
Copy link
Member

Backported to 4.2 too, in light of the extra negative effects of the bug.

asias pushed a commit to asias/scylla that referenced this issue Apr 15, 2021
…t_not_deleted during self-race

on_compaction_completion() updates _sstables_compacted_but_not_deleted
through a temporary to avoid an exception causing a partial update:

  1. copy _sstables_compacted_but_not_deleted to a temporary
  2. update temporary
  3. do dangerous stuff
  4. move temporary to _sstables_compacted_but_not_deleted

This is racy when we have parallel compactions, since step 3 yields.
We can have two invocations running in parallel, taking snapshots
of the same _sstables_compacted_but_not_deleted in step 1, each
modifying it in different ways, and only one of them winning the
race and assigning in step 4. With the right timing we can end
with extra sstables in _sstables_compacted_but_not_deleted.

Before a536988, this was a benign race (only resulting in
deleted file space not being reclaimed until the service is shut
down), but afterwards, extra sstable references result in the service
refusing to shut down. This was observed in database_test in debug
mode, where the race more or less reliably happens for system.truncated.

Fix by using a different method to protect
_sstables_compacted_but_not_deleted. We unconditionally update it,
and also unconditionally fix it up (on success or failure) using
seastar::defer(). The fixup includes a call to rebuild_statistics()
which must happen every time we touch the sstable list.

Ref scylladb#7331.
Fixes scylladb#8038.

BACKPORT NOTES:
- Turns out this race prevented deletion of expired sstables because the leaked
deleted sstables would be accounted when checking if an expired sstable can
be purged.
- Switch to unordered_set<>::count() as it's not supported by older compilers.

(cherry picked from commit a43d507)
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20210212203832.45846-1-raphaelsc@scylladb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants