def read_page(self, range_type: str, page_index: int, column: int) -> Page: file, size = self.__open_file(column, range_type) # checks if the file needs to be enlarged if page_index >= size // PAGESIZE: file.seek(0, SEEK_END) new_page = Page(range_type=range_type) # doubles the size of the file new_bytes = new_page.data * (page_index + 1) file.write(new_bytes) # reads specified page file.seek(page_index * PAGESIZE) return Page(data=file.read(PAGESIZE))
def load_page_from_disk(self, table_name, address): if (self.bufferpool.is_full()): # evict page and flush it to disk if dirty evict_page = self.bufferpool.evict() while (len(evict_page) == 0): evict_page = self.bufferpool.evict() if (evict_page[1].dirty): self.flush_page(evict_page) # then locate page from disk and copy, save in Page() object, then add to buffer pool if table_name not in self.active_table_indexes: self.load_index_from_disk( table_name) # load the table's index from file into memory table_index = self.active_table_indexes[table_name] file_offset = table_index[(address.pagerange, address.page)][FILE_OFFSET] num_records = table_index[(address.pagerange, address.page)][NUM_RECORDS] filename = self.directory_path + table_name + BIN_EXTENSION # file for table data with open(filename, "rb") as file: file.seek(file_offset) page_bytes = file.read(PAGESIZE) page_copy = Page(page_bytes, num_records) #page_copy = Page(page_bytes) self.bufferpool.add_page(table_name, address, page_copy)
def create_empty_pages_bp(self, num_cols, start_range, page_flag): list_page_ids = [] for i in range(num_cols): if self.bp.size == self.bp_capacity: self.evict_page() if page_flag == BASE_FLAG: self.bp.appendleft(Page(init.CURR_BASE_PAGE_ID)) list_page_ids.append(init.CURR_BASE_PAGE_ID) init.CURR_BASE_PAGE_ID += 1 else: self.bp.appendleft(Page(init.CURR_TAIL_PAGE_ID)) list_page_ids.append(init.CURR_TAIL_PAGE_ID) init.CURR_TAIL_PAGE_ID -= 1 if page_flag == BASE_FLAG: self.page_directory[start_range][0][NUM_BASE] += 1 else: self.page_directory[start_range][0][NUM_TAIL] += 1 self.page_directory[start_range].append(list_page_ids)
def _convert_bytes_to_page(cls, columns, metadata_bytes, data_bytes): lst_page = [] for i in range(columns): if i < METADATA_COLUMN_COUNT: bytes_of_page = cls._bytes_of_pages(i, metadata_bytes) else: bytes_of_page = cls._bytes_of_pages(i - METADATA_COLUMN_COUNT, data_bytes) page = Page.new_page_from_bytes(bytes_of_page) lst_page.append(page) return lst_page
def new_page(self, table_name, address, column_index): lstore.globals.access.acquire() filename = self.directory_path + table_name + BIN_EXTENSION # file for table data orig_filesize = os.path.getsize(filename) total_columns = int(self.active_table_metadata[table_name] [COLUMNS]) + NUM_METADATA_COLUMNS column_set_size = COLUMN_BLOCK_BYTES * total_columns file_offset = orig_filesize - column_set_size + (COLUMN_BLOCK_BYTES * column_index) with open(filename, "r+b") as file: block_full = True for i in range(COLUMN_BLOCK_PAGES): file.seek(file_offset) page_TPS = int.from_bytes(file.read(DATASIZE), byteorder='big', signed=False) if (page_TPS == 0): block_full = False break file_offset += PAGESIZE if (block_full): # append whitespace for new set of column blocks to end of file here file.seek(orig_filesize) file.write(bytearray(column_set_size)) file_offset = orig_filesize + ( COLUMN_BLOCK_BYTES * column_index ) # reset file_offset to start of column block to modify # write the TPS = 2^64 - 1 for first entry in the new page, for each column block # at the same time, add page mapping to table index init_TPS = 2**64 - 1 init_TPS_bytes = init_TPS.to_bytes(8, byteorder="big") table_index = self.active_table_indexes[table_name] file.seek( file_offset) # reset file position to start of blank page slot file.write(init_TPS_bytes) # write TPS number # add to table index the mapping from conceptual address to file offset + num_records # -- note that num_records is initially 1 because the TPS is first data entry table_index[(address.pagerange, address.page)] = [file_offset, 1] # also load the new page into bufferpool, checking first if bufferpool needs to evict a page if (self.bufferpool.is_full()): # evict page and flush it to disk if dirty evict_page = self.bufferpool.evict() while (len(evict_page) == 0): evict_page = self.bufferpool.evict() if (evict_page[1].dirty): self.flush_page(evict_page) in_memory_pg = Page() self.bufferpool.add_page(table_name, address, in_memory_pg) lstore.globals.access.release() return file_offset
def add_range(self, name, page_slot): curr_table = self.db.get_table(name) new_range = [] for column_index in range(lstore.config.Offset + curr_table.num_columns): new_page = Page() new_range.append(new_page) if self.must_evict( ): #need to evict a page to add the new range from memory frame_num = self.evict(name) self.frame_map[page_slot] = frame_num self.page_map[frame_num] = new_range self.accesses[ frame_num] += 1 #increase num accesses for this frame else: #space in the buffer pool to add a new range from memory self.frame_map[page_slot] = len(self.page_map) self.page_map[self.frame_map[page_slot]] = new_range self.accesses[self.frame_map[ page_slot]] += 1 #increase num accesses for this frame
def __init__(self, num_columns): self._pages = [] self.num_columns = num_columns + METADATA_COLUMN_COUNT for i in range(self.num_columns): self._pages.append(Page()) self.is_dirty = False