Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1252if (options.reuse_logs) {1253// Need to force a memtable compaction since recovery does not do so.1254ASSERT_OK(dbfull()->TEST_CompactMemTable());1255}1257// Check sizes across recovery by reopening a few times1258for (int run = 0; run < 3; run++) {1259Reopen(&options);1261ASSERT_TRUE(Between(Size("", Key(0)), 0, 0));1262ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000));1263ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000));1264ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000));1265ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000));1266ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000));1267ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000));1268ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000));1269ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000));1271ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000));1273dbfull()->TEST_CompactRange(0, nullptr, nullptr);1274}1275} while (ChangeOptions());1276}1278TEST(DBTest, IteratorPinsRef) {1279Put("foo", "hello");1281// Get iterator that will yield the current contents of the DB.1282Iterator* iter = db_->NewIterator(ReadOptions());1284// Write to force compactions1285Put("foo", "newvalue1");1286for (int i = 0; i < 100; i++) {1287ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values1288}1289Put("foo", "newvalue2");1291iter->SeekToFirst();1292ASSERT_TRUE(iter->Valid());1293ASSERT_EQ("foo", iter->key().ToString());1294ASSERT_EQ("hello", iter->value().ToString());1295iter->Next();1296ASSERT_TRUE(!iter->Valid());1297delete iter;1298}1300TEST(DBTest, Snapshot) {1301do {1302Put("foo", "v1");1303const Snapshot* s1 = db_->GetSnapshot();1304Put("foo", "v2");1305const Snapshot* s2 = db_->GetSnapshot();1306Put("foo", "v3");1307const Snapshot* s3 = db_->GetSnapshot();1309Put("foo", "v4");1310ASSERT_EQ("v1", Get("foo", s1));1311ASSERT_EQ("v2", Get("foo", s2));1312ASSERT_EQ("v3", Get("foo", s3));1313ASSERT_EQ("v4", Get("foo"));1315db_->ReleaseSnapshot(s3);1316ASSERT_EQ("v1", Get("foo", s1));1317ASSERT_EQ("v2", Get("foo", s2));1318ASSERT_EQ("v4", Get("foo"));1320db_->ReleaseSnapshot(s1);1321ASSERT_EQ("v2", Get("foo", s2));1322ASSERT_EQ("v4", Get("foo"));1324db_->ReleaseSnapshot(s2);1325ASSERT_EQ("v4", Get("foo"));1326} while (ChangeOptions());1327}1329TEST(DBTest, HiddenValuesAreRemoved) {1330do {1331Random rnd(301);1332FillLevels("a", "z");1334std::string big = RandomString(&rnd, 50000);1335Put("foo", big);1336Put("pastfoo", "v");1337const Snapshot* snapshot = db_->GetSnapshot();1338Put("foo", "tiny");1339Put("pastfoo2", "v2"); // Advance sequence number one more1341ASSERT_OK(dbfull()->TEST_CompactMemTable());1342ASSERT_GT(NumTableFilesAtLevel(0), 0);1344ASSERT_EQ(big, Get("foo", snapshot));1345ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000));1346db_->ReleaseSnapshot(snapshot);1347ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]");1348Slice x("x");1349dbfull()->TEST_CompactRange(0, nullptr, &x);1350ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");1351ASSERT_EQ(NumTableFilesAtLevel(0), 0);1352ASSERT_GE(NumTableFilesAtLevel(1), 1);1353dbfull()->TEST_CompactRange(1, nullptr, &x);1354ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");1356ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000));1357} while (ChangeOptions());1358}1360TEST(DBTest, DeletionMarkers1) {1361Put("foo", "v1");1362ASSERT_OK(dbfull()->TEST_CompactMemTable());1363const int last = config::kMaxMemCompactLevel;1364ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level1366// Place a table at level last-1 to prevent merging with preceding mutation1367Put("a", "begin");1368Put("z", "end");1369dbfull()->TEST_CompactMemTable();1370ASSERT_EQ(NumTableFilesAtLevel(last), 1);1371ASSERT_EQ(NumTableFilesAtLevel(last - 1), 1);1373Delete("foo");1374Put("foo", "v2");1375ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");1376ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-21377ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");1378Slice z("z");1379dbfull()->TEST_CompactRange(last - 2, nullptr, &z);1380// DEL eliminated, but v1 remains because we aren't compacting that level1381// (DEL can be eliminated because v2 hides v1).1382ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]");1383dbfull()->TEST_CompactRange(last - 1, nullptr, nullptr);1384// Merging last-1 w/ last, so we are the base level for "foo", so1385// DEL is removed. (as is v1).1386ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]");1387}1389TEST(DBTest, DeletionMarkers2) {1390Put("foo", "v1");1391ASSERT_OK(dbfull()->TEST_CompactMemTable());1392const int last = config::kMaxMemCompactLevel;1393ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level1395// Place a table at level last-1 to prevent merging with preceding mutation1396Put("a", "begin");1397Put("z", "end");1398dbfull()->TEST_CompactMemTable();1399ASSERT_EQ(NumTableFilesAtLevel(last), 1);1400ASSERT_EQ(NumTableFilesAtLevel(last - 1), 1);1402Delete("foo");1403ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");1404ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-21405ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");1406dbfull()->TEST_CompactRange(last - 2, nullptr, nullptr);1407// DEL kept: "last" file overlaps1408ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");1409dbfull()->TEST_CompactRange(last - 1, nullptr, nullptr);1410// Merging last-1 w/ last, so we are the base level for "foo", so1411// DEL is removed. (as is v1).1412ASSERT_EQ(AllEntriesFor("foo"), "[ ]");1413}1415TEST(DBTest, OverlapInLevel0) {1416do {1417ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config";1419// Fill levels 1 and 2 to disable the pushing of new memtables to levels >1420// 0.1421ASSERT_OK(Put("100", "v100"));1422ASSERT_OK(Put("999", "v999"));1423dbfull()->TEST_CompactMemTable();1424ASSERT_OK(Delete("100"));1425ASSERT_OK(Delete("999"));1426dbfull()->TEST_CompactMemTable();1427ASSERT_EQ("0,1,1", FilesPerLevel());1429// Make files spanning the following ranges in level-0:1430// files[0] 200 .. 9001431// files[1] 300 .. 5001432// Note that files are sorted by smallest key.1433ASSERT_OK(Put("300", "v300"));1434ASSERT_OK(Put("500", "v500"));1435dbfull()->TEST_CompactMemTable();1436ASSERT_OK(Put("200", "v200"));1437ASSERT_OK(Put("600", "v600"));1438ASSERT_OK(Put("900", "v900"));1439dbfull()->TEST_CompactMemTable();1440ASSERT_EQ("2,1,1", FilesPerLevel());1442// Compact away the placeholder files we created initially1443dbfull()->TEST_CompactRange(1, nullptr, nullptr);1444dbfull()->TEST_CompactRange(2, nullptr, nullptr);1445ASSERT_EQ("2", FilesPerLevel());1447// Do a memtable compaction. Before bug-fix, the compaction would1448// not detect the overlap with level-0 files and would incorrectly place1449// the deletion in a deeper level.1450ASSERT_OK(Delete("600"));1451dbfull()->TEST_CompactMemTable();1452ASSERT_EQ("3", FilesPerLevel());1453ASSERT_EQ("NOT_FOUND", Get("600"));1454} while (ChangeOptions());1455}1457TEST(DBTest, L0_CompactionBug_Issue44_a) {1458Reopen();1459ASSERT_OK(Put("b", "v"));1460Reopen();1461ASSERT_OK(Delete("b"));1462ASSERT_OK(Delete("a"));1463Reopen();1464ASSERT_OK(Delete("a"));1465Reopen();1466ASSERT_OK(Put("a", "v"));1467Reopen();1468Reopen();1469ASSERT_EQ("(a->v)", Contents());1470DelayMilliseconds(1000); // Wait for compaction to finish1471ASSERT_EQ("(a->v)", Contents());1472}1474TEST(DBTest, L0_CompactionBug_Issue44_b) {1475Reopen();1476Put("", "");1477Reopen();1478Delete("e");1479Put("", "");1480Reopen();1481Put("c", "cv");1482Reopen();1483Put("", "");1484Reopen();1485Put("", "");1486DelayMilliseconds(1000); // Wait for compaction to finish1487Reopen();1488Put("d", "dv");1489Reopen();1490Put("", "");1491Reopen();1492Delete("d");1493Delete("b");1494Reopen();1495ASSERT_EQ("(->)(c->cv)", Contents());1496DelayMilliseconds(1000); // Wait for compaction to finish1497ASSERT_EQ("(->)(c->cv)", Contents());1498}1500TEST(DBTest, Fflush_Issue474) {
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.