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 wiscdb { 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 00215 PageIterator end(); 00216 00217 private: 00221 void initialize(); 00222 00228 void set_page_number(const PageId new_page_number) { 00229 header_.current_page_number = new_page_number; 00230 } 00231 00237 void set_next_page_number(const PageId new_next_page_number) { 00238 header_.next_page_number = new_next_page_number; 00239 } 00240 00251 void deleteRecord(const RecordId& record_id, 00252 const bool allow_slot_compaction); 00253 00262 PageSlot* getSlot(const SlotId slot_number); 00263 00272 const PageSlot& getSlot(const SlotId slot_number) const; 00273 00288 SlotId getAvailableSlot(); 00289 00303 void insertRecordInSlot(const SlotId slot_number, 00304 const std::string& record_data); 00305 00314 void validateRecordId(const RecordId& record_id) const; 00315 00321 bool isUsed() const { return page_number() != INVALID_NUMBER; } 00322 00326 PageHeader header_; 00327 00333 std::string data_; 00334 00335 friend class File; 00336 friend class PageIterator; 00337 friend class PageTest; 00338 friend class BufferTest; 00339 }; 00340 00341 static_assert(Page::SIZE > sizeof(PageHeader), 00342 "Page size must be large enough to hold header and data."); 00343 static_assert(Page::DATA_SIZE > 0, 00344 "Page must have some space to hold data."); 00345 00346 }