void checkDummyPages(BM_BufferPool *bm, int num) { int i; BM_PageHandle *h = MAKE_PAGE_HANDLE(); char *expected = malloc(sizeof(char) * 512); CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); for (i = 0; i < num; i++) { CHECK(pinPage(bm, h, i)); sprintf(expected, "%s-%i", "Page", h->pageNum); ASSERT_EQUALS_STRING(expected, h->data, "reading back dummy page content"); CHECK(unpinPage(bm,h)); } CHECK(shutdownBufferPool(bm)); free(expected); free(h); }
void createDummyPages(BM_BufferPool *bm, int num) { int i; BM_PageHandle *h = MAKE_PAGE_HANDLE(); CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); for (i = 0; i < num; i++) { CHECK(pinPage(bm, h, i)); sprintf(h->data, "%s-%i", "Page", h->pageNum); CHECK(markDirty(bm, h)); CHECK(unpinPage(bm,h)); } CHECK(shutdownBufferPool(bm)); free(h); }
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(); }
/* * 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; }
void testClock(void) { // expected results const char *poolContents[]= { "[3x0],[-1 0],[-1 0],[-1 0]", "[3x0],[2 0],[-1 0],[-1 0]", "[3x0],[2 0],[0 0],[-1 0]", "[3x0],[2 0],[0 0],[8 0]", "[4 0],[2 0],[0 0],[8 0]", "[4 0],[2 0],[0 0],[8 0]", "[4 0],[2 0],[5 0],[8 0]", "[4 0],[2 0],[5 0],[0 0]", "[9 0],[2 0],[5 0],[0 0]", "[9 0],[8 0],[5 0],[0 0]", "[9 0],[8 0],[3x0],[0 0]", "[9 0],[8 0],[3x0],[2 0]" }; const int orderRequests[]= {3,2,0,8,4,2,5,0,9,8,3,2}; int i; int snapshot = 0; BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Testing CLOCK page replacement"; CHECK(createPageFile("testbuffer.bin")); createDummyPages(bm, 100); CHECK(initBufferPool(bm, "testbuffer.bin", 4, RS_CLOCK, NULL)); for (i=0;i<11;i++) { pinPage(bm,h,orderRequests[i]); if(orderRequests[i] == 3) markDirty(bm,h); unpinPage(bm,h); ASSERT_EQUALS_POOL(poolContents[snapshot++], bm, "check pool content using pages"); } forceFlushPool(bm); // check number of write IOs ASSERT_EQUALS_INT(2, getNumWriteIO(bm), "check number of write I/Os"); ASSERT_EQUALS_INT(10, getNumReadIO(bm), "check number of read I/Os"); CHECK(shutdownBufferPool(bm)); CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
/* * 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; }
/* * This function is used to Open a Created Table, * for any operation to be performed, the table has to be opened first * Also store the Schema related info by deserializing the schema, * in the Table Data */ RC openTable (RM_TableData *rel, char *name) { //Record Management to store record attributes RM_RecordMgmt *rm_mgmt = (RM_RecordMgmt*)malloc(sizeof(RM_RecordMgmt)); FILE *fptr; //FILE pointer fptr = fopen(name, "r+"); //Open the PageFile (Table) //Get the total Number of Pages in the page File char* readHeader; readHeader = (char*)calloc(PAGE_SIZE,sizeof(char)); fgets(readHeader,PAGE_SIZE,fptr); char* totalPage; totalPage = readHeader; totalPages = atoi(totalPage); //convert to integer //Make a Buffer Pool rm_mgmt->bm = MAKE_POOL(); //Make a Page Handle BM_PageHandle *page = MAKE_PAGE_HANDLE(); //Initialize the BufferPool initBufferPool(rm_mgmt->bm,name,6,RS_FIFO,NULL); //Pin the Page = 0, which has the Schema Information pinPage(rm_mgmt->bm,page,0); //FreePages are stored in an array rm_mgmt->freePages = (int*)malloc(sizeof(int)); rm_mgmt->freePages[0] = totalPages; //initialize the table data attributes //Deserialzing the Schema gives us the Relation information (i.e. Schema info) rel->schema = deserializeSchema(page->data); //store the name of the schema rel->name = name; //store the record management details rel->mgmtData = rm_mgmt; //Free the temp. memory allocations free(readHeader); free(page); return RC_OK; }
void readAndCheckDummyPage(BM_BufferPool *bm, int pageNum) { BM_PageHandle *h = MAKE_PAGE_HANDLE(); char *expected = malloc(sizeof(char) * 512); CHECK(pinPage(bm, h, pageNum)); sprintf(expected, "%s-%i", "Page", h->pageNum); ASSERT_EQUALS_STRING(expected, h->data, "check read page dummy page content"); CHECK(unpinPage(bm,h)); free(expected); free(h); }
/* * This function is used to get the Record from the Table * using the RID details */ RC getRecord (RM_TableData *rel, RID id, Record *record) { //find the record in the record table if(id.page > 0 && id.page <= totalPages) { //make a page handle BM_PageHandle *page = MAKE_PAGE_HANDLE(); //pin page, and mark it for use pinPage(((RM_RecordMgmt *)rel->mgmtData)->bm, page, id.page); //temp, to store the record data char *record_data = (char*)malloc(sizeof(char) * strlen(page->data)); //copy the data strcpy(record_data,page->data); //printf("Page data is: %s",record_data); //store the record data and id record->id = id; //deSerialze the data Record* deSerializedRecord = deserializeRecord(record_data,rel->schema); //unpin the page, after fetching the record unpinPage(((RM_RecordMgmt *)rel->mgmtData)->bm, page); //return the new data record->data = deSerializedRecord->data; //printf("Record Data in getRecord: %s\n",record->data); //free temp. allocations to avoid memory leaks free(deSerializedRecord); free(page); return RC_OK; } else //if record not found return RC_RM_NO_MORE_TUPLES { return RC_RM_NO_MORE_TUPLES; } return RC_OK; }
/************************************************************************************** * Function Name: initPageList * * Description: * Initialize the PageList to store pages in the Buffer Pool * * Parameters: * BM_BufferPool * const bm: Buffer Pool Handler * * Return: * void * * Author: * Xin Su <*****@*****.**> * * History: * Date Name Content * ---------- ---------------------------------- ------------------------ * 2015-03-15 Xin Su <*****@*****.**> Initialization **************************************************************************************/ void initPageList(BM_BufferPool * const bm) { PageList *queue = (PageList *) bm->mgmtData; PageFrame *pf[bm->numPages]; int i; for (i = 0; i < bm->numPages; i++) { // init PageFrame -> position 3 // Free them in shutdownBufferPool -> position 2 pf[i] = (PageFrame *) malloc(sizeof(PageFrame)); // Initialize the content in the PageFrame pf[i]->page = MAKE_PAGE_HANDLE(); // init page->data -> position 4 // Free them in shutdownBufferPool -> position 1 pf[i]->page->data = (char *) malloc(PAGE_SIZE * sizeof(char)); pf[i]->page->pageNum = NO_PAGE; pf[i]->frameNum = i; pf[i]->numReadIO = 0; pf[i]->numWriteIO = 0; pf[i]->fixCount = 0; pf[i]->dirtyFlag = FALSE; pf[i]->clockFlag = FALSE; // Add this new PageFrame to the tail of pf // if pf has only one node (i = 0), then add this new PageFrame as the head // else, add this new PageFrame to the tail if (i == 0) { pf[i]->previous = NULL; pf[i]->next = NULL; } else { pf[i - 1]->next = pf[i]; pf[i]->previous = pf[i - 1]; pf[i]->next = NULL; } } // Reset all pointers and queue's size to the initial state queue->head = pf[0]; queue->tail = queue->head; queue->current = queue->head; queue->clock = queue->head; queue->size = 0; return; } // initPageList
// 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 testsimpleFIFO () { printf("FIFO Execution in new thread : \n " ); // expected results const char *poolContents[] = { "[0 0],[-1 0],[-1 0]" , "[0 0],[1 0],[-1 0]", "[0 0],[1 0],[2 0]", "[3 0],[1 0],[2 0]" }; const int requests[] = {0,1,2,3,4,4,5,6,0}; const int numLinRequests = 4; int i; BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Testing FIFO page replacement"; CHECK(createPageFile("testbuffer.bin")); createDummyPages(bm, 100); CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); // reading some pages linearly with direct unpin and no modifications for(i = 0; i < numLinRequests; i++) { pinPage(bm, h, requests[i]); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[i], bm, "check pool content"); } CHECK(shutdownBufferPool(bm)); CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
// test the CLOCK page replacement strategy void testClock (void) { // expected results const char *poolContents[] = { // read first five pages and directly unpin them "[0 0],[-1 0],[-1 0]" , "[0 0],[1 0],[-1 0]" , "[2 0],[1 0],[-1 0]" , "[2 0],[1 0],[3 0]" , // pin the page 2 again "[2 0],[1 0],[3 0]" , // read other pages use pin_CLOCK "[2 0],[4 0],[3 0]" , "[5 0],[4 0],[3 0]" , "[6 0],[4 0],[3 0]", "[6 0],[7 0],[3 0]" }; const int orderRequests[] = {2}; const int numrfChange = 1; int i; int snapshot = 0; BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Testing CLOCK page replacement"; CHECK(createPageFile("testbuffer.bin")); createDummyPages(bm, 100); CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_CLOCK, NULL)); // reading first five pages linearly with direct unpin and no modifications for(i = 0; i <4; i++) { pinPage(bm, h, i); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[snapshot++], bm, "check pool content reading in pages"); } // read pages to rf of the frames for(i = 0; i < numrfChange; i++) { pinPage(bm, h, orderRequests[i]); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[snapshot++], bm, "check pool content using pages"); } // replace pages and check that it happens in LRU_K order for(i = 0; i < 4; i++) { pinPage(bm, h, 4 + i); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[snapshot++], bm, "check pool content using pages"); } // check number of write IOs ASSERT_EQUALS_INT(0, getNumWriteIO(bm), "check number of write I/Os"); ASSERT_EQUALS_INT(8, getNumReadIO(bm), "check number of read I/Os"); CHECK(shutdownBufferPool(bm)); CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
//Clock[START] void testClock() { // expected results const char *poolContents[] = { "[0 0],[-1 0],[-1 0]", "[0 0],[4 0],[-1 0]", "[0 0],[4 0],[1 0]", "[0 0],[4 0],[1 0]", "[2 0],[4 0],[1 0]", "[2 0],[4 0],[1 0]", "[2 0],[4 0],[3 0]", "[2 0],[4 0],[3 0]", "[2 0],[4 0],[3 0]", "[2 0],[4 0],[3 0]", "[2 0],[4 0],[0 0]", "[2 0],[4 0],[0 0]", "[1 0],[4 0],[0 0]", "[1 0],[4 0],[0 0]", "[1 0],[4 0],[2 0]", "[1 0],[4 0],[2 0]", "[3 0],[4 0],[2 0]", "[3 0],[4 0],[2 0]", "[3 0],[4 0],[2 0]", }; const int requests[] = {0,4,1,4,2,4,3,4,2,4,0,4,1,4,2,4,3,4}; int i; BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Testing CLOCK page replacement"; CHECK(createPageFile("testbuffer.bin")); createDummyPages(bm, 100); CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_CLOCK, NULL)); // reading some pages linearly with direct unpin and no modifications for(i = 0; i < 18; i++) { pinPage(bm, h, requests[i]); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[i], bm, "check pool content"); } forceFlushPool(bm); ASSERT_EQUALS_POOL(poolContents[i],bm,"pool content after flush"); // check number of write IOs //0 writes because no dirty pages were present ASSERT_EQUALS_INT(0, getNumWriteIO(bm), "check number of write I/Os"); ASSERT_EQUALS_INT(9, getNumReadIO(bm), "check number of read I/Os"); CHECK(shutdownBufferPool(bm)); CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
void testFIFO () { // expected results const char *poolContents[] = { "[0 0],[-1 0],[-1 0]" , "[0 0],[1 0],[-1 0]", "[0 0],[1 0],[2 0]", "[3 0],[1 0],[2 0]", "[3 0],[4 0],[2 0]", "[3 0],[4 1],[2 0]", "[3 0],[4 1],[5x0]", "[6x0],[4 1],[5x0]", "[6x0],[4 1],[0x0]", "[6x0],[4 0],[0x0]", "[6 0],[4 0],[0 0]" }; const int requests[] = {0,1,2,3,4,4,5,6,0}; const int numLinRequests = 5; const int numChangeRequests = 3; int i; BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Testing FIFO page replacement"; CHECK(createPageFile("testbuffer.bin")); createDummyPages(bm, 100); CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_FIFO, NULL)); // reading some pages linearly with direct unpin and no modifications for(i = 0; i < numLinRequests; i++) { pinPage(bm, h, requests[i]); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[i], bm, "check pool content"); } // pin one page and test remainder i = numLinRequests; pinPage(bm, h, requests[i]); ASSERT_EQUALS_POOL(poolContents[i],bm,"pool content after pin page"); // read pages and mark them as dirty for(i = numLinRequests + 1; i < numLinRequests + numChangeRequests + 1; i++) { pinPage(bm, h, requests[i]); markDirty(bm, h); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[i], bm, "check pool content"); } // flush buffer pool to disk i = numLinRequests + numChangeRequests + 1; h->pageNum = 4; unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[i],bm,"unpin last page"); i++; forceFlushPool(bm); ASSERT_EQUALS_POOL(poolContents[i],bm,"pool content after flush"); // check number of write IOs ASSERT_EQUALS_INT(3, getNumWriteIO(bm), "check number of write I/Os"); ASSERT_EQUALS_INT(8, getNumReadIO(bm), "check number of read I/Os"); CHECK(shutdownBufferPool(bm)); CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
/* * 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; }
// test the LRU page replacement strategy void testLRU (void) { // expected results const char *poolContents[] = { // read first five pages and directly unpin them "[0 0],[-1 0],[-1 0],[-1 0],[-1 0]" , "[0 0],[1 0],[-1 0],[-1 0],[-1 0]", "[0 0],[1 0],[2 0],[-1 0],[-1 0]", "[0 0],[1 0],[2 0],[3 0],[-1 0]", "[0 0],[1 0],[2 0],[3 0],[4 0]", // use some of the page to create a fixed LRU order without changing pool content "[0 0],[1 0],[2 0],[3 0],[4 0]", "[0 0],[1 0],[2 0],[3 0],[4 0]", "[0 0],[1 0],[2 0],[3 0],[4 0]", "[0 0],[1 0],[2 0],[3 0],[4 0]", "[0 0],[1 0],[2 0],[3 0],[4 0]", // check that pages get evicted in LRU order "[0 0],[1 0],[2 0],[5 0],[4 0]", "[0 0],[1 0],[2 0],[5 0],[6 0]", "[7 0],[1 0],[2 0],[5 0],[6 0]", "[7 0],[1 0],[8 0],[5 0],[6 0]", "[7 0],[9 0],[8 0],[5 0],[6 0]" }; const int orderRequests[] = {3,4,0,2,1}; const int numLRUOrderChange = 5; int i; int snapshot = 0; BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Testing LRU page replacement"; CHECK(createPageFile("testbuffer.bin")); createDummyPages(bm, 100); CHECK(initBufferPool(bm, "testbuffer.bin", 5, RS_LRU, NULL)); // reading first five pages linearly with direct unpin and no modifications for(i = 0; i < 5; i++) { pinPage(bm, h, i); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[snapshot++], bm, "check pool content reading in pages"); } // read pages to change LRU order for(i = 0; i < numLRUOrderChange; i++) { pinPage(bm, h, orderRequests[i]); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[snapshot++], bm, "check pool content using pages"); } // replace pages and check that it happens in LRU order for(i = 0; i < 5; i++) { pinPage(bm, h, 5 + i); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[snapshot++], bm, "check pool content using pages"); } // check number of write IOs ASSERT_EQUALS_INT(0, getNumWriteIO(bm), "check number of write I/Os"); ASSERT_EQUALS_INT(10, getNumReadIO(bm), "check number of read I/Os"); CHECK(shutdownBufferPool(bm)); CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }
void testLFU() { // expected results const char *poolContents[] = { //Pin and Unpin 3 pages "[0 0],[-1 0],[-1 0]" , "[0 0],[1 0],[-1 0]", "[0 0],[1 0],[2 0]", //Pin the 0th page thrice,1st page twice "[0 3],[1 2],[2 0]", //Now pin a new page say 4. 4 should replace page 2 as page 2 has been Least Freq Used. "[0 3],[1 2],[4 1]", //Pin the 4th page thrice "[0 3],[1 2],[4 4]", //Now pin a new page 5. 5 should replace page 1 as page 1 has been Least Freq Used. "[0 3],[5 1],[4 4]", //Unpin page 0 thrice, page 5 once and page 4 four times. "[0 0],[5 0],[4 0]", }; const int requests[] = {0,1,2,3,4,5,6}; const int numLinRequests = 3; int i; BM_BufferPool *bm = MAKE_POOL(); BM_PageHandle *h = MAKE_PAGE_HANDLE(); testName = "Testing LFU page replacement"; CHECK(createPageFile("testbuffer.bin")); createDummyPages(bm, 100); CHECK(initBufferPool(bm, "testbuffer.bin", 3, RS_LFU, NULL)); // reading some pages linearly with direct unpin and no modifications for(i = 0; i < numLinRequests; i++) { pinPage(bm, h, requests[i]); unpinPage(bm, h); ASSERT_EQUALS_POOL(poolContents[i], bm, "check pool content"); } pinPage(bm, h, 0); pinPage(bm, h, 0); pinPage(bm, h, 0); pinPage(bm, h, 1); pinPage(bm, h, 1); ASSERT_EQUALS_POOL(poolContents[i++],bm,"pool content after pin page"); pinPage(bm, h, 4); ASSERT_EQUALS_POOL(poolContents[i++],bm,"pool content after pin page"); pinPage(bm,h,4); pinPage(bm,h,4); pinPage(bm,h,4); ASSERT_EQUALS_POOL(poolContents[i++],bm,"pool content after pin page"); pinPage(bm,h,5); ASSERT_EQUALS_POOL(poolContents[i++],bm,"pool content after pin page"); h->data = "Page-0"; h->pageNum = 0; unpinPage(bm,h); unpinPage(bm,h); unpinPage(bm,h); h->data = "Page-5"; h->pageNum = 5; unpinPage(bm,h); h->data = "Page-4"; h->pageNum = 4; unpinPage(bm,h); unpinPage(bm,h); unpinPage(bm,h); unpinPage(bm,h); forceFlushPool(bm); ASSERT_EQUALS_POOL(poolContents[i],bm,"pool content after flush"); // check number of write IOs //0 writes because no dirty pages were present ASSERT_EQUALS_INT(0, getNumWriteIO(bm), "check number of write I/Os"); ASSERT_EQUALS_INT(5, getNumReadIO(bm), "check number of read I/Os"); CHECK(shutdownBufferPool(bm)); CHECK(destroyPageFile("testbuffer.bin")); free(bm); free(h); TEST_DONE(); }