RC forceFlushPool(BM_BufferPool *const bm) { int i; if(bm == NULL) return RC_BUFFER_MGR_NOT_INIT; // Get the head node of the linked list. BM_PageReplaceList *current = bm->mgmtData->head; while(current != NULL) { if(current->pageFrameHandle->fixCount == 0) { if(current->pageFrameHandle->dirtyFlag) { BM_PageHandle *const page = current->pageFrameHandle->pageHandle; if(forcePage(bm, page) != RC_OK) { return RC_FORCE_FLUSH_FAILED; } } } current = current->nextFrame; } return RC_OK; }
void testReadPage () { BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Reading a page"; CHECK(createPageFile("testbuffer.bin")); CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); CHECK(pinPage(bm, h, 0)); CHECK(pinPage(bm, h, 0)); CHECK(markDirty(bm, h)); CHECK(unpinPage(bm,h)); CHECK(unpinPage(bm,h)); CHECK(forcePage(bm, h)); CHECK(shutdownBufferPool(bm)); CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
void updateOperationDetails(RM_TableData *rel, recordTableInfo *rec, BM_PageHandle *pageHandle, int recordId) { char *data; recordId = 0; markDirty(rec->bufferManager, pageHandle); unpinPage(rec->bufferManager, pageHandle); forcePage(rec->bufferManager, pageHandle); tableInfoDetailsToFileData(rel->name, data, rec); }
/************************************************************************************** * Function Name: forceFlushPool * * Description: * Write back the data in all dirty pages in the Buffer Pool * * Parameters: * BM_BufferPool *const bm: Buffer Pool Handler * * Return: * RC: return code * * Author: * Chengnan Zhao <*****@*****.**> * * History: * Date Name Content * ---------- -------------------------------------- ------------------------ * 2015-03-14 Chengnan Zhao <*****@*****.**> Initialization * 2015-03-20 Xin Su <*****@*****.**> Modify the PageList queue * Add comments * Add judgment of the rc returned by write function * 2015-03-27 Xin Su <*****@*****.**> Add validation of whether there is any unwritable page **************************************************************************************/ RC forceFlushPool(BM_BufferPool * const bm) { PageList *queue = (PageList *) bm->mgmtData; int unwritableCount = 0; // Set the current pointer to the head queue->current = queue->head; // Before writing a page back to disk, do check whether the fixCount = 0 // Just call forcePage() to write a dirty and writable page back to the file // The while loop ends when the current pointer points to the tail while (queue->current != queue->tail) { // Validate whether the page is writable // if the page is unwritable, then increment the unwritableCount // else if the page is dirty and writable, call forcePage() to write the page back to the file if (queue->current->dirtyFlag == TRUE && queue->current->fixCount > 0) { unwritableCount++; } else if (queue->current->dirtyFlag == TRUE && queue->current->fixCount == 0) { forcePage(bm, queue->current->page); } queue->current = queue->current->next; } // After the while loop, the current points to the tail of the PageList // We still need to check the page in the tail, using the same logic above if (queue->current == queue->tail) { if (queue->current->dirtyFlag == TRUE && queue->current->fixCount > 0) { unwritableCount++; } else if (queue->current->dirtyFlag == TRUE && queue->current->fixCount == 0) { forcePage(bm, queue->current->page); } } // if there is any unwritable page, then return error code if (unwritableCount != 0) { return RC_FLUSH_POOL_ERROR; } return RC_OK; } // forceFlushPool
/* * This function is used to update a Record, * updating on a deleted page is not possible */ RC updateRecord (RM_TableData *rel, Record *record) { //Find the data to be updated if(record->id.page > 0 && record->id.page <= totalPages) { BM_PageHandle *page = MAKE_PAGE_HANDLE(); int pageNum, slotNum; // Setting record id and slot number pageNum = record->id.page; slotNum = record->id.slot; //Compare if the record is a deleted Record, //return update not possible for deleted records (EC 401) if(strncmp(record->data, "DELETED_RECORD", 14) == 0) return RC_RM_UPDATE_NOT_POSSIBLE_ON_DELETED_RECORD; //Take the serailized updated record data char *record_str = serializeRecord(record, rel->schema); //pin page pinPage(((RM_RecordMgmt *)rel->mgmtData)->bm, page, record->id.page); //set the new fields, or the entire modified page memset(page->data, '\0', strlen(page->data)); sprintf(page->data, "%s", record_str); //free the temp data free(record_str); //mark the page as dirty markDirty(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //unpin the page, after use unpinPage(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //force write onto the page, as it is modified page now forcePage(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //printf("record data in update: %s\n", page->data); free(page); //free page, avoid leaks return RC_OK; } else { return RC_RM_NO_MORE_TUPLES; //return the data to be modfied not found } return RC_OK; }
/* * This function is used to Delete the Record from the Table * BONUS IMPLEMENTATION - TOMBSTONE IS USED IN DELETION PROCESS */ RC deleteRecord (RM_TableData *rel, RID id) { /*A TOMBSTONE FLAG is set to mark it as a Deleted Record, but actual delete is not done * The Record is Prefixed with DELETED_RECORD string * ex. consider the record to be deleted be * (a:1,b:aaaa,c:45), the serializer store it as [1-0](a:1,b:aaaa,c:45) * deleted will be marked as DELETED RECORD[1-0](a:1,b:aaaa,c:45) */ char deleteTombStomeFlag[14] = "DELETED_RECORD"; //Tombstone flag char *temp = (char*)malloc(sizeof(char*)); //temp memory allocation to preappend the flag if(id.page > 0 && id.page <= totalPages) { BM_PageHandle *page = MAKE_PAGE_HANDLE(); //Pin page, to mark it in USE pinPage(((RM_RecordMgmt *)rel->mgmtData)->bm, page, id.page); //attach the flag to deletedRecord strcpy(temp, deleteTombStomeFlag); strcat(temp, page->data); //set pageNum page->pageNum = id.page; //copy the new data onto the Page i.e. modify the page->data memset(page->data, '\0', strlen(page->data)); sprintf(page->data, "%s", temp); //marking the page dirty, as new data has been written, i.e. tombstone data markDirty(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //unpin page, after use unpinPage(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //write the new data onto the page, in the pageFile forcePage(((RM_RecordMgmt *)rel->mgmtData)->bm, page); page = NULL; free(page); //free page, avoid leaks return RC_OK; } else { return RC_RM_NO_MORE_TUPLES; } return RC_OK; }
RC shutdownBufferPool(BM_BufferPool *const bm) { RC retCode; // Get the head node of the linked list. BM_PageReplaceList *current = bm->mgmtData->last; while(current != NULL) { if(current->pageFrameHandle->fixCount == 0) { // If fix count is 0, then proceed, else throw error. if(current->pageFrameHandle->dirtyFlag) { // If dirty flag is set, write page back to the disk. BM_PageHandle *const page = current->pageFrameHandle->pageHandle; if(forcePage(bm, page) != RC_OK) { return RC_FORCE_FLUSH_FAILED; } } current = current->prevFrame; } else { // Throw error as buffer pool is still in use. return RC_POOL_IN_USE; } } int i; // Deallocate memory allocated for frame data and page handle. for(i=0; i < bm->numPages; i++) { free(bm->mgmtData->hashT->hashArray[i]->pageHandle->data); // Char * free(bm->mgmtData->hashT->hashArray[i]->pageHandle); // BM_PageHandle free(bm->mgmtData->hashT->hashArray[i]); // PageInfo } // free(bm->mgmtData->hashT->hashArray); // Close file and deallocate memory assigned to file handle. closePageFile(bm->mgmtData->fh); // Deallocate memory assigned for each link in the linked list. current = bm->mgmtData->last; while(current->prevFrame != NULL) { free(current->nextFrame); current = current->prevFrame; } free(current); free(bm->mgmtData->fh); // Deallocate memory for SM_FileHandle free(bm->mgmtData->hashT); // Deallocation of PageInfo ** free(bm->mgmtData); // Deallocation of BM_MgmtData free(bm->pageFile); // Deallocation of page file return RC_OK; }
// test error cases void testError (void) { BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "ERROR TEST"; CHECK(createPageFile("testbuffer.bin")); // pinpage until buffer pool is full and then request additional page. CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); CHECK(pinPage(bm, h, 0)); CHECK(pinPage(bm, h, 1)); CHECK(pinPage(bm, h, 2)); ASSERT_ERROR(pinPage(bm, h, 3), "try to pin page when pool is full of pinned pages with fix-count > 0"); CHECK(shutdownBufferPool(bm)); // try to pin page with negative page number. CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); ASSERT_ERROR(pinPage(bm, h, -10), "try to pin page with negative page number"); CHECK(shutdownBufferPool(bm)); // try to use uninitialized buffer pool ASSERT_ERROR(initBufferPool(bm, "unavailable.bin", 3, RS_FIFO, NULL), "try to init buffer pool for non existing page file"); ASSERT_ERROR(shutdownBufferPool(bm), "shutdown buffer pool that is not open"); ASSERT_ERROR(forceFlushPool(bm), "flush buffer pool that is not open"); ASSERT_ERROR(pinPage(bm, h, 1), "pin page in buffer pool that is not open"); // try to unpin, mark, or force page that is not in pool CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); ASSERT_ERROR(unpinPage(bm, h), "Try to unpin a page which is not available in framelist."); ASSERT_ERROR(forcePage(bm, h), "Try to forceflush a page which is not available in framelist."); ASSERT_ERROR(markDirty(bm, h), "Try to markdirty a page which is not available in framelist."); CHECK(shutdownBufferPool(bm)); // done remove page file CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
// test error cases void testError (void) { int i; BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Testing LRU page replacement"; CHECK(createPageFile("testbuffer.bin")); // pin until buffer pool is full and request additional page CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); CHECK(pinPage(bm, h, 0)); CHECK(pinPage(bm, h, 1)); CHECK(pinPage(bm, h, 2)); ASSERT_ERROR(pinPage(bm, h, 3), "try to pin page when pool is full of pinned pages"); CHECK(shutdownBufferPool(bm)); // try to ready page with negative page number CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); ASSERT_ERROR(pinPage(bm, h, -1), "try to pin page with negative page number"); CHECK(shutdownBufferPool(bm)); // try to use uninitialized buffer pool ASSERT_ERROR(shutdownBufferPool(bm), "shutdown buffer pool that is not open"); ASSERT_ERROR(forceFlushPool(bm), "flush buffer pool that is not open"); ASSERT_ERROR(pinPage(bm, h, 1), "pin page in buffer pool that is not open"); ASSERT_ERROR(initBufferPool(bm, "xxx.bin", 3, RS_FIFO, NULL), "try to init buffer pool for non existing page file"); // try to unpin, mark, or force page that is not in pool CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); ASSERT_ERROR(unpinPage(bm, h), "unpin page not in buffer pool"); ASSERT_ERROR(forcePage(bm, h), "unpin page not in buffer pool"); ASSERT_ERROR(markDirty(bm, h), "mark page dirty that is not in buffer pool"); CHECK(shutdownBufferPool(bm)); // done remove page file CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
void pageOperations(recordTableInfo *table, int pageNum, int slot, RM_TableData *rel, Record *record) { BM_PageHandle *pageHandle=NULL; pageHandle = getBuffPageHandle(); char *strRecord,*tempData; strRecord = serializeRecord(record, rel->schema); if(pinPage(table->bufferManager, pageHandle, pageNum)==RC_OK) strncpy(pageHandle->data + (slot * table->slotSize), strRecord, strlen(strRecord)); markDirty(table->bufferManager, pageHandle); unpinPage(table->bufferManager, pageHandle); if(forcePage(table->bufferManager, pageHandle)==RC_OK) record->id.tombS = false; table->numOfRecords = table->numOfRecords + 1; tableInfoDetailsToFileData(rel->name, tempData, table); free(pageHandle); free(strRecord); }
RC unpinPage (BM_BufferPool *const bm, BM_PageHandle *const page) { resetPages(); int i; for (i = 0; i < bm->numPages; i++) { if (pages->pageNum == page->pageNum) { break; } if(i < bm->numPages-1){ pages = pages->nextPage; } } if(pages->isMark){ forcePage(bm, page); } pages->fixCount--; resetPages(); return RC_OK; }
//adding one to the fix for the pin page in the buffer pool //And adding one to each time of mgmtDataLRU in the buffer pool RC LRU_pinPage(BM_BufferPool *const bm, BM_PageHandle *const page, PageNumber pageNum){ //printf("pin: %d\n", pageNum); int i; int ind = LRU_findByPageNumber(bm, pageNum); //get the system time at pinPage; clock_t c = clock(); mgmtDataLRU * nodes = (mgmtDataLRU *)bm->mgmtData; RC _rc; SM_FileHandle fHandle; //if the page is in buffer, return the pagehandle if (ind >= 0){ page->pageNum = pageNum; page->data = nodes[ind].pagehandle->data; nodes[ind].time = c; nodes[ind].fix++; //printf("page found in buffer: %d\n", ind); return RC_OK; } //if there are free page in the buffer for(i=0; i<bm->numPages; i++){ if ( nodes[i].pagehandle->pageNum == NO_PAGE){ //printf("%dth page is free\n", i); nodes[i].pagehandle->pageNum = pageNum; free(nodes[i].pagehandle->data); nodes[i].pagehandle->data = (char *)calloc(1, PAGE_SIZE); _rc = openPageFile(bm->pageFile, &fHandle); if(_rc != RC_OK){ return _rc; } _rc = readBlock(pageNum, &fHandle, nodes[i].pagehandle->data); closePageFile(&fHandle); if(_rc == RC_OK){ //printf("page # %d is in disk\n", pageNum); bm->numOfRead++; } nodes[i].fix++; nodes[i].time = c; nodes[i].dirty = false; page->pageNum = pageNum; page->data = nodes[i].pagehandle->data; //printf("pinpage succeed, %dth page become page# %d\n", i, page->pageNum); return RC_OK; } } //if all buffers have data i = LRU_findTheEariestUnfixedNode(bm); if (i == -1){ //all buffers are full and occupied return RC_BM_ALL_PAGE_PINNED; } else{ //write the content to disk if(nodes[i].dirty){ _rc = forcePage(bm,nodes[i].pagehandle); //bm->numOfWrite++; } nodes[i].pagehandle->pageNum = pageNum; free(nodes[i].pagehandle->data); nodes[i].pagehandle->data = (char *)calloc(1, PAGE_SIZE); _rc = openPageFile(bm->pageFile, &fHandle); if(_rc != RC_OK){ return _rc; } _rc = readBlock(pageNum, &fHandle, nodes[i].pagehandle->data); closePageFile(&fHandle); if(_rc == RC_OK){ bm->numOfRead++; } nodes[i].fix++; nodes[i].time = c; nodes[i].dirty = false; // nodes[i].time = (double)seconds; page->pageNum = pageNum; page->data = nodes[i].pagehandle->data; return RC_OK; } }
/* * This function is used to insert a new Record into the table * while inserting, the record Manager assigns a RID to the record * and update the "record" parameter too */ RC insertRecord (RM_TableData *rel, Record *record) { //Create a record variable Record *r = (Record *)malloc(sizeof(Record)); RID rid; rid.page = 1; rid.slot = 0; //Find the next place of insertion of a record while(rid.page > 0 && rid.page < totalPages) { rid.page = rid.page + 1; rid.slot = 0; /*getRecord(rel, rid, r); //obtaining the record from the table //checking for soft delete record in the table space for insertion if(strncmp(r->data, "DELETED_RECORD", 14) == 0) break;*/ } r = NULL; free(r); //free the memory of r which was just a temporary allocation //mark the page as free page ((RM_RecordMgmt *)rel->mgmtData)->freePages[0] = rid.page; //create a page handle BM_PageHandle *page = MAKE_PAGE_HANDLE(); //assign the record, its RID and slot number record->id.page = ((RM_RecordMgmt *)rel->mgmtData)->freePages[0]; record->id.slot = 0; //Serialize the Record to be inserted char * serializedRecord = serializeRecord(record, rel->schema); //Pin the record page, to mark that it is in use pinPage(((RM_RecordMgmt *)rel->mgmtData)->bm, page, ((RM_RecordMgmt *)rel->mgmtData)->freePages[0]); //insert the new record data, into the Table i.e. Pages of the PageFile memset(page->data, '\0', strlen(page->data)); sprintf(page->data, "%s", serializedRecord); //mark the page as Dirty Page, as now there is a new record entry on that page markDirty(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //Unpin the page as now it has been used unpinPage(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //Force Page to push entire data onto the page forcePage(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //printf("record data: %s\n", page->data); free(page); //free page, avoid memory leaks ((RM_RecordMgmt *)rel->mgmtData)->freePages[0] += 1; totalPages++; return RC_OK; }