Skip to content

Commit 453ec52

Browse files
author
Lei Jin
committed
journal log_number correctly in MANIFEST
Summary: Here is what it can cause probelm: There is one memtable flush and one compaction. Both call LogAndApply(). If both edits are applied in the same batch with flush edit first and the compaction edit followed. LogAndApplyHelper() will assign compaction edit current VersionSet's log number(which should be smaller than the log number from flush edit). It cause log_numbers in MANIFEST to be not monotonic increasing, which violates the assume Recover() makes. What is more is after comitting to MANIFEST file, log_number_ in VersionSet is updated to the log_number from the last edit, which is the compaction one. It ends up not updating the log_number. Test Plan: make whitebox_crash_test got another assertion about iter->valid(), not sure if that is related to this. Reviewers: igor, haobo Reviewed By: igor CC: leveldb Differential Revision: https://reviews.facebook.net/D16875
1 parent 5948a66 commit 453ec52

File tree

1 file changed

+26
-3
lines changed

1 file changed

+26
-3
lines changed

db/version_set.cc

+26-3
Original file line numberDiff line numberDiff line change
@@ -1507,9 +1507,20 @@ Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu,
15071507
ManifestWriter* last_writer = &w;
15081508
assert(!manifest_writers_.empty());
15091509
assert(manifest_writers_.front() == &w);
1510+
1511+
uint64_t max_log_number_in_batch = 0;
15101512
for (const auto& writer : manifest_writers_) {
15111513
last_writer = writer;
15121514
LogAndApplyHelper(&builder, v, writer->edit, mu);
1515+
if (edit->has_log_number_) {
1516+
// When batch commit of manifest writes, we could have multiple flush and
1517+
// compaction edits. A flush edit has a bigger log number than what
1518+
// VersionSet has while a compaction edit does not have a log number.
1519+
// In this case, we want to make sure the largest log number is updated
1520+
// to VersionSet
1521+
max_log_number_in_batch =
1522+
std::max(max_log_number_in_batch, edit->log_number_);
1523+
}
15131524
batch_edits.push_back(writer->edit);
15141525
}
15151526
builder.SaveTo(v);
@@ -1640,7 +1651,10 @@ Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu,
16401651
if (s.ok()) {
16411652
manifest_file_size_ = new_manifest_file_size;
16421653
AppendVersion(v);
1643-
log_number_ = edit->log_number_;
1654+
if (max_log_number_in_batch != 0) {
1655+
assert(log_number_ < max_log_number_in_batch);
1656+
log_number_ = max_log_number_in_batch;
1657+
}
16441658
prev_log_number_ = edit->prev_log_number_;
16451659

16461660
} else {
@@ -1678,9 +1692,9 @@ void VersionSet::LogAndApplyHelper(Builder* builder, Version* v,
16781692
if (edit->has_log_number_) {
16791693
assert(edit->log_number_ >= log_number_);
16801694
assert(edit->log_number_ < next_file_number_);
1681-
} else {
1682-
edit->SetLogNumber(log_number_);
16831695
}
1696+
// If the edit does not have log number, it must be generated
1697+
// from a compaction
16841698

16851699
if (!edit->has_prev_log_number_) {
16861700
edit->SetPrevLogNumber(prev_log_number_);
@@ -1772,7 +1786,15 @@ Status VersionSet::Recover() {
17721786

17731787
builder.Apply(&edit);
17741788

1789+
// Only a flush's edit or a new snapshot can write log number during
1790+
// LogAndApply. Since memtables are flushed and inserted into
1791+
// manifest_writers_ queue in order, the log number in MANIFEST file
1792+
// should be monotonically increasing.
17751793
if (edit.has_log_number_) {
1794+
if (have_log_number && log_number > edit.log_number_) {
1795+
s = Status::Corruption("log number decreases");
1796+
break;
1797+
}
17761798
log_number = edit.log_number_;
17771799
have_log_number = true;
17781800
}
@@ -2072,6 +2094,7 @@ Status VersionSet::WriteSnapshot(log::Writer* log) {
20722094
f->smallest_seqno, f->largest_seqno);
20732095
}
20742096
}
2097+
edit.SetLogNumber(log_number_);
20752098

20762099
std::string record;
20772100
edit.EncodeTo(&record);

0 commit comments

Comments
 (0)