mirror of
https://github.com/google/leveldb.git
synced 2025-02-04 07:10:10 +08:00
Release LevelDB 1.16
- Make Log::Reader not report a corruption when the last record in a log file is truncated. - Fix issue 224: variable created but not utilized. - Remove comment that referenced a removed feature.
This commit is contained in:
parent
0cfb990d58
commit
269fc6ca94
2
Makefile
2
Makefile
@ -72,7 +72,7 @@ SHARED = $(SHARED1)
|
|||||||
else
|
else
|
||||||
# Update db.h if you change these.
|
# Update db.h if you change these.
|
||||||
SHARED_MAJOR = 1
|
SHARED_MAJOR = 1
|
||||||
SHARED_MINOR = 15
|
SHARED_MINOR = 16
|
||||||
SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
|
SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
|
||||||
SHARED2 = $(SHARED1).$(SHARED_MAJOR)
|
SHARED2 = $(SHARED1).$(SHARED_MAJOR)
|
||||||
SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
|
SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
|
||||||
|
@ -133,7 +133,9 @@ bool Reader::ReadRecord(Slice* record, std::string* scratch) {
|
|||||||
|
|
||||||
case kEof:
|
case kEof:
|
||||||
if (in_fragmented_record) {
|
if (in_fragmented_record) {
|
||||||
ReportCorruption(scratch->size(), "partial record without end(3)");
|
// This can be caused by the writer dying immediately after
|
||||||
|
// writing a physical record but before completing the next; don't
|
||||||
|
// treat it as a corruption, just ignore the entire logical record.
|
||||||
scratch->clear();
|
scratch->clear();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -193,13 +195,12 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result) {
|
|||||||
eof_ = true;
|
eof_ = true;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (buffer_.size() == 0) {
|
|
||||||
// End of file
|
|
||||||
return kEof;
|
|
||||||
} else {
|
} else {
|
||||||
size_t drop_size = buffer_.size();
|
// Note that if buffer_ is non-empty, we have a truncated header at the
|
||||||
|
// end of the file, which can be caused by the writer crashing in the
|
||||||
|
// middle of writing the header. Instead of considering this an error,
|
||||||
|
// just report EOF.
|
||||||
buffer_.clear();
|
buffer_.clear();
|
||||||
ReportCorruption(drop_size, "truncated record at end of file");
|
|
||||||
return kEof;
|
return kEof;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,8 +214,14 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result) {
|
|||||||
if (kHeaderSize + length > buffer_.size()) {
|
if (kHeaderSize + length > buffer_.size()) {
|
||||||
size_t drop_size = buffer_.size();
|
size_t drop_size = buffer_.size();
|
||||||
buffer_.clear();
|
buffer_.clear();
|
||||||
ReportCorruption(drop_size, "bad record length");
|
if (!eof_) {
|
||||||
return kBadRecord;
|
ReportCorruption(drop_size, "bad record length");
|
||||||
|
return kBadRecord;
|
||||||
|
}
|
||||||
|
// If the end of the file has been reached without reading |length| bytes
|
||||||
|
// of payload, assume the writer died in the middle of writing the record.
|
||||||
|
// Don't report a corruption.
|
||||||
|
return kEof;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == kZeroType && length == 0) {
|
if (type == kZeroType && length == 0) {
|
||||||
|
@ -351,20 +351,32 @@ TEST(LogTest, BadRecordType) {
|
|||||||
ASSERT_EQ("OK", MatchError("unknown record type"));
|
ASSERT_EQ("OK", MatchError("unknown record type"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(LogTest, TruncatedTrailingRecord) {
|
TEST(LogTest, TruncatedTrailingRecordIsIgnored) {
|
||||||
Write("foo");
|
Write("foo");
|
||||||
ShrinkSize(4); // Drop all payload as well as a header byte
|
ShrinkSize(4); // Drop all payload as well as a header byte
|
||||||
ASSERT_EQ("EOF", Read());
|
ASSERT_EQ("EOF", Read());
|
||||||
ASSERT_EQ(kHeaderSize - 1, DroppedBytes());
|
// Truncated last record is ignored, not treated as an error.
|
||||||
ASSERT_EQ("OK", MatchError("truncated record at end of file"));
|
ASSERT_EQ(0, DroppedBytes());
|
||||||
|
ASSERT_EQ("", ReportMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(LogTest, BadLength) {
|
TEST(LogTest, BadLength) {
|
||||||
|
const int kPayloadSize = kBlockSize - kHeaderSize;
|
||||||
|
Write(BigString("bar", kPayloadSize));
|
||||||
|
Write("foo");
|
||||||
|
// Least significant size byte is stored in header[4].
|
||||||
|
IncrementByte(4, 1);
|
||||||
|
ASSERT_EQ("foo", Read());
|
||||||
|
ASSERT_EQ(kBlockSize, DroppedBytes());
|
||||||
|
ASSERT_EQ("OK", MatchError("bad record length"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LogTest, BadLengthAtEndIsIgnored) {
|
||||||
Write("foo");
|
Write("foo");
|
||||||
ShrinkSize(1);
|
ShrinkSize(1);
|
||||||
ASSERT_EQ("EOF", Read());
|
ASSERT_EQ("EOF", Read());
|
||||||
ASSERT_EQ(kHeaderSize + 2, DroppedBytes());
|
ASSERT_EQ(0, DroppedBytes());
|
||||||
ASSERT_EQ("OK", MatchError("bad record length"));
|
ASSERT_EQ("", ReportMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(LogTest, ChecksumMismatch) {
|
TEST(LogTest, ChecksumMismatch) {
|
||||||
@ -415,6 +427,24 @@ TEST(LogTest, UnexpectedFirstType) {
|
|||||||
ASSERT_EQ("OK", MatchError("partial record without end"));
|
ASSERT_EQ("OK", MatchError("partial record without end"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(LogTest, MissingLastIsIgnored) {
|
||||||
|
Write(BigString("bar", kBlockSize));
|
||||||
|
// Remove the LAST block, including header.
|
||||||
|
ShrinkSize(14);
|
||||||
|
ASSERT_EQ("EOF", Read());
|
||||||
|
ASSERT_EQ("", ReportMessage());
|
||||||
|
ASSERT_EQ(0, DroppedBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LogTest, PartialLastIsIgnored) {
|
||||||
|
Write(BigString("bar", kBlockSize));
|
||||||
|
// Cause a bad record length in the LAST block.
|
||||||
|
ShrinkSize(1);
|
||||||
|
ASSERT_EQ("EOF", Read());
|
||||||
|
ASSERT_EQ("", ReportMessage());
|
||||||
|
ASSERT_EQ(0, DroppedBytes());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(LogTest, ErrorJoinsRecords) {
|
TEST(LogTest, ErrorJoinsRecords) {
|
||||||
// Consider two fragmented records:
|
// Consider two fragmented records:
|
||||||
// first(R1) last(R1) first(R2) last(R2)
|
// first(R1) last(R1) first(R2) last(R2)
|
||||||
|
@ -242,7 +242,6 @@ class Repairer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ExtractMetaData() {
|
void ExtractMetaData() {
|
||||||
std::vector<TableInfo> kept;
|
|
||||||
for (size_t i = 0; i < table_numbers_.size(); i++) {
|
for (size_t i = 0; i < table_numbers_.size(); i++) {
|
||||||
ScanTable(table_numbers_[i]);
|
ScanTable(table_numbers_[i]);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
Does not support:
|
Does not support:
|
||||||
. getters for the option types
|
. getters for the option types
|
||||||
. custom comparators that implement key shortening
|
. custom comparators that implement key shortening
|
||||||
. capturing post-write-snapshot
|
|
||||||
. custom iter, db, env, cache implementations using just the C bindings
|
. custom iter, db, env, cache implementations using just the C bindings
|
||||||
|
|
||||||
Some conventions:
|
Some conventions:
|
||||||
|
@ -14,7 +14,7 @@ namespace leveldb {
|
|||||||
|
|
||||||
// Update Makefile if you change these
|
// Update Makefile if you change these
|
||||||
static const int kMajorVersion = 1;
|
static const int kMajorVersion = 1;
|
||||||
static const int kMinorVersion = 15;
|
static const int kMinorVersion = 16;
|
||||||
|
|
||||||
struct Options;
|
struct Options;
|
||||||
struct ReadOptions;
|
struct ReadOptions;
|
||||||
|
Loading…
Reference in New Issue
Block a user