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.
1001}1003// Check that writes done during a memtable compaction are recovered1004// if the database is shutdown during the memtable compaction.1005TEST(DBTest, RecoverDuringMemtableCompaction) {1006do {1007Options options = CurrentOptions();1008options.env = env_;1009options.write_buffer_size = 1000000;1010Reopen(&options);1012// Trigger a long memtable compaction and reopen the database during it1013ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file1014ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable1015ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction1016ASSERT_OK(Put("bar", "v2")); // Goes to new log file1018Reopen(&options);1019ASSERT_EQ("v1", Get("foo"));1020ASSERT_EQ("v2", Get("bar"));1021ASSERT_EQ(std::string(10000000, 'x'), Get("big1"));1022ASSERT_EQ(std::string(1000, 'y'), Get("big2"));1023} while (ChangeOptions());1024}1026static std::string Key(int i) {1027char buf[100];1028snprintf(buf, sizeof(buf), "key%06d", i);1029return std::string(buf);1030}1032TEST(DBTest, MinorCompactionsHappen) {1033Options options = CurrentOptions();1034options.write_buffer_size = 10000;1035Reopen(&options);1037const int N = 500;1039int starting_num_tables = TotalTableFiles();1040for (int i = 0; i < N; i++) {1041ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));1042}1043int ending_num_tables = TotalTableFiles();1044ASSERT_GT(ending_num_tables, starting_num_tables);1046for (int i = 0; i < N; i++) {1047ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));1048}1050Reopen();1052for (int i = 0; i < N; i++) {1053ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));1054}1055}1057TEST(DBTest, RecoverWithLargeLog) {1058{1059Options options = CurrentOptions();1060Reopen(&options);1061ASSERT_OK(Put("big1", std::string(200000, '1')));1062ASSERT_OK(Put("big2", std::string(200000, '2')));1063ASSERT_OK(Put("small3", std::string(10, '3')));1064ASSERT_OK(Put("small4", std::string(10, '4')));1065ASSERT_EQ(NumTableFilesAtLevel(0), 0);1066}1068// Make sure that if we re-open with a small write buffer size that1069// we flush table files in the middle of a large log file.1070Options options = CurrentOptions();1071options.write_buffer_size = 100000;1072Reopen(&options);1073ASSERT_EQ(NumTableFilesAtLevel(0), 3);1074ASSERT_EQ(std::string(200000, '1'), Get("big1"));1075ASSERT_EQ(std::string(200000, '2'), Get("big2"));1076ASSERT_EQ(std::string(10, '3'), Get("small3"));1077ASSERT_EQ(std::string(10, '4'), Get("small4"));1078ASSERT_GT(NumTableFilesAtLevel(0), 1);1079}1081TEST(DBTest, CompactionsGenerateMultipleFiles) {1082Options options = CurrentOptions();1083options.write_buffer_size = 100000000; // Large write buffer1084Reopen(&options);1086Random rnd(301);1088// Write 8MB (80 values, each 100K)1089ASSERT_EQ(NumTableFilesAtLevel(0), 0);1090std::vector<std::string> values;1091for (int i = 0; i < 80; i++) {1092values.push_back(RandomString(&rnd, 100000));1093ASSERT_OK(Put(Key(i), values[i]));1094}1096// Reopening moves updates to level-01097Reopen(&options);1098dbfull()->TEST_CompactRange(0, nullptr, nullptr);1100ASSERT_EQ(NumTableFilesAtLevel(0), 0);1101ASSERT_GT(NumTableFilesAtLevel(1), 1);1102for (int i = 0; i < 80; i++) {1103ASSERT_EQ(Get(Key(i)), values[i]);1104}1105}1107TEST(DBTest, RepeatedWritesToSameKey) {1108Options options = CurrentOptions();1109options.env = env_;1110options.write_buffer_size = 100000; // Small write buffer1111Reopen(&options);1113// We must have at most one file per level except for level-0,1114// which may have up to kL0_StopWritesTrigger files.1115const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger;1117Random rnd(301);1118std::string value = RandomString(&rnd, 2 * options.write_buffer_size);1119for (int i = 0; i < 5 * kMaxFiles; i++) {1120Put("key", value);1121ASSERT_LE(TotalTableFiles(), kMaxFiles);1122fprintf(stderr, "after %d: %d files\n", i + 1, TotalTableFiles());1123}1124}1126TEST(DBTest, SparseMerge) {1127Options options = CurrentOptions();1128options.compression = kNoCompression;1129Reopen(&options);1131FillLevels("A", "Z");1133// Suppose there is:1134// small amount of data with prefix A1135// large amount of data with prefix B1136// small amount of data with prefix C1137// and that recent updates have made small changes to all three prefixes.1138// Check that we do not do a compaction that merges all of B in one shot.1139const std::string value(1000, 'x');1140Put("A", "va");1141// Write approximately 100MB of "B" values1142for (int i = 0; i < 100000; i++) {1143char key[100];1144snprintf(key, sizeof(key), "B%010d", i);1145Put(key, value);1146}1147Put("C", "vc");1148dbfull()->TEST_CompactMemTable();1149dbfull()->TEST_CompactRange(0, nullptr, nullptr);1151// Make sparse update1152Put("A", "va2");1153Put("B100", "bvalue2");1154Put("C", "vc2");1155dbfull()->TEST_CompactMemTable();1157// Compactions should not cause us to create a situation where1158// a file overlaps too much data at the next level.1159ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20 * 1048576);1160dbfull()->TEST_CompactRange(0, nullptr, nullptr);1161ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20 * 1048576);1162dbfull()->TEST_CompactRange(1, nullptr, nullptr);1163ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20 * 1048576);1164}1166static bool Between(uint64_t val, uint64_t low, uint64_t high) {1167bool result = (val >= low) && (val <= high);1168if (!result) {1169fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",1170(unsigned long long)(val), (unsigned long long)(low),1171(unsigned long long)(high));1172}1173return result;1174}1176TEST(DBTest, ApproximateSizes) {1177do {1178Options options = CurrentOptions();1179options.write_buffer_size = 100000000; // Large write buffer1180options.compression = kNoCompression;1181DestroyAndReopen();1183ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));1184Reopen(&options);1185ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));1187// Write 8MB (80 values, each 100K)1188ASSERT_EQ(NumTableFilesAtLevel(0), 0);1189const int N = 80;1190static const int S1 = 100000;1191static const int S2 = 105000; // Allow some expansion from metadata1192Random rnd(301);1193for (int i = 0; i < N; i++) {1194ASSERT_OK(Put(Key(i), RandomString(&rnd, S1)));1195}1197// 0 because GetApproximateSizes() does not account for memtable space1198ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));1200if (options.reuse_logs) {1201// Recovery will reuse memtable, and GetApproximateSizes() does not1202// account for memtable usage;1203Reopen(&options);1204ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));1205continue;1206}1208// Check sizes across recovery by reopening a few times1209for (int run = 0; run < 3; run++) {1210Reopen(&options);1212for (int compact_start = 0; compact_start < N; compact_start += 10) {1213for (int i = 0; i < N; i += 10) {1214ASSERT_TRUE(Between(Size("", Key(i)), S1 * i, S2 * i));1215ASSERT_TRUE(Between(Size("", Key(i) + ".suffix"), S1 * (i + 1),1216S2 * (i + 1)));1217ASSERT_TRUE(Between(Size(Key(i), Key(i + 10)), S1 * 10, S2 * 10));1218}1219ASSERT_TRUE(Between(Size("", Key(50)), S1 * 50, S2 * 50));1220ASSERT_TRUE(Between(Size("", Key(50) + ".suffix"), S1 * 50, S2 * 50));1222std::string cstart_str = Key(compact_start);1223std::string cend_str = Key(compact_start + 9);1224Slice cstart = cstart_str;1225Slice cend = cend_str;1226dbfull()->TEST_CompactRange(0, &cstart, &cend);1227}1229ASSERT_EQ(NumTableFilesAtLevel(0), 0);1230ASSERT_GT(NumTableFilesAtLevel(1), 0);1231}1232} while (ChangeOptions());1233}1235TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {1236do {1237Options options = CurrentOptions();1238options.compression = kNoCompression;1239Reopen();1241Random rnd(301);1242std::string big1 = RandomString(&rnd, 100000);1243ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000)));1244ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000)));1245ASSERT_OK(Put(Key(2), big1));1246ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000)));1247ASSERT_OK(Put(Key(4), big1));1248ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000)));1249ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));1250ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));
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.