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.
251WritableFile* actual_writable_file;252Status s = target()->NewAppendableFile(fname, &actual_writable_file);253if (s.ok()) {254FileState state(fname);255state.pos_ = 0;256{257MutexLock l(&mutex_);258if (db_file_state_.count(fname) == 0) {259new_files_since_last_dir_sync_.insert(fname);260} else {261state = db_file_state_[fname];262}263}264*result = new TestWritableFile(state, actual_writable_file, this);265}266return s;267}269Status FaultInjectionTestEnv::DropUnsyncedFileData() {270Status s;271MutexLock l(&mutex_);272for (const auto& kvp : db_file_state_) {273if (!s.ok()) {274break;275}276const FileState& state = kvp.second;277if (!state.IsFullySynced()) {278s = state.DropUnsyncedData();279}280}281return s;282}284void FaultInjectionTestEnv::DirWasSynced() {285MutexLock l(&mutex_);286new_files_since_last_dir_sync_.clear();287}289bool FaultInjectionTestEnv::IsFileCreatedSinceLastDirSync(290const std::string& filename) {291MutexLock l(&mutex_);292return new_files_since_last_dir_sync_.find(filename) !=293new_files_since_last_dir_sync_.end();294}296void FaultInjectionTestEnv::UntrackFile(const std::string& f) {297MutexLock l(&mutex_);298db_file_state_.erase(f);299new_files_since_last_dir_sync_.erase(f);300}302Status FaultInjectionTestEnv::DeleteFile(const std::string& f) {303Status s = EnvWrapper::DeleteFile(f);304ASSERT_OK(s);305if (s.ok()) {306UntrackFile(f);307}308return s;309}311Status FaultInjectionTestEnv::RenameFile(const std::string& s,312const std::string& t) {313Status ret = EnvWrapper::RenameFile(s, t);315if (ret.ok()) {316MutexLock l(&mutex_);317if (db_file_state_.find(s) != db_file_state_.end()) {318db_file_state_[t] = db_file_state_[s];319db_file_state_.erase(s);320}322if (new_files_since_last_dir_sync_.erase(s) != 0) {323assert(new_files_since_last_dir_sync_.find(t) ==324new_files_since_last_dir_sync_.end());325new_files_since_last_dir_sync_.insert(t);326}327}329return ret;330}332void FaultInjectionTestEnv::ResetState() {333// Since we are not destroying the database, the existing files334// should keep their recorded synced/flushed state. Therefore335// we do not reset db_file_state_ and new_files_since_last_dir_sync_.336SetFilesystemActive(true);337}339Status FaultInjectionTestEnv::DeleteFilesCreatedAfterLastDirSync() {340// Because DeleteFile access this container make a copy to avoid deadlock341mutex_.Lock();342std::set<std::string> new_files(new_files_since_last_dir_sync_.begin(),343new_files_since_last_dir_sync_.end());344mutex_.Unlock();345Status status;346for (const auto& new_file : new_files) {347Status delete_status = DeleteFile(new_file);348if (!delete_status.ok() && status.ok()) {349status = std::move(delete_status);350}351}352return status;353}355void FaultInjectionTestEnv::WritableFileClosed(const FileState& state) {356MutexLock l(&mutex_);357db_file_state_[state.filename_] = state;358}360Status FileState::DropUnsyncedData() const {361int64_t sync_pos = pos_at_last_sync_ == -1 ? 0 : pos_at_last_sync_;362return Truncate(filename_, sync_pos);363}365class FaultInjectionTest {366public:367enum ExpectedVerifResult { VAL_EXPECT_NO_ERROR, VAL_EXPECT_ERROR };368enum ResetMethod { RESET_DROP_UNSYNCED_DATA, RESET_DELETE_UNSYNCED_FILES };370FaultInjectionTestEnv* env_;371std::string dbname_;372Cache* tiny_cache_;373Options options_;374DB* db_;376FaultInjectionTest()377: env_(new FaultInjectionTestEnv),378tiny_cache_(NewLRUCache(100)),379db_(nullptr) {380dbname_ = test::TmpDir() + "/fault_test";381DestroyDB(dbname_, Options()); // Destroy any db from earlier run382options_.reuse_logs = true;383options_.env = env_;384options_.paranoid_checks = true;385options_.block_cache = tiny_cache_;386options_.create_if_missing = true;387}389~FaultInjectionTest() {390CloseDB();391DestroyDB(dbname_, Options());392delete tiny_cache_;393delete env_;394}396void ReuseLogs(bool reuse) { options_.reuse_logs = reuse; }398void Build(int start_idx, int num_vals) {399std::string key_space, value_space;400WriteBatch batch;401for (int i = start_idx; i < start_idx + num_vals; i++) {402Slice key = Key(i, &key_space);403batch.Clear();404batch.Put(key, Value(i, &value_space));405WriteOptions options;406ASSERT_OK(db_->Write(options, &batch));407}408}410Status ReadValue(int i, std::string* val) const {411std::string key_space, value_space;412Slice key = Key(i, &key_space);413Value(i, &value_space);414ReadOptions options;415return db_->Get(options, key, val);416}418Status Verify(int start_idx, int num_vals,419ExpectedVerifResult expected) const {420std::string val;421std::string value_space;422Status s;423for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) {424Value(i, &value_space);425s = ReadValue(i, &val);426if (expected == VAL_EXPECT_NO_ERROR) {427if (s.ok()) {428ASSERT_EQ(value_space, val);429}430} else if (s.ok()) {431fprintf(stderr, "Expected an error at %d, but was OK\n", i);432s = Status::IOError(dbname_, "Expected value error:");433} else {434s = Status::OK(); // An expected error435}436}437return s;438}440// Return the ith key441Slice Key(int i, std::string* storage) const {442char buf[100];443snprintf(buf, sizeof(buf), "%016d", i);444storage->assign(buf, strlen(buf));445return Slice(*storage);446}448// Return the value to associate with the specified key449Slice Value(int k, std::string* storage) const {450Random r(k);451return test::RandomString(&r, kValueSize, storage);452}454Status OpenDB() {455delete db_;456db_ = nullptr;457env_->ResetState();458return DB::Open(options_, dbname_, &db_);459}461void CloseDB() {462delete db_;463db_ = nullptr;464}466void DeleteAllData() {467Iterator* iter = db_->NewIterator(ReadOptions());468for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {469ASSERT_OK(db_->Delete(WriteOptions(), iter->key()));470}472delete iter;473}475void ResetDBState(ResetMethod reset_method) {476switch (reset_method) {477case RESET_DROP_UNSYNCED_DATA:478ASSERT_OK(env_->DropUnsyncedFileData());479break;480case RESET_DELETE_UNSYNCED_FILES:481ASSERT_OK(env_->DeleteFilesCreatedAfterLastDirSync());482break;483default:484assert(false);485}486}488void PartialCompactTestPreFault(int num_pre_sync, int num_post_sync) {489DeleteAllData();490Build(0, num_pre_sync);491db_->CompactRange(nullptr, nullptr);492Build(num_pre_sync, num_post_sync);493}495void PartialCompactTestReopenWithFault(ResetMethod reset_method,496int num_pre_sync, int num_post_sync) {497env_->SetFilesystemActive(false);498CloseDB();499ResetDBState(reset_method);500ASSERT_OK(OpenDB());
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.