BadgerDB
|
00001 00008 #pragma once 00009 00010 #include <cstddef> 00011 #include <stdint.h> 00012 #include <memory> 00013 #include <string> 00014 00015 #include "types.h" 00016 00017 namespace badgerdb { 00018 00025 struct PageHeader { 00030 std::uint16_t free_space_lower_bound; 00031 00036 std::uint16_t free_space_upper_bound; 00037 00043 SlotId num_slots; 00044 00048 SlotId num_free_slots; 00049 00053 PageId current_page_number; 00054 00058 PageId next_page_number; 00059 00066 bool operator==(const PageHeader& rhs) const { 00067 return num_slots == rhs.num_slots && 00068 num_free_slots == rhs.num_free_slots && 00069 current_page_number == rhs.current_page_number && 00070 next_page_number == rhs.next_page_number; 00071 } 00072 }; 00073 00077 struct PageSlot { 00082 bool used; 00083 00087 std::uint16_t item_offset; 00088 00092 std::uint16_t item_length; 00093 }; 00094 00095 class PageIterator; 00096 00107 class Page { 00108 public: 00113 static const std::size_t SIZE = 8192; 00114 00118 static const std::size_t DATA_SIZE = SIZE - sizeof(PageHeader); 00119 00123 static const PageId INVALID_NUMBER = 0; 00124 00128 static const SlotId INVALID_SLOT = 0; 00129 00133 Page(); 00134 00141 RecordId insertRecord(const std::string& record_data); 00142 00151 std::string getRecord(const RecordId& record_id) const; 00152 00161 void updateRecord(const RecordId& record_id, const std::string& record_data); 00162 00170 void deleteRecord(const RecordId& record_id); 00171 00178 bool hasSpaceForRecord(const std::string& record_data) const; 00179 00185 std::uint16_t getFreeSpace() const { return header_.free_space_upper_bound - 00186 header_.free_space_lower_bound; } 00187 00193 PageId page_number() const { return header_.current_page_number; } 00194 00200 PageId next_page_number() const { return header_.next_page_number; } 00201 00207 PageIterator begin(); 00208 00214 PageIterator beginAt(SlotId slot); 00215 00222 PageIterator end(); 00223 00224 private: 00228 void initialize(); 00229 00235 void set_page_number(const PageId new_page_number) { 00236 header_.current_page_number = new_page_number; 00237 } 00238 00244 void set_next_page_number(const PageId new_next_page_number) { 00245 header_.next_page_number = new_next_page_number; 00246 } 00247 00258 void deleteRecord(const RecordId& record_id, 00259 const bool allow_slot_compaction); 00260 00269 PageSlot* getSlot(const SlotId slot_number); 00270 00279 const PageSlot& getSlot(const SlotId slot_number) const; 00280 00295 SlotId getAvailableSlot(); 00296 00310 void insertRecordInSlot(const SlotId slot_number, 00311 const std::string& record_data); 00312 00321 void validateRecordId(const RecordId& record_id) const; 00322 00328 bool isUsed() const { return page_number() != INVALID_NUMBER; } 00329 00333 PageHeader header_; 00334 00340 char data_[DATA_SIZE]; 00341 00342 friend class File; 00343 friend class PageFile; 00344 friend class BlobFile; 00345 friend class PageIterator; 00346 }; 00347 00348 static_assert(Page::SIZE > sizeof(PageHeader), 00349 "Page size must be large enough to hold header and data."); 00350 static_assert(Page::DATA_SIZE > 0, 00351 "Page must have some space to hold data."); 00352 00353 }