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.
2001for (int id = 0; id < kNumThreads; id++) {2002thread[id].state = &mt;2003thread[id].id = id;2004env_->StartThread(MTThreadBody, &thread[id]);2005}2007// Let them run for a while2008DelayMilliseconds(kTestSeconds * 1000);2010// Stop the threads and wait for them to finish2011mt.stop.store(true, std::memory_order_release);2012for (int id = 0; id < kNumThreads; id++) {2013while (!mt.thread_done[id].load(std::memory_order_acquire)) {2014DelayMilliseconds(100);2015}2016}2017} while (ChangeOptions());2018}2020namespace {2021typedef std::map<std::string, std::string> KVMap;2022}2024class ModelDB : public DB {2025public:2026class ModelSnapshot : public Snapshot {2027public:2028KVMap map_;2029};2031explicit ModelDB(const Options& options) : options_(options) {}2032~ModelDB() override = default;2033Status Put(const WriteOptions& o, const Slice& k, const Slice& v) override {2034return DB::Put(o, k, v);2035}2036Status Delete(const WriteOptions& o, const Slice& key) override {2037return DB::Delete(o, key);2038}2039Status Get(const ReadOptions& options, const Slice& key,2040std::string* value) override {2041assert(false); // Not implemented2042return Status::NotFound(key);2043}2044Iterator* NewIterator(const ReadOptions& options) override {2045if (options.snapshot == nullptr) {2046KVMap* saved = new KVMap;2047*saved = map_;2048return new ModelIter(saved, true);2049} else {2050const KVMap* snapshot_state =2051&(reinterpret_cast<const ModelSnapshot*>(options.snapshot)->map_);2052return new ModelIter(snapshot_state, false);2053}2054}2055const Snapshot* GetSnapshot() override {2056ModelSnapshot* snapshot = new ModelSnapshot;2057snapshot->map_ = map_;2058return snapshot;2059}2061void ReleaseSnapshot(const Snapshot* snapshot) override {2062delete reinterpret_cast<const ModelSnapshot*>(snapshot);2063}2064Status Write(const WriteOptions& options, WriteBatch* batch) override {2065class Handler : public WriteBatch::Handler {2066public:2067KVMap* map_;2068void Put(const Slice& key, const Slice& value) override {2069(*map_)[key.ToString()] = value.ToString();2070}2071void Delete(const Slice& key) override { map_->erase(key.ToString()); }2072};2073Handler handler;2074handler.map_ = &map_;2075return batch->Iterate(&handler);2076}2078bool GetProperty(const Slice& property, std::string* value) override {2079return false;2080}2081void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) override {2082for (int i = 0; i < n; i++) {2083sizes[i] = 0;2084}2085}2086void CompactRange(const Slice* start, const Slice* end) override {}2088private:2089class ModelIter : public Iterator {2090public:2091ModelIter(const KVMap* map, bool owned)2092: map_(map), owned_(owned), iter_(map_->end()) {}2093~ModelIter() override {2094if (owned_) delete map_;2095}2096bool Valid() const override { return iter_ != map_->end(); }2097void SeekToFirst() override { iter_ = map_->begin(); }2098void SeekToLast() override {2099if (map_->empty()) {2100iter_ = map_->end();2101} else {2102iter_ = map_->find(map_->rbegin()->first);2103}2104}2105void Seek(const Slice& k) override {2106iter_ = map_->lower_bound(k.ToString());2107}2108void Next() override { ++iter_; }2109void Prev() override { --iter_; }2110Slice key() const override { return iter_->first; }2111Slice value() const override { return iter_->second; }2112Status status() const override { return Status::OK(); }2114private:2115const KVMap* const map_;2116const bool owned_; // Do we own map_2117KVMap::const_iterator iter_;2118};2119const Options options_;2120KVMap map_;2121};2123static bool CompareIterators(int step, DB* model, DB* db,2124const Snapshot* model_snap,2125const Snapshot* db_snap) {2126ReadOptions options;2127options.snapshot = model_snap;2128Iterator* miter = model->NewIterator(options);2129options.snapshot = db_snap;2130Iterator* dbiter = db->NewIterator(options);2131bool ok = true;2132int count = 0;2133for (miter->SeekToFirst(), dbiter->SeekToFirst();2134ok && miter->Valid() && dbiter->Valid(); miter->Next(), dbiter->Next()) {2135count++;2136if (miter->key().compare(dbiter->key()) != 0) {2137fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", step,2138EscapeString(miter->key()).c_str(),2139EscapeString(dbiter->key()).c_str());2140ok = false;2141break;2142}2144if (miter->value().compare(dbiter->value()) != 0) {2145fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n",2146step, EscapeString(miter->key()).c_str(),2147EscapeString(miter->value()).c_str(),2148EscapeString(miter->value()).c_str());2149ok = false;2150}2151}2153if (ok) {2154if (miter->Valid() != dbiter->Valid()) {2155fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n",2156step, miter->Valid(), dbiter->Valid());2157ok = false;2158}2159}2160fprintf(stderr, "%d entries compared: ok=%d\n", count, ok);2161delete miter;2162delete dbiter;2163return ok;2164}2166TEST(DBTest, Randomized) {2167Random rnd(test::RandomSeed());2168do {2169ModelDB model(CurrentOptions());2170const int N = 10000;2171const Snapshot* model_snap = nullptr;2172const Snapshot* db_snap = nullptr;2173std::string k, v;2174for (int step = 0; step < N; step++) {2175if (step % 100 == 0) {2176fprintf(stderr, "Step %d of %d\n", step, N);2177}2178// TODO(sanjay): Test Get() works2179int p = rnd.Uniform(100);2180if (p < 45) { // Put2181k = RandomKey(&rnd);2182v = RandomString(2183&rnd, rnd.OneIn(20) ? 100 + rnd.Uniform(100) : rnd.Uniform(8));2184ASSERT_OK(model.Put(WriteOptions(), k, v));2185ASSERT_OK(db_->Put(WriteOptions(), k, v));2187} else if (p < 90) { // Delete2188k = RandomKey(&rnd);2189ASSERT_OK(model.Delete(WriteOptions(), k));2190ASSERT_OK(db_->Delete(WriteOptions(), k));2192} else { // Multi-element batch2193WriteBatch b;2194const int num = rnd.Uniform(8);2195for (int i = 0; i < num; i++) {2196if (i == 0 || !rnd.OneIn(10)) {2197k = RandomKey(&rnd);2198} else {2199// Periodically reuse the same key from the previous iter, so2200// we have multiple entries in the write batch for the same key2201}2202if (rnd.OneIn(2)) {2203v = RandomString(&rnd, rnd.Uniform(10));2204b.Put(k, v);2205} else {2206b.Delete(k);2207}2208}2209ASSERT_OK(model.Write(WriteOptions(), &b));2210ASSERT_OK(db_->Write(WriteOptions(), &b));2211}2213if ((step % 100) == 0) {2214ASSERT_TRUE(CompareIterators(step, &model, db_, nullptr, nullptr));2215ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap));2216// Save a snapshot from each DB this time that we'll use next2217// time we compare things, to make sure the current state is2218// preserved with the snapshot2219if (model_snap != nullptr) model.ReleaseSnapshot(model_snap);2220if (db_snap != nullptr) db_->ReleaseSnapshot(db_snap);2222Reopen();2223ASSERT_TRUE(CompareIterators(step, &model, db_, nullptr, nullptr));2225model_snap = model.GetSnapshot();2226db_snap = db_->GetSnapshot();2227}2228}2229if (model_snap != nullptr) model.ReleaseSnapshot(model_snap);2230if (db_snap != nullptr) db_->ReleaseSnapshot(db_snap);2231} while (ChangeOptions());2232}2234std::string MakeKey(unsigned int num) {2235char buf[30];2236snprintf(buf, sizeof(buf), "%016u", num);2237return std::string(buf);2238}2240void BM_LogAndApply(int iters, int num_base_files) {2241std::string dbname = test::TmpDir() + "/leveldb_test_benchmark";2242DestroyDB(dbname, Options());2244DB* db = nullptr;2245Options opts;2246opts.create_if_missing = true;2247Status s = DB::Open(opts, dbname, &db);2248ASSERT_OK(s);2249ASSERT_TRUE(db != nullptr);
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.