BadgerDB
|
00001 00008 #pragma once 00009 00010 #include <cstddef> 00011 #include <stdint.h> 00012 #include <memory> 00013 #include <string> 00014 00015 //#include <gtest/gtest.h> 00016 #include "types.h" 00017 00018 namespace badgerdb { 00019 00026 struct PageHeader { 00031 std::uint16_t free_space_lower_bound; 00032 00037 std::uint16_t free_space_upper_bound; 00038 00044 SlotId num_slots; 00045 00049 SlotId num_free_slots; 00050 00054 PageId current_page_number; 00055 00059 PageId next_page_number; 00060 00067 bool operator==(const PageHeader& rhs) const { 00068 return num_slots == rhs.num_slots && 00069 num_free_slots == rhs.num_free_slots && 00070 current_page_number == rhs.current_page_number && 00071 next_page_number == rhs.next_page_number; 00072 } 00073 }; 00074 00078 struct PageSlot { 00083 bool used; 00084 00088 std::uint16_t item_offset; 00089 00093 std::uint16_t item_length; 00094 }; 00095 00096 class PageIterator; 00097 00108 class Page { 00109 public: 00114 static const std::size_t SIZE = 8192; 00115 00119 static const std::size_t DATA_SIZE = SIZE - sizeof(PageHeader); 00120 00124 static const PageId INVALID_NUMBER = 0; 00125 00129 static const SlotId INVALID_SLOT = 0; 00130 00134 Page(); 00135 00142 RecordId insertRecord(const std::string& record_data); 00143 00152 std::string getRecord(const RecordId& record_id) const; 00153 00162 void updateRecord(const RecordId& record_id, const std::string& record_data); 00163 00171 void deleteRecord(const RecordId& record_id); 00172 00179 bool hasSpaceForRecord(const std::string& record_data) const; 00180 00186 std::uint16_t getFreeSpace() const { return header_.free_space_upper_bound - 00187 header_.free_space_lower_bound; } 00188 00194 PageId page_number() const { return header_.current_page_number; } 00195 00201 PageId next_page_number() const { return header_.next_page_number; } 00202 00208 PageIterator begin(); 00209 00216 PageIterator end(); 00217 00218 private: 00222 void initialize(); 00223 00229 void set_page_number(const PageId new_page_number) { 00230 header_.current_page_number = new_page_number; 00231 } 00232 00238 void set_next_page_number(const PageId new_next_page_number) { 00239 header_.next_page_number = new_next_page_number; 00240 } 00241 00252 void deleteRecord(const RecordId& record_id, 00253 const bool allow_slot_compaction); 00254 00263 PageSlot* getSlot(const SlotId slot_number); 00264 00273 const PageSlot& getSlot(const SlotId slot_number) const; 00274 00289 SlotId getAvailableSlot(); 00290 00304 void insertRecordInSlot(const SlotId slot_number, 00305 const std::string& record_data); 00306 00315 void validateRecordId(const RecordId& record_id) const; 00316 00322 bool isUsed() const { return page_number() != INVALID_NUMBER; } 00323 00327 PageHeader header_; 00328 00334 char data_[DATA_SIZE]; 00335 00336 friend class File; 00337 friend class PageFile; 00338 friend class BlobFile; 00339 friend class PageIterator; 00340 }; 00341 00342 static_assert(Page::SIZE > sizeof(PageHeader), 00343 "Page size must be large enough to hold header and data."); 00344 static_assert(Page::DATA_SIZE > 0, 00345 "Page must have some space to hold data."); 00346 00347 }