]> git-server-git.apps.pok.os.sepia.ceph.com Git - rocksdb.git/commitdiff
Fix deadlock in WAL sync
authorAndres Noetzli <andres.noetzli@gmail.com>
Sat, 29 Aug 2015 01:06:32 +0000 (18:06 -0700)
committerAndres Noetzli <andres.noetzli@gmail.com>
Sat, 29 Aug 2015 01:07:47 +0000 (18:07 -0700)
Summary:
MarkLogsSynced() was doing `logs_.erase(it++);`. The standard is saying:

```
all iterators and references are invalidated, unless the erased members are at an end (front or back) of the deque (in which case only iterators and references to the erased members are invalidated)
```

Because `it` is an iterator to the first element of the container, it is
invalidated, only one iteration is executed and `log.getting_synced = false;`
is not being done, so `while (logs_.front().getting_synced)` in `WriteImpl()`
is not terminating.

Test Plan: make db_bench && ./db_bench --benchmarks=fillsync

Reviewers: igor, rven, IslamAbdelRahman, anthony, kradhakrishnan, yhchiang, sdong, tnovak

Reviewed By: tnovak

Subscribers: kolmike, dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D45807

db/db_impl.cc
db/db_test.cc

index 7652a66d616985645ee5a7492d0e6a32eead1901..62ab45fb5f3d4ca0d41bcb276bfeb8f347d617a2 100644 (file)
@@ -2019,12 +2019,13 @@ void DBImpl::MarkLogsSynced(
     assert(log.getting_synced);
     if (status.ok() && logs_.size() > 1) {
       logs_to_free_.push_back(log.ReleaseWriter());
-      logs_.erase(it++);
+      it = logs_.erase(it);
     } else {
       log.getting_synced = false;
       ++it;
     }
   }
+  assert(logs_.empty() || (logs_.size() == 1 && !logs_[0].getting_synced));
   log_sync_cv_.SignalAll();
 }
 
index 07a0b570ebcc7b345221189c6e448bf27166a038..e618f2cce9108e2c42cc3bc8b61484aeba1540fa 100644 (file)
@@ -4398,6 +4398,30 @@ TEST_F(DBTest, PurgeInfoLogs) {
   }
 }
 
+TEST_F(DBTest, SyncMultipleLogs) {
+  const uint64_t kNumBatches = 2;
+  const int kBatchSize = 1000;
+
+  Options options = CurrentOptions();
+  options.create_if_missing = true;
+  options.write_buffer_size = 4096;
+  Reopen(options);
+
+  WriteBatch batch;
+  WriteOptions wo;
+  wo.sync = true;
+
+  for (uint64_t b = 0; b < kNumBatches; b++) {
+    batch.Clear();
+    for (int i = 0; i < kBatchSize; i++) {
+      batch.Put(Key(i), DummyString(128));
+    }
+
+    dbfull()->Write(wo, &batch);
+  }
+
+  ASSERT_OK(dbfull()->SyncWAL());
+}
 
 //
 // Test WAL recovery for the various modes available