From f7704aeca5963d9b54c20dfec4b6d1f00c7fa744 Mon Sep 17 00:00:00 2001 From: artpaul Date: Thu, 19 Sep 2024 18:29:56 +0500 Subject: [PATCH] ignore partially written record at the end --- include/bitcask/bitcask.h | 10 +++++++++- src/bitcask.cc | 26 +++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/include/bitcask/bitcask.h b/include/bitcask/bitcask.h index 899fbdb..b1113ae 100644 --- a/include/bitcask/bitcask.h +++ b/include/bitcask/bitcask.h @@ -117,6 +117,8 @@ class Database { std::mutex fd_mutex; /// File descriptor. int fd{-1}; + /// The file may have partially written record at the end. + const bool may_have_uncommitted; /// Total size of the file. /// The size is only updated on writing or set on loading. @@ -131,7 +133,8 @@ class Database { std::atomic_uint64_t tombstones{0}; public: - FileInfo(std::filesystem::path p, uint64_t s) noexcept : path(std::move(p)), size(s) {} + FileInfo(std::filesystem::path p, uint64_t s, bool uncommitted) noexcept + : path(std::move(p)), may_have_uncommitted(uncommitted), size(s) {} #ifndef NDEBUG ~FileInfo() { @@ -251,6 +254,11 @@ class Database { std::error_code EnumerateIndex(const std::shared_ptr& file, const FileSections::Range& range, const std::function& cb) const; + /** + * Enumerates all entries in a file. + * + * @param file a file to enumerate. + */ std::error_code EnumerateEntries(const std::shared_ptr& file, const FileSections::Range& range, const std::function& cb) const; diff --git a/src/bitcask.cc b/src/bitcask.cc index 36a42f5..ffd6b72 100644 --- a/src/bitcask.cc +++ b/src/bitcask.cc @@ -61,7 +61,15 @@ std::error_code LoadFromFile(int fd, void* buf, size_t len, size_t& off) noexcep return {}; } -/// Reads full content of an entry. +/** + * Reads full content of an entry. + * + * @param fd + * @param offset beginning of the entry. + * @param check_crc check consistency of read data. + * + * @returns bytes read or an error code. + */ std::pair ReadEntryImpl(const int fd, const size_t offset, const bool check_crc, format::Entry& entry, std::string& key, std::string& value) { size_t current_offset = offset; @@ -633,7 +641,7 @@ std::error_code Database::Initialize() { continue; } - auto file = std::make_shared(entry.path(), entry.file_size()); + auto file = std::make_shared(entry.path(), entry.file_size(), index.value() == 0); // Open file for reading. if (auto ec = file->EnsureReadable()) { return ec; @@ -644,6 +652,12 @@ std::error_code Database::Initialize() { if (IsNotFound(ec)) { continue; } + // A former active file may have a partially written record at the end in case of unexpected shutdown. + // Ignore it. + if (IsUnexpectedEndOfFile(ec) && file->may_have_uncommitted) { + continue; + } + return ec; } @@ -761,6 +775,12 @@ std::error_code Database::PackFiles( } // Enumerate all records in the source file. if (auto ec = EnumerateEntriesNoLock(file, cb)) { + // A former active file may have a partially written record at the end in case of unexpected shutdown. + // Ignore it. + if (IsUnexpectedEndOfFile(ec) && file->may_have_uncommitted) { + continue; + } + read_lock.unlock(); // TODO: finalize. return ec; @@ -978,7 +998,7 @@ Database::FileInfoStatus Database::MakeWritableFile(const std::string& name, boo return {{}, std::make_error_code(static_cast(err))}; } } - auto file = std::make_shared(std::move(path), sizeof(format::Header)); + auto file = std::make_shared(std::move(path), sizeof(format::Header), name.starts_with("0-")); file->fd = fd; return {file, {}}; }