Squashed 'src/leveldb/' changes from ab6c84e6f3..a7f9bdc611
What changed, and why it matters
This commit updates Bitcoin Core's embedded LevelDB copy. The most notable change is disabling an automatic database compaction feature that was triggered by read patterns. The commit also reverts a previous increase in memory-mapped file limits, fixes a compiler warning, and makes minor build and code cleanups. None of these changes fix a known active security vulnerability; they are maintenance and behavior-tuning changes.
Treat as routine dependency/subtree maintenance. Review whether the disabled seek compaction or reduced mmap limit affects node performance or resource usage in your deployment. No urgent security patch action is indicated by the commit content.
Security signals we found
Behavior change: automatic seek-triggered compactions disabled in LevelDB
Revert of mmap limit increase on 64-bit POSIX systems (4096 -> 1000)
Uninitialized variable warning fixed in VersionSet::ReuseManifest
C++17 standardization and build cleanup
No explicit security bug fix or CVE reference present
Evidence from the diff
The squashed subtree update contains several LevelDB changes: (1) Version::UpdateStats is stubbed out to disable seek-triggered automatic compactions, with a comment explaining this reduces write amplification on large random-key databases; (2) the POSIX mmap limit for 64-bit systems is reverted from 4096 back to 1000; (3) a Clang -Wconditional-uninitialized warning is fixed by initializing manifest_size; (4) the unused ScopedHandle move-assignment operator is deleted; (5) FALLTHROUGH_INTENDED is replaced with C++17 [[fallthrough]]; (6) CMakeLists.txt now requires C++17 and allows standard overrides when used as a subproject. Tests are updated to match the disabled seek-compaction behavior.
Changed components
src/leveldb/db/version_set.ccsrc/leveldb/util/env_posix.ccsrc/leveldb/util/env_windows.ccsrc/leveldb/util/hash.ccsrc/leveldb/CMakeLists.txtsrc/leveldb/db/autocompact_test.ccsrc/leveldb/db/db_test.ccInspect captured patch +46 / −55
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfd4faa3..78efde95 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,19 +2,25 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. See the AUTHORS file for names of contributors.
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.22)
# Keep the version below in sync with the one in db.h
project(leveldb VERSION 1.22.0 LANGUAGES C CXX)
-# This project can use C11, but will gracefully decay down to C89.
-set(CMAKE_C_STANDARD 11)
-set(CMAKE_C_STANDARD_REQUIRED OFF)
-set(CMAKE_C_EXTENSIONS OFF)
-
-# This project requires C++11.
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_EXTENSIONS OFF)
+# C standard can be overridden when this is used as a sub-project.
+if(NOT CMAKE_C_STANDARD)
+ # This project can use C11, but will gracefully decay down to C89.
+ set(CMAKE_C_STANDARD 11)
+ set(CMAKE_C_STANDARD_REQUIRED OFF)
+ set(CMAKE_C_EXTENSIONS OFF)
+endif(NOT CMAKE_C_STANDARD)
+
+# C++ standard can be overridden when this is used as a sub-project.
+if(NOT CMAKE_CXX_STANDARD)
+ # This project requires C++17.
+ set(CMAKE_CXX_STANDARD 17)
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
+ set(CMAKE_CXX_EXTENSIONS OFF)
+endif(NOT CMAKE_CXX_STANDARD)
if (WIN32)
set(LEVELDB_PLATFORM_NAME LEVELDB_PLATFORM_WINDOWS)
diff --git a/db/autocompact_test.cc b/db/autocompact_test.cc
index e6c97a05..f6e714c6 100644
--- a/db/autocompact_test.cc
+++ b/db/autocompact_test.cc
@@ -54,8 +54,8 @@ static const int kValueSize = 200 * 1024;
static const int kTotalSize = 100 * 1024 * 1024;
static const int kCount = kTotalSize / kValueSize;
-// Read through the first n keys repeatedly and check that they get
-// compacted (verified by checking the size of the key space).
+// Read through the first n keys repeatedly and check that reads do NOT
+// trigger compaction (seek compaction is disabled in this fork).
void AutoCompactTest::DoReads(int n) {
std::string value(kValueSize, 'x');
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
@@ -76,25 +76,23 @@ void AutoCompactTest::DoReads(int n) {
const int64_t initial_size = Size(Key(0), Key(n));
const int64_t initial_other_size = Size(Key(n), Key(kCount));
- // Read until size drops significantly.
+ // Read repeatedly. The size of the read range must NOT shrink: with
+ // seek compaction disabled, reads never schedule a compaction.
std::string limit_key = Key(n);
- for (int read = 0; true; read++) {
- ASSERT_LT(read, 100) << "Taking too long to compact";
+ for (int read = 0; read < 100; read++) {
Iterator* iter = db_->NewIterator(ReadOptions());
for (iter->SeekToFirst();
iter->Valid() && iter->key().ToString() < limit_key; iter->Next()) {
// Drop data
}
delete iter;
- // Wait a little bit to allow any triggered compactions to complete.
- Env::Default()->SleepForMicroseconds(1000000);
uint64_t size = Size(Key(0), Key(n));
fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", read + 1,
size / 1048576.0, Size(Key(n), Key(kCount)) / 1048576.0);
- if (size <= initial_size / 10) {
- break;
- }
}
+ // Give any background work a chance to run, even though none should.
+ Env::Default()->SleepForMicroseconds(1000000);
+ ASSERT_EQ(Size(Key(0), Key(n)), static_cast<uint64_t>(initial_size));
// Verify that the size of the key space not touched by the reads
// is pretty much unchanged.
diff --git a/db/db_test.cc b/db/db_test.cc
index 3c9f8942..16e8ecb9 100644
--- a/db/db_test.cc
+++ b/db/db_test.cc
@@ -735,15 +735,14 @@ TEST(DBTest, GetPicksCorrectFile) {
} while (ChangeOptions());
}
-TEST(DBTest, GetEncountersEmptyLevel) {
+TEST(DBTest, GetDoesNotTriggerSeekCompaction) {
do {
// Arrange for the following to happen:
// * sstable A in level 0
// * nothing in level 1
// * sstable B in level 2
- // Then do enough Get() calls to arrange for an automatic compaction
- // of sstable A. A bug would cause the compaction to be marked as
- // occurring at level 1 (instead of the correct level 0).
+ // Seek compaction is disabled in this fork, so repeated reads must
+ // not change the level layout. A manual compaction must still work.
// Step 1: First place sstables in levels 0 and 2
int compaction_count = 0;
@@ -761,14 +760,17 @@ TEST(DBTest, GetEncountersEmptyLevel) {
ASSERT_EQ(NumTableFilesAtLevel(1), 0);
ASSERT_EQ(NumTableFilesAtLevel(2), 1);
- // Step 3: read a bunch of times
+ // Step 3: many read misses must not schedule any compaction.
for (int i = 0; i < 1000; i++) {
ASSERT_EQ("NOT_FOUND", Get("missing"));
}
-
- // Step 4: Wait for compaction to finish
DelayMilliseconds(1000);
+ ASSERT_EQ(NumTableFilesAtLevel(0), 1);
+ ASSERT_EQ(NumTableFilesAtLevel(1), 0);
+ ASSERT_EQ(NumTableFilesAtLevel(2), 1);
+ // Step 4: a manual compaction still moves the L0 file down.
+ dbfull()->TEST_CompactRange(0, nullptr, nullptr);
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
} while (ChangeOptions());
}
diff --git a/db/version_set.cc b/db/version_set.cc
index cd07346e..2b56bbcd 100644
--- a/db/version_set.cc
+++ b/db/version_set.cc
@@ -400,16 +400,11 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k,
return state.found ? state.s : Status::NotFound(Slice());
}
-bool Version::UpdateStats(const GetStats& stats) {
- FileMetaData* f = stats.seek_file;
- if (f != nullptr) {
- f->allowed_seeks--;
- if (f->allowed_seeks <= 0 && file_to_compact_ == nullptr) {
- file_to_compact_ = f;
- file_to_compact_level_ = stats.seek_file_level;
- return true;
- }
- }
+bool Version::UpdateStats(const GetStats& /*stats*/) {
+ // Disable automatic compactions triggered by read seek counters.
+ // The heuristic was tuned for expensive random seeks and can create
+ // severe write amplification on large random-key databases.
+ // Size and manual compactions still run.
return false;
}
@@ -661,6 +656,8 @@ class VersionSet::Builder {
// same as the compaction of 40KB of data. We are a little
// conservative and allow approximately one seek for every 16KB
// of data before triggering a compaction.
+ //
+ // Note: seek compactions are disabled. See Version::UpdateStats.
f->allowed_seeks = static_cast<int>((f->file_size / 16384U));
if (f->allowed_seeks < 100) f->allowed_seeks = 100;
@@ -994,7 +991,7 @@ bool VersionSet::ReuseManifest(const std::string& dscname,
}
FileType manifest_type;
uint64_t manifest_number;
- uint64_t manifest_size;
+ uint64_t manifest_size = 0;
if (!ParseFileName(dscbase, &manifest_number, &manifest_type) ||
manifest_type != kDescriptorFile ||
!env_->GetFileSize(dscname, &manifest_size).ok() ||
diff --git a/util/env_posix.cc b/util/env_posix.cc
index 8a33534e..00bfd598 100644
--- a/util/env_posix.cc
+++ b/util/env_posix.cc
@@ -42,8 +42,8 @@ namespace {
// Set by EnvPosixTestHelper::SetReadOnlyMMapLimit() and MaxOpenFiles().
int g_open_read_only_file_limit = -1;
-// Up to 4096 mmap regions for 64-bit binaries; none for 32-bit.
-constexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 4096 : 0;
+// Up to 1000 mmap regions for 64-bit binaries; none for 32-bit.
+constexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 1000 : 0;
// Can be set using EnvPosixTestHelper::SetReadOnlyMMapLimit().
int g_mmap_limit = kDefaultMmapLimit;
diff --git a/util/env_windows.cc b/util/env_windows.cc
index 8897e2aa..6ef27e45 100644
--- a/util/env_windows.cc
+++ b/util/env_windows.cc
@@ -81,10 +81,7 @@ class ScopedHandle {
ScopedHandle& operator=(const ScopedHandle&) = delete;
- ScopedHandle& operator=(ScopedHandle&& rhs) noexcept {
- if (this != &rhs) handle_ = rhs.Release();
- return *this;
- }
+ ScopedHandle& operator=(ScopedHandle&& rhs) = delete;
bool Close() {
if (!is_valid()) {
diff --git a/util/hash.cc b/util/hash.cc
index 5432b618..6b277306 100644
--- a/util/hash.cc
+++ b/util/hash.cc
@@ -8,15 +8,6 @@
#include "util/coding.h"
-// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
-// between switch labels. The real definition should be provided externally.
-// This one is a fallback version for unsupported compilers.
-#ifndef FALLTHROUGH_INTENDED
-#define FALLTHROUGH_INTENDED \
- do { \
- } while (0)
-#endif
-
namespace leveldb {
uint32_t Hash(const char* data, size_t n, uint32_t seed) {
@@ -39,10 +30,10 @@ uint32_t Hash(const char* data, size_t n, uint32_t seed) {
switch (limit - data) {
case 3:
h += static_cast<uint8_t>(data[2]) << 16;
- FALLTHROUGH_INTENDED;
+ [[fallthrough]];
case 2:
h += static_cast<uint8_t>(data[1]) << 8;
- FALLTHROUGH_INTENDED;
+ [[fallthrough]];
case 1:
h += static_cast<uint8_t>(data[0]);
h *= m;
Why this scored 23/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.