diff --git a/src/include/buffer/buffer_pool_manager.h b/src/include/buffer/buffer_pool_manager.h index aa29e04eb..b7449a3ff 100644 --- a/src/include/buffer/buffer_pool_manager.h +++ b/src/include/buffer/buffer_pool_manager.h @@ -22,7 +22,6 @@ #include "common/config.h" #include "recovery/log_manager.h" #include "storage/disk/disk_scheduler.h" -#include "storage/disk/write_back_cache.h" #include "storage/page/page.h" #include "storage/page/page_guard.h" @@ -155,13 +154,6 @@ class BufferPoolManager { /** @brief A pointer to the disk scheduler. */ std::unique_ptr disk_scheduler_; - /** - * @brief A write-back cache. - * - * Note: You may want to use this cache to optimize the write requests for the leaderboard task. - */ - WriteBackCache write_back_cache_ __attribute__((__unused__)); - /** * @brief A pointer to the log manager. * diff --git a/src/include/storage/disk/disk_manager_memory.h b/src/include/storage/disk/disk_manager_memory.h index 4d86d6a55..ff67f4f2e 100644 --- a/src/include/storage/disk/disk_manager_memory.h +++ b/src/include/storage/disk/disk_manager_memory.h @@ -9,7 +9,11 @@ // Copyright (c) 2015-2020, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// + +#include "storage/disk/disk_manager.h" + #include +#include #include // NOLINT #include #include @@ -27,10 +31,12 @@ #include "common/exception.h" #include "common/logger.h" #include "fmt/core.h" -#include "storage/disk/disk_manager.h" namespace bustub { +/** @brief The default size of the database file. */ +static const size_t DEFAULT_DB_IO_SIZE = 16; + /** * DiskManagerMemory replicates the utility of DiskManager on memory. It is primarily used for * data structure performance testing. @@ -72,12 +78,31 @@ class DiskManagerMemory : public DiskManager { */ class DiskManagerUnlimitedMemory : public DiskManager { public: - DiskManagerUnlimitedMemory() { std::fill(recent_access_.begin(), recent_access_.end(), -1); } + DiskManagerUnlimitedMemory() { + std::scoped_lock l(mutex_); + while (data_.size() < pages_ + 1) { + data_.push_back(std::make_shared()); + } + std::fill(recent_access_.begin(), recent_access_.end(), -1); + } /** * This function should increase the disk space, but since this is memory we just resize the vector. */ - void IncreaseDiskSpace(size_t pages) override { data_.resize(pages + 1, std::make_shared()); } + void IncreaseDiskSpace(size_t pages) override { + std::scoped_lock l(mutex_); + + if (pages < pages_) { + return; + } + + while (data_.size() < pages + 1) { + data_.push_back(std::make_shared()); + } + assert(data_.size() == pages + 1); + + pages_ = pages; + } /** * Write a page to the database file. @@ -124,7 +149,7 @@ class DiskManagerUnlimitedMemory : public DiskManager { return; } if (data_[page_id] == nullptr) { - fmt::println(stderr, "page {} not exist", page_id); + fmt::println(stderr, "page {} not exist", page_id, pages_); std::terminate(); return; } @@ -186,6 +211,8 @@ class DiskManagerUnlimitedMemory : public DiskManager { std::mutex mutex_; std::optional thread_id_; std::vector> data_; + + size_t pages_{DEFAULT_DB_IO_SIZE}; }; } // namespace bustub diff --git a/src/include/storage/disk/write_back_cache.h b/src/include/storage/disk/write_back_cache.h deleted file mode 100644 index 1a09b59ab..000000000 --- a/src/include/storage/disk/write_back_cache.h +++ /dev/null @@ -1,97 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// BusTub -// -// write_back_cache.h -// -// Identification: src/include/storage/disk/write_back_cache.h -// -// Copyright (c) 2015-2024, Carnegie Mellon University Database Group -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include -#include -#include "common/config.h" -#include "common/macros.h" -#include "storage/page/page.h" - -namespace bustub { - -/** - * WriteBackCache provides extra memory space other than the buffer pool to store the pages. It's purpose - * is to gather the copy of pages that are about to be written back to disk, so that the bpm doesn't have - * to incur IO penality and wait for the write to be completed when evicting. - * Spring 24: The cache is limited to store a constant number of pages in total (8). - * !! ANY ATTEMPTS TO ADD ANOTHER IN-MEMORY CACHE WILL BE REVIEWED MANUALLY AS PER LEADERBOARD POLICY !! - */ -class WriteBackCache { - public: - WriteBackCache() : write_back_pages_{new Page[8]} {} - ~WriteBackCache() { delete[] write_back_pages_; } - DISALLOW_COPY_AND_MOVE(WriteBackCache); - - /** - * @brief Adds a new page to the write back cache. - * @param page the page pointer from the bpm that is about to be evicted. - * @return pointer to the copied page in the cache, or nullptr if the cache is full. - */ - auto Add(Page *page) -> Page * { - if ((page == nullptr) || IsFull()) { - return nullptr; - } - - uint32_t slot = FindFreeSlot(); - memcpy(write_back_pages_[slot].GetData(), page->GetData(), BUSTUB_PAGE_SIZE); - MarkSlotUsed(slot); - - return write_back_pages_ + slot; - } - - /** - * @brief Removes a page from the write back cache. - * @param page the pointer previously returned by Add. - */ - auto Remove(Page *page) -> void { - if (page != nullptr) { - MarkSlotFree(page - write_back_pages_); - } - } - - private: - /** @brief Whether the cache is full. */ - auto IsFull() -> bool { return free_slot_bitmap_ == 0xFFU; } - - /** @brief Finds a free slot in the cache, if not full. */ - auto FindFreeSlot() -> uint32_t { - BUSTUB_ASSERT(!IsFull(), "no free slot in write back cache"); - uint32_t i = 0; - uint8_t bitmap = free_slot_bitmap_; - while ((bitmap & 1U) != 0) { - bitmap >>= 1; - i++; - } - return i; - } - - /** @brief Marks a free slot as used. */ - void MarkSlotUsed(uint32_t slot) { - BUSTUB_ASSERT(((free_slot_bitmap_ >> slot) & 1U) == 0, "slot has already been used"); - free_slot_bitmap_ |= (1U << slot); - } - - /** @brief Marks a used slot as free. */ - void MarkSlotFree(uint32_t slot) { - BUSTUB_ASSERT(((free_slot_bitmap_ >> slot) & 1U) == 1, "slot is already free"); - free_slot_bitmap_ &= ~(1U << slot); - } - - /** The array of write back cache pages. */ - Page *write_back_pages_; - /** The bitmap that records which slots are free. */ - uint8_t free_slot_bitmap_{0}; -}; - -} // namespace bustub diff --git a/src/storage/disk/disk_manager.cpp b/src/storage/disk/disk_manager.cpp index de18df9a5..0fb3e1cfb 100644 --- a/src/storage/disk/disk_manager.cpp +++ b/src/storage/disk/disk_manager.cpp @@ -33,7 +33,8 @@ static const size_t DEFAULT_DB_IO_SIZE = 16; * Constructor: open/create a single database file & log file * @input db_file: database file name */ -DiskManager::DiskManager(const std::filesystem::path &db_file) : file_name_(db_file) { +DiskManager::DiskManager(const std::filesystem::path &db_file) + : file_name_(db_file), pages_(0), page_capacity_(DEFAULT_DB_IO_SIZE) { log_name_ = file_name_.filename().stem().string() + ".log"; log_io_.open(log_name_, std::ios::binary | std::ios::in | std::ios::app | std::ios::out); @@ -60,9 +61,6 @@ DiskManager::DiskManager(const std::filesystem::path &db_file) : file_name_(db_f } // Initialize the database file. - pages_ = 0; - page_capacity_ = DEFAULT_DB_IO_SIZE; - std::filesystem::resize_file(db_file, (page_capacity_ + 1) * BUSTUB_PAGE_SIZE); assert(static_cast(GetFileSize(file_name_)) >= page_capacity_ * BUSTUB_PAGE_SIZE); @@ -84,12 +82,12 @@ void DiskManager::ShutDown() { * @brief Increases the size of the file to fit the specified number of pages. */ void DiskManager::IncreaseDiskSpace(size_t pages) { + std::scoped_lock scoped_db_io_latch(db_io_latch_); + if (pages < pages_) { return; } - std::scoped_lock scoped_db_io_latch(db_io_latch_); - pages_ = pages; while (page_capacity_ < pages_) { page_capacity_ *= 2; diff --git a/test/storage/write_back_cache_test.cpp b/test/storage/write_back_cache_test.cpp deleted file mode 100644 index c2463854c..000000000 --- a/test/storage/write_back_cache_test.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// BusTub -// -// write_back_cache_test.cpp -// -// Identification: test/storage/write_back_cache_test.cpp -// -// Copyright (c) 2015-2024, Carnegie Mellon University Database Group -// -//===----------------------------------------------------------------------===// - -#include "storage/disk/write_back_cache.h" -#include "gtest/gtest.h" - -namespace bustub { - -// NOLINTNEXTLINE -TEST(WriteBackCacheTest, ScheduleWriteReadPageTest) { - WriteBackCache wbc{}; - std::vector wbc_pages{}; - for (size_t i{0}; i < 8; i++) { - Page bpm_page{}; - auto content{"Meuh!: " + std::to_string(i) + " 🐄🐄🐄🐄"}; - std::strncpy(bpm_page.GetData(), content.data(), BUSTUB_PAGE_SIZE); - - Page *wbc_page{wbc.Add(&bpm_page)}; - EXPECT_NE(wbc_page, nullptr); - EXPECT_NE(wbc_page, &bpm_page); - wbc_pages.push_back(wbc_page); - EXPECT_EQ(std::memcmp(wbc_page->GetData(), bpm_page.GetData(), BUSTUB_PAGE_SIZE), 0); - } - - Page extra_page{}; - Page *wbc_extra_page{wbc.Add(&extra_page)}; - EXPECT_EQ(wbc_extra_page, nullptr); - - for (size_t i{0}; i < 8; i++) { - auto check{"Meuh!: " + std::to_string(i) + " 🐄🐄🐄🐄"}; - EXPECT_EQ(std::memcmp(wbc_pages[i]->GetData(), check.data(), check.size()), 0); - } - - wbc.Remove(wbc_pages[5]); - Page replace_page{}; - wbc_pages[5] = wbc.Add(&replace_page); - EXPECT_NE(wbc_pages[5], nullptr); - - for (size_t i{0}; i < 8; i++) { - wbc.Remove(wbc_pages[i]); // Shouldn't crash. - } - - wbc.Remove(nullptr); // Shouldn't crash. -} - -} // namespace bustub