-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add CoW buffer for spring2024 p1 (#690)
* Prepare Spring 24 P1 * fix typo * add default impl for page guard constructor * format * new line at eof --------- Co-authored-by: xx01cyx <[email protected]>
- Loading branch information
Showing
6 changed files
with
174 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// BusTub | ||
// | ||
// cow_buffer.h | ||
// | ||
// Identification: src/include/storage/disk/cow_buffer.h | ||
// | ||
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#pragma once | ||
|
||
#include <cstdint> | ||
#include <cstring> | ||
#include "common/config.h" | ||
#include "common/macros.h" | ||
#include "storage/page/page.h" | ||
|
||
namespace bustub { | ||
|
||
/** | ||
* CoWBuffer provides extra memory space other than the buffer pool to store the copy-on-write 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 buffer 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 CoWBuffer { | ||
public: | ||
CoWBuffer() : cow_pages_{new Page[8]} {} | ||
~CoWBuffer() { delete[] cow_pages_; } | ||
DISALLOW_COPY_AND_MOVE(CoWBuffer); | ||
|
||
/** | ||
* @brief Adds a new page to the CoW buffer. | ||
* @param page the page pointer from the bpm that is about to be evicted. | ||
* @return pointer to the copied page in the buffer, or nullptr if the buffer is full. | ||
*/ | ||
auto Add(Page *page) -> Page * { | ||
if ((page == nullptr) || IsFull()) { | ||
return nullptr; | ||
} | ||
|
||
uint32_t slot = FindFreeSlot(); | ||
memcpy(cow_pages_[slot].GetData(), page->GetData(), BUSTUB_PAGE_SIZE); | ||
MarkSlotUsed(slot); | ||
|
||
return cow_pages_ + slot; | ||
} | ||
|
||
/** | ||
* @brief Removes a page from the CoW buffer. | ||
* @param page the pointer previously returned by Add. | ||
*/ | ||
auto Remove(Page *page) -> void { | ||
if (page != nullptr) { | ||
MarkSlotFree(page - cow_pages_); | ||
} | ||
} | ||
|
||
private: | ||
/** @brief Whether the buffer is full. */ | ||
auto IsFull() -> bool { return free_slot_bitmap_ == 0xFFU; } | ||
|
||
/** @brief Finds a free slot in the buffer, if not full. */ | ||
auto FindFreeSlot() -> uint32_t { | ||
BUSTUB_ASSERT(!IsFull(), "no free slot in cow buffer"); | ||
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 CoW buffer pages. */ | ||
Page *cow_pages_; | ||
/** The bitmap that records which slots are free. */ | ||
uint8_t free_slot_bitmap_{0}; | ||
}; | ||
|
||
} // namespace bustub |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// BusTub | ||
// | ||
// page_guard_test.cpp | ||
// | ||
// Identification: test/storage/page_guard_test.cpp | ||
// | ||
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "storage/disk/cow_buffer.h" | ||
#include "gtest/gtest.h" | ||
|
||
namespace bustub { | ||
|
||
// NOLINTNEXTLINE | ||
TEST(CoWBufferTest, ScheduleWriteReadPageTest) { | ||
CoWBuffer cow{}; | ||
std::vector<Page *> cow_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 *cow_page{cow.Add(&bpm_page)}; | ||
EXPECT_NE(cow_page, nullptr); | ||
EXPECT_NE(cow_page, &bpm_page); | ||
cow_pages.push_back(cow_page); | ||
EXPECT_EQ(std::memcmp(cow_page->GetData(), bpm_page.GetData(), BUSTUB_PAGE_SIZE), 0); | ||
} | ||
|
||
Page extra_page{}; | ||
Page *cow_extra_page{cow.Add(&extra_page)}; | ||
EXPECT_EQ(cow_extra_page, nullptr); | ||
|
||
for (size_t i{0}; i < 8; i++) { | ||
auto check{"Meuh!: " + std::to_string(i) + " 🐄🐄🐄🐄"}; | ||
EXPECT_EQ(std::memcmp(cow_pages[i]->GetData(), check.data(), check.size()), 0); | ||
} | ||
|
||
cow.Remove(cow_pages[5]); | ||
Page replace_page{}; | ||
cow_pages[5] = cow.Add(&replace_page); | ||
EXPECT_NE(cow_pages[5], nullptr); | ||
|
||
for (size_t i{0}; i < 8; i++) { | ||
cow.Remove(cow_pages[i]); // Shouldn't crash. | ||
} | ||
|
||
cow.Remove(nullptr); // Shouldn't crash. | ||
} | ||
|
||
} // namespace bustub |