Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CS4420 EC] Added toy slotted pages implementation #31

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/include/utils/slotted_page.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include <vector>
#include <cstdint>

namespace buzzdb {

struct SlottedPage {
struct Header {
Header(uint32_t page_size);

uint16_t slot_count;
uint16_t next_free_slot;
uint32_t page_size;
};

struct Slot {
Slot() = default;

uint32_t stored_value;
};

SlottedPage(uint32_t page_size);

uint16_t addSlot(uint32_t stored_value);

// Completely remove a slot at a particular index.
uint16_t removeSlot(int index);

// Removes the first instance of a value found in a slot without removing the
// slot completely.
uint16_t removeSlot(uint32_t value_to_remove);

Header slot_header;
std::vector<std::byte> data;
std::vector<Slot> slots;
};

struct SlotReference {
SlotReference(uint64_t page, uint16_t slot);

// 48 bytes page id and 16 bytes for slot id = 64 byte slot id value
uint64_t slot_id_value;
};

}
74 changes: 74 additions & 0 deletions src/slotted_page.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include "utils/slotted_page.h"
#include <cstdint>

using SlottedPage = buzzdb::SlottedPage;
using SlotReference = buzzdb::SlotReference;

SlotReference::SlotReference(uint64_t page, uint16_t slot) {
this -> slot_id_value = (page << 16) | slot;
}

SlottedPage::Header::Header(uint32_t page_size) {
this -> slot_count = 0;
// Header data takes up around 4 bytes of space.
this -> next_free_slot = page_size - 4;
this -> page_size = page_size;
}

SlottedPage::SlottedPage(uint32_t page_size) : slot_header(page_size) {
this -> data.resize(page_size - 4);
}

uint16_t SlottedPage::addSlot(uint32_t stored_value) {
// Case where we have a free slot somewhere and therefore it would be
// wasteful to add a new slot.
if (this -> slot_header.next_free_slot != this -> slot_header.page_size - 4) {
this -> slots[this -> slot_header.next_free_slot].stored_value = stored_value;
uint16_t old_free_slot = this -> slot_header.next_free_slot;
int index = 0;

for (auto slot : slots) {
if (slot.stored_value == (uint32_t) -1) {
this -> slot_header.next_free_slot = index;
break;
}
index++;
}

if (this -> slot_header.next_free_slot == old_free_slot) {
this -> slot_header.next_free_slot = -1;
}

return old_free_slot;
} else {
Slot new_slot;
new_slot.stored_value = stored_value;
this -> slot_header.slot_count++;
this -> slots.push_back(new_slot);
return this -> slot_header.slot_count;
}
}

uint16_t SlottedPage::removeSlot(int index) {
this -> slots.erase(this -> slots.begin() + index);
this -> slot_header.slot_count--;
return this -> slot_header.slot_count;
}

uint16_t SlottedPage::removeSlot(uint32_t value_to_remove) {
int index = 0;

for (auto slot : this -> slots) {
if (slot.stored_value == value_to_remove) {
this -> slots[index].stored_value = -1;
if (this -> slot_header.next_free_slot == (uint16_t) -1 ||
(this -> slot_header.next_free_slot != (uint16_t) -1 && index < this -> slot_header.next_free_slot)) {
this -> slot_header.next_free_slot = index;
}
break;
}
index++;
}

return index;
}
95 changes: 95 additions & 0 deletions test/unit/utils/slotted_page_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include <gtest/gtest.h>

#include "utils/slotted_page.h"

using SlottedPage = buzzdb::SlottedPage;

namespace {

TEST(SlottedPageTest, AddSlot) {
SlottedPage new_page(32);
new_page.addSlot(45);
new_page.addSlot(69);
new_page.addSlot(67);

EXPECT_EQ(45, new_page.slots[0].stored_value);
EXPECT_EQ(69, new_page.slots[1].stored_value);
EXPECT_EQ(67, new_page.slots[2].stored_value);
}

TEST(SlottedPageTest, RemoveWholeSlotBasic) {
int removeIndex = 1;
SlottedPage new_page(32);
new_page.addSlot(45);
new_page.addSlot(69);
new_page.addSlot(67);
new_page.removeSlot(removeIndex);

EXPECT_EQ(45, new_page.slots[0].stored_value);
EXPECT_EQ(67, new_page.slots[1].stored_value);
}

TEST(SlottedPageTest, RemoveValueBasic) {
uint32_t removeValue = 67;
SlottedPage new_page(32);
new_page.addSlot(45);
new_page.addSlot(69);
new_page.addSlot(67);
new_page.removeSlot(removeValue);

EXPECT_EQ(45, new_page.slots[0].stored_value);
EXPECT_EQ(69, new_page.slots[1].stored_value);
EXPECT_EQ(-1, new_page.slots[2].stored_value);
EXPECT_EQ(2, new_page.slot_header.next_free_slot);
}

TEST(SlottedPageTest, RemoveValueThenAddNoFreeSlots) {
uint32_t removeValue = 67;
SlottedPage new_page(32);
new_page.addSlot(45);
new_page.addSlot(69);
new_page.addSlot(67);
new_page.removeSlot(removeValue);

EXPECT_EQ(45, new_page.slots[0].stored_value);
EXPECT_EQ(69, new_page.slots[1].stored_value);
EXPECT_EQ(-1, new_page.slots[2].stored_value);
EXPECT_EQ(2, new_page.slot_header.next_free_slot);

new_page.addSlot(42);

EXPECT_EQ(45, new_page.slots[0].stored_value);
EXPECT_EQ(69, new_page.slots[1].stored_value);
EXPECT_EQ(42, new_page.slots[2].stored_value);
EXPECT_EQ((uint16_t) -1, new_page.slot_header.next_free_slot);
}

TEST(SlottedPageTest, RemoveValueThenAddWithFreeSlot) {
uint32_t removeValue1 = 67;
uint32_t removeValue2 = 69;
SlottedPage new_page(32);
new_page.addSlot(45);
new_page.addSlot(69);
new_page.addSlot(67);
new_page.removeSlot(removeValue1);
new_page.removeSlot(removeValue2);

EXPECT_EQ(45, new_page.slots[0].stored_value);
EXPECT_EQ(-1, new_page.slots[1].stored_value);
EXPECT_EQ(-1, new_page.slots[2].stored_value);
EXPECT_EQ(1, new_page.slot_header.next_free_slot);

new_page.addSlot(42);

EXPECT_EQ(45, new_page.slots[0].stored_value);
EXPECT_EQ(42, new_page.slots[1].stored_value);
EXPECT_EQ(-1, new_page.slots[2].stored_value);
EXPECT_EQ(2, new_page.slot_header.next_free_slot);
}

}

int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}