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.
1251while (true) {1252Writer* ready = writers_.front();1253writers_.pop_front();1254if (ready != &w) {1255ready->status = status;1256ready->done = true;1257ready->cv.Signal();1258}1259if (ready == last_writer) break;1260}1262// Notify new head of write queue1263if (!writers_.empty()) {1264writers_.front()->cv.Signal();1265}1267return status;1268}1270// REQUIRES: Writer list must be non-empty1271// REQUIRES: First writer must have a non-null batch1272WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) {1273mutex_.AssertHeld();1274assert(!writers_.empty());1275Writer* first = writers_.front();1276WriteBatch* result = first->batch;1277assert(result != nullptr);1279size_t size = WriteBatchInternal::ByteSize(first->batch);1281// Allow the group to grow up to a maximum size, but if the1282// original write is small, limit the growth so we do not slow1283// down the small write too much.1284size_t max_size = 1 << 20;1285if (size <= (128 << 10)) {1286max_size = size + (128 << 10);1287}1289*last_writer = first;1290std::deque<Writer*>::iterator iter = writers_.begin();1291++iter; // Advance past "first"1292for (; iter != writers_.end(); ++iter) {1293Writer* w = *iter;1294if (w->sync && !first->sync) {1295// Do not include a sync write into a batch handled by a non-sync write.1296break;1297}1299if (w->batch != nullptr) {1300size += WriteBatchInternal::ByteSize(w->batch);1301if (size > max_size) {1302// Do not make batch too big1303break;1304}1306// Append to *result1307if (result == first->batch) {1308// Switch to temporary batch instead of disturbing caller's batch1309result = tmp_batch_;1310assert(WriteBatchInternal::Count(result) == 0);1311WriteBatchInternal::Append(result, first->batch);1312}1313WriteBatchInternal::Append(result, w->batch);1314}1315*last_writer = w;1316}1317return result;1318}1320// REQUIRES: mutex_ is held1321// REQUIRES: this thread is currently at the front of the writer queue1322Status DBImpl::MakeRoomForWrite(bool force) {1323mutex_.AssertHeld();1324assert(!writers_.empty());1325bool allow_delay = !force;1326Status s;1327while (true) {1328if (!bg_error_.ok()) {1329// Yield previous error1330s = bg_error_;1331break;1332} else if (allow_delay && versions_->NumLevelFiles(0) >=1333config::kL0_SlowdownWritesTrigger) {1334// We are getting close to hitting a hard limit on the number of1335// L0 files. Rather than delaying a single write by several1336// seconds when we hit the hard limit, start delaying each1337// individual write by 1ms to reduce latency variance. Also,1338// this delay hands over some CPU to the compaction thread in1339// case it is sharing the same core as the writer.1340mutex_.Unlock();1341env_->SleepForMicroseconds(1000);1342allow_delay = false; // Do not delay a single write more than once1343mutex_.Lock();1344} else if (!force &&1345(mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) {1346// There is room in current memtable1347break;1348} else if (imm_ != nullptr) {1349// We have filled up the current memtable, but the previous1350// one is still being compacted, so we wait.1351Log(options_.info_log, "Current memtable full; waiting...\n");1352background_work_finished_signal_.Wait();1353} else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) {1354// There are too many level-0 files.1355Log(options_.info_log, "Too many L0 files; waiting...\n");1356background_work_finished_signal_.Wait();1357} else {1358// Attempt to switch to a new memtable and trigger compaction of old1359assert(versions_->PrevLogNumber() == 0);1360uint64_t new_log_number = versions_->NewFileNumber();1361WritableFile* lfile = nullptr;1362s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);1363if (!s.ok()) {1364// Avoid chewing through file number space in a tight loop.1365versions_->ReuseFileNumber(new_log_number);1366break;1367}1368delete log_;1369delete logfile_;1370logfile_ = lfile;1371logfile_number_ = new_log_number;1372log_ = new log::Writer(lfile);1373imm_ = mem_;1374has_imm_.store(true, std::memory_order_release);1375mem_ = new MemTable(internal_comparator_);1376mem_->Ref();1377force = false; // Do not force another compaction if have room1378MaybeScheduleCompaction();1379}1380}1381return s;1382}1384bool DBImpl::GetProperty(const Slice& property, std::string* value) {1385value->clear();1387MutexLock l(&mutex_);1388Slice in = property;1389Slice prefix("leveldb.");1390if (!in.starts_with(prefix)) return false;1391in.remove_prefix(prefix.size());1393if (in.starts_with("num-files-at-level")) {1394in.remove_prefix(strlen("num-files-at-level"));1395uint64_t level;1396bool ok = ConsumeDecimalNumber(&in, &level) && in.empty();1397if (!ok || level >= config::kNumLevels) {1398return false;1399} else {1400char buf[100];1401snprintf(buf, sizeof(buf), "%d",1402versions_->NumLevelFiles(static_cast<int>(level)));1403*value = buf;1404return true;1405}1406} else if (in == "stats") {1407char buf[200];1408snprintf(buf, sizeof(buf),1409" Compactions\n"1410"Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n"1411"--------------------------------------------------\n");1412value->append(buf);1413for (int level = 0; level < config::kNumLevels; level++) {1414int files = versions_->NumLevelFiles(level);1415if (stats_[level].micros > 0 || files > 0) {1416snprintf(buf, sizeof(buf), "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", level,1417files, versions_->NumLevelBytes(level) / 1048576.0,1418stats_[level].micros / 1e6,1419stats_[level].bytes_read / 1048576.0,1420stats_[level].bytes_written / 1048576.0);1421value->append(buf);1422}1423}1424return true;1425} else if (in == "sstables") {1426*value = versions_->current()->DebugString();1427return true;1428} else if (in == "approximate-memory-usage") {1429size_t total_usage = options_.block_cache->TotalCharge();1430if (mem_) {1431total_usage += mem_->ApproximateMemoryUsage();1432}1433if (imm_) {1434total_usage += imm_->ApproximateMemoryUsage();1435}1436char buf[50];1437snprintf(buf, sizeof(buf), "%llu",1438static_cast<unsigned long long>(total_usage));1439value->append(buf);1440return true;1441}1443return false;1444}1446void DBImpl::GetApproximateSizes(const Range* range, int n, uint64_t* sizes) {1447// TODO(opt): better implementation1448MutexLock l(&mutex_);1449Version* v = versions_->current();1450v->Ref();1452for (int i = 0; i < n; i++) {1453// Convert user_key into a corresponding internal key.1454InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek);1455InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek);1456uint64_t start = versions_->ApproximateOffsetOf(v, k1);1457uint64_t limit = versions_->ApproximateOffsetOf(v, k2);1458sizes[i] = (limit >= start ? limit - start : 0);1459}1461v->Unref();1462}1464// Default implementations of convenience methods that subclasses of DB1465// can call if they wish1466Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) {1467WriteBatch batch;1468batch.Put(key, value);1469return Write(opt, &batch);1470}1472Status DB::Delete(const WriteOptions& opt, const Slice& key) {1473WriteBatch batch;1474batch.Delete(key);1475return Write(opt, &batch);1476}1478DB::~DB() = default;1480Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) {1481*dbptr = nullptr;1483DBImpl* impl = new DBImpl(options, dbname);1484impl->mutex_.Lock();1485VersionEdit edit;1486// Recover handles create_if_missing, error_if_exists1487bool save_manifest = false;1488Status s = impl->Recover(&edit, &save_manifest);1489if (s.ok() && impl->mem_ == nullptr) {1490// Create new log and a corresponding memtable.1491uint64_t new_log_number = impl->versions_->NewFileNumber();1492WritableFile* lfile;1493s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),1494&lfile);1495if (s.ok()) {1496edit.SetLogNumber(new_log_number);1497impl->logfile_ = lfile;1498impl->logfile_number_ = new_log_number;1499impl->log_ = new log::Writer(lfile);1500impl->mem_ = new MemTable(impl->internal_comparator_);
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.