RC FIFO(BM_BufferPool *const bm, BM_PageHandle *const page, const PageNumber pageNum) { int ret, i; struct BM_PageFrame *frameListHead, *curFrame, *selectedFrame; SM_FileHandle fh; ret = openPageFile(bm->pageFile, &fh); if (RC_OK != ret){ printf("%s, %d, Open Page File Fail\n", __func__,__LINE__); return RC_FILE_HANDLE_NOT_INIT; } frameListHead = (BM_PageFrame *)bm->mgmtData; selectedFrame = findEmpPage(frameListHead); // No Empty page, fetch suitable position to replace the page if (NULL == selectedFrame) { selectedFrame = pinPosition(frameListHead); } // Do not have usable frame in memory if (NULL == selectedFrame) { printf("%s All frame cannot be used\n", __func__); return RC_BM_BP_NO_FRAME_TO_REP; } //Prepare to read the page from disk to memory if (fh.totalNumPages < pageNum +1) { ret = ensureCapacity(pageNum +1, &fh); NumWriteIO += pageNum +1 - fh.totalNumPages; if (RC_OK != ret) { closePageFile(&fh); printf("%s, %d ensurecapacity fail\n",__func__, __LINE__ ); return RC_READ_NON_EXISTING_PAGE; } } //Write framepage to disk if page is dirty if(selectedFrame->flags & Frame_dirty) { writeBlock(selectedFrame->pageHandle.pageNum, &fh, selectedFrame->pageHandle.data); selectedFrame->flags &= ~Frame_dirty; NumWriteIO++; } ret = readBlock(pageNum, &fh, selectedFrame->pageHandle.data); NumReadIO++; page->pageNum = pageNum; page->data = selectedFrame->pageHandle.data; selectedFrame->fixCount += 1; selectedFrame->pageHandle.pageNum = pageNum; selectedFrame->flags |=Frame_cached; maintainSortedFrameList(bm, selectedFrame); closePageFile(&fh); return ret; }
RC forceFlushPool(BM_BufferPool *const bm) { //write all dirty pages (fix count 0) to disk //do pinned check buffer *bf = bm->mgmtData; SM_FileHandle fHandle; RC rt_value = openPageFile(bm->pageFile, &fHandle); if (rt_value!=RC_OK) return rt_value; frame *pt = bf->head; do { if (pt->dirty) { rt_value = writeBlock(pt->currpage, &fHandle, pt->data); if (rt_value!=RC_OK) return rt_value; pt->dirty = false; bf->numWrite++; } pt = pt->next; }while (pt!=bf->head); closePageFile(&fHandle); return RC_OK; }
int pinThispage(BM_BufferPool *const bm, frame *pt, PageNumber pageNum) /*pin page pointed by pt with pageNum-th page. If do not have, create one*/ { buffer *bf = bm->mgmtData; SM_FileHandle fHandle; //cheating: should malloc then free RC rt_value = openPageFile(bm->pageFile, &fHandle); if (rt_value!=RC_OK) return rt_value; rt_value = ensureCapacity(pageNum, &fHandle); //你不说谁知道啊 if (rt_value!=RC_OK) return rt_value; if (pt->dirty) { rt_value = writeBlock(pt->currpage, &fHandle, pt->data); if (rt_value!=RC_OK) return rt_value; pt->dirty = false; bf->numWrite++; } rt_value = readBlock(pageNum, &fHandle, pt->data); if (rt_value!=RC_OK) return rt_value; bf->numRead++; pt->currpage = pageNum; pt->fixCount++; closePageFile(&fHandle); return 0; }
RC shutdownBufferPool (BM_BufferPool *const bm) { SM_FileHandle fh; RC code = openPageFile(bm->pageFile, &fh); if (code != RC_OK) return code; resetPages(); int i = 0; for(i = 0; i < bm->numPages; i++){ if (pages->isMark && pages->fixCount > 0){ code = writeBlock(pages->pageNum, &fh, pages->pageData); if(code != RC_OK) return code; metaData.numWriteIO++; } pages->isMark = false; pages->pageData = malloc(PAGE_SIZE); strcpy(pages->pageData, ""); pages->pageNum = -1; pages->fixCount = 0; pages->repStrat = -1; if(i < bm->numPages-1){ pages = pages->nextPage; } } closePageFile(&fh); return RC_OK; }
RC shutdownBufferPool(BM_BufferPool *const bm){ forceFlushPool(bm); //store data into memory free(bm->mgmtData); closePageFile(fh); return RC_OK; }
RC createTable(char *name, Schema *schema) { SM_FileHandle fh; char data[PAGE_SIZE]; char *offset = data; // Prepare schema for writing to block header memset(offset, 0, PAGE_SIZE); *(int*)offset = 0; offset = offset + sizeof(int); *(int*)offset = 0; offset = offset + sizeof(int); *(int*)offset = schema->numAttr; offset = offset + sizeof(int); *(int*)offset = schema->keySize; offset = offset + sizeof(int); // Copy everything from schema to be written to block int i; for (i = 0; i < schema->numAttr; i++) { strncpy(offset, schema->attrNames[i], NAME_SIZE); offset = offset + NAME_SIZE; *(int*)offset = (int)schema->dataTypes[i]; offset = offset + TYPE_SIZE; *(int*)offset = (int)schema->typeLength[i]; offset = offset + LENGTH_SIZE; if (i < schema->keySize) { *(int*)offset = (int)schema->keyAttrs[i]; } offset = offset + KEY_SIZE; } // Write the table and schema information to file RC createPageFileResult; if ((createPageFileResult = createPageFile(name)) != RC_OK) { return createPageFileResult; } RC openPageFileResult; if ((openPageFileResult = openPageFile(name, &fh)) != RC_OK) { return openPageFileResult; } RC writeBlockResult; if ((writeBlockResult = writeBlock(0, &fh, data)) != RC_OK) { return writeBlockResult; } RC closePageFileResult; if ((closePageFileResult = closePageFile(&fh)) != RC_OK) { return closePageFileResult; } return RC_OK; }
RC forcePage (BM_BufferPool *const bm, BM_PageHandle *const page) { //current frame2file buffer *bf = bm->mgmtData; SM_FileHandle fHandle; RC rt_value; rt_value = openPageFile(bm->pageFile, &fHandle); if (rt_value!=RC_OK) return RC_FILE_NOT_FOUND; rt_value = writeBlock(page->pageNum, &fHandle, page->data); if (rt_value!=RC_OK) { closePageFile(&fHandle); return RC_FILE_NOT_FOUND; } bf->numWrite++; closePageFile(&fHandle); return RC_OK; }
RC shutdownBufferPool(BM_BufferPool *const bm) { // Flush the pool RC flushResult = forceFlushPool(bm); if (flushResult != RC_OK) { return flushResult; } // Retrieve management data BM_MgmtData *mgmtData = bm->mgmtData; BM_Frame *frame = &mgmtData->framePool[0]; // Check for pinned pages int i; for (i = 0; i < bm->numPages; i++) { if (frame->fixCount != 0) { return RC_FRAME_PINNED_PAGE; } frame++; } // Close storage manager details RC pageCloseResult = closePageFile(&mgmtData->fh); if (pageCloseResult != RC_OK) { return pageCloseResult; } // Free memory and lists // Free frames for (i = 0; i < bm->numPages; i++) { free(mgmtData->framePool[i].memPage); } // Free frame pool free(mgmtData->framePool); // Free linked list nodes BM_Node *freeHead = mgmtData->head; while (freeHead != NULL) { freeHead = removeFromHead(&mgmtData->head); if (freeHead != NULL) { free(freeHead); } } // Free mgmt data free(bm->mgmtData); // Free buffer pool free(bm->pageFile); 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; }
/* Name: ShutDown BufferPool * Behavior:Would shutdown an existing buffer pool. * Version: 1.0.0 */ RC shutdownBufferPool(BM_BufferPool *const bm) { RC ret=RC_WRITE_FAILED; int i ,*pgnums, *fixounts; bool ispinned=FALSE; Buffer_page_Dtl *pg_dtl; BufferPool_Node *bufnode; char *frame; int currentaccessed; // pthread_mutex_lock(&work_mutex_shutdown);//1st Incoming thread hold a lock. fixounts=getFixCounts(bm); pgnums=getFrameContents(bm); for(i=0 ; i < bm->numPages ; i++) { if(fixounts[i] > 0) { ispinned=TRUE;//Condition to check for pinned pages before shut down. } } free(fixounts); if(ispinned==FALSE) { ret=RC_OK; bufnode=search_data(BP_StNode_ptr,bm);//Get the active buffer pool from collection of pools. currentaccessed=getfilebeingused(BP_StNode_ptr,bm->pageFile);//Check if the same pool is being shared. if(bufnode!=NULL) { pg_dtl=bufnode->buffer_page_dtl; if(pg_dtl!=NULL) for(i=0;i<bm->numPages;i++) { frame=pg_dtl[i].pageframes; if(pg_dtl[i].isdirty==TRUE) { ret=writeBlock(pg_dtl[i].pagenums,bm->mgmtData,frame)==RC_OK?RC_OK:RC_WRITE_FAILED;//Write the content with dirty to disk. } currentaccessed == 1 ?free(frame):' '; } currentaccessed == 1 ?free(pg_dtl):' '; pg_dtl=NULL; delete_node(&BP_StNode_ptr,bm); } currentaccessed == 1 ?closePageFile(bm->mgmtData):' '; currentaccessed == 1 ?free(bm->mgmtData):' '; } // pthread_mutex_unlock(&work_mutex_shutdown);//1st Incoming thread release a lock. free(pgnums); return ret; }
//Creating a table should create the underlying page file and store information about the schema, free-space, ... and so on in the Table Information pages RC createTable (char *name, Schema *schema){ createPageFile(name); SM_PageHandle ph; openPageFile(name, &fh); ensureCapacity(1, &fh); ph=schemaToString(schema); writeCurrentBlock(&fh,ph); calSlotSize(schema); calPageHeader(schema); closePageFile(&fh); return RC_OK; }
RC forcePage (BM_BufferPool *const bm, BM_PageHandle *const page) { SM_FileHandle fH; int code = openPageFile(bm->pageFile, &fH); if(code != RC_OK) return code; appendEmptyBlock(&fH); code = writeBlock(page->pageNum, &fH, page->data); if(code != RC_OK) return code; closePageFile(&fH); metaData.numWriteIO++; return RC_OK; }
// Close buffer pool RC shutdownBufferPool(BM_BufferPool *const bm) { RC rc= RC_OK; int frmNo; BM_PageFrame *pf; BM_Pool_MgmtData *mgmtData= bm->mgmtData; // Flush dirty pages rc= forceFlushPool(bm); if (rc != RC_OK) RETURN(rc); BM_LOCK(); // Check if we have pinned pages, pf= &mgmtData->pool[0]; for (frmNo=0; frmNo < bm->numPages; frmNo++) { if (pf->fixCount) { BM_UNLOCK(); RETURN(RC_HAVE_PINNED_PAGE); } // Also reset page table if (pf->pn != NO_PAGE) resetPageFrame(&mgmtData->pt_head, pf->pn); pf++; } rc= closePageFile(&mgmtData->fh); if (rc != RC_OK) { BM_UNLOCK(); RETURN(rc); } cleanLRUlist(&mgmtData->stratData); free(mgmtData->pool); free(bm->pageFile); BM_UNLOCK(); pthread_mutex_destroy(&mgmtData->bm_mutex); free(mgmtData); RETURN(RC_OK); }
/************************************************************************************** * Function Name: shutdownBufferPool * * Description: * Shut down the buffer pool * * Parameters: * BM_BufferPool *const bm: buffer pool that users try to shut down * * Return: * RC: return code * * Author: * Chengnan Zhao <*****@*****.**> * * History: * Date Name Content * ---------- -------------------------------------- ------------------------ * 2015-03-14 Chengnan Zhao <*****@*****.**> Initialization * 2015-03-20 Xin Su <*****@*****.**> Add judgment of the rc returned by forceFlushPool * Modify the logic of freeing the PageList * Add comments * Add judgment of the rc returned by closePageFile * Add the free code of F_HANDLE and MEM_PAGE **************************************************************************************/ RC shutdownBufferPool(BM_BufferPool * const bm) { // Force to flush all pages updated in the Buffer Pool back to the disk RC rc = -99; // init return code rc = forceFlushPool(bm); if (rc != RC_OK) { // TO DO } // Free allocated memory blocks (PageFrame) of the PageList PageList *queue = (PageList *) bm->mgmtData; queue->current = queue->tail; // if the capacity is 1, simply free the only block // else (the capacity > 1), free the PageFrame from the tail back to the head if (bm->numPages == 1) { free(bm->mgmtData); } else { while (queue->current != queue->head) { queue->current = queue->current->previous; free(queue->current->next); } // After the while loop, the current pointer points to the head, // then free the only left block free(queue->head); } // Turn off the Storage Manager by closing the page file rc = -99; // reset return code rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Then free the F_HANDLE and MEM_PAGE free(F_HANDLE); free(MEM_PAGE); return RC_OK; }
/* Try to create, open, and close a page file */ void testCreateOpenClose(void) { SM_FileHandle fh; testName = "test create open and close methods"; TEST_CHECK(createPageFile (TESTPF)); TEST_CHECK(openPageFile (TESTPF, &fh)); ASSERT_TRUE(strcmp(fh.fileName, TESTPF) == 0, "filename correct"); ASSERT_TRUE((fh.totalNumPages == 1), "expect 1 page in new file"); ASSERT_TRUE((fh.curPagePos == 0), "freshly opened file's page position should be 0"); TEST_CHECK(closePageFile (&fh)); TEST_CHECK(destroyPageFile (TESTPF)); // after destruction trying to open the file should cause an error ASSERT_TRUE((openPageFile(TESTPF, &fh) != RC_OK), "opening non-existing file should return an error."); TEST_DONE(); }
/*Purpose: when buffer pool is to be shut down, this function will write the pages which are dirty to the memory */ RC forceFlushPool(BM_BufferPool *const bm) { BufferManager *mgmtDataInfo=(BufferManager *)bm->mgmtData; PageFrames *TempTraverseNode=mgmtDataInfo->HeadNode; RC msg; if(TempTraverseNode==NULL){return RC_FRAME_NOT_INIT;} mgmtDataInfo->Total_WriteIO=getNumWriteIO(bm); while(TempTraverseNode!=NULL) { if(TempTraverseNode->Pining==0){ if(TempTraverseNode->DirtyCount==1) { if((msg = ensureCapacity(TempTraverseNode->PageNumberValue, &mgmtDataInfo->fileHandler_StorageMgr)) != RC_OK){ return msg; } if((msg=writeBlock(TempTraverseNode->PageNumberValue,&mgmtDataInfo->fileHandler_StorageMgr,TempTraverseNode->Data_Value))==RC_OK) { TempTraverseNode->DirtyCount=0; mgmtDataInfo->DirtyValue[(TempTraverseNode->PageNumberValue)-1]=false; mgmtDataInfo->Total_WriteIO+=1; } else { RC_message = "forceFlushPool"; RC_WRITE_FAILED; } } } else return RC_PINED_PAGE_FOUND; TempTraverseNode=TempTraverseNode->next; } closePageFile(&mgmtDataInfo->fileHandler_StorageMgr); free(TempTraverseNode); return RC_OK; }
RC forceFlushPool(BM_BufferPool *const bm){ //function used to store data into memory BufferPageNode *tem; int result; tem=g_queue->front; while (tem!=NULL) //loop to check dirty files { result=-1; if(tem->dirty==1) //check file if it is dirty { result=writeBlock(tem->PageNum,fh, tem->data); countWrite++; tem->dirty=0; //after storing set the dirty flag into 0 if (result!=0) { closePageFile(fh); return RC_WRITE_FAILED; } } tem=tem->next; } return RC_OK; }
RC forceFlushPool (BM_BufferPool *const bm) { int i = 0; resetPages(); SM_FileHandle fh; RC code = openPageFile(bm->pageFile, &fh); if (code != RC_OK) return code; for(i = 0; i < bm->numPages; i++){ if (pages->isMark && pages->pageNum > -1){ pages->isMark = false; } if(i < bm->numPages-1){ pages = pages->nextPage; } } resetPages(); closePageFile(&fh); return RC_OK; }
/************************************************************************************** * Function Name: forcePage * * Description: * Write the requested page back to the page file on disk * * Parameters: * BM_BufferPool * const bm: Buffer Pool Handler * BM_PageHandle * const page: Buffer Page Handler * * Return: * RC: return code * * Author: * Jie Zhou <*****@*****.**> * * History: * Date Name Content * ---------- ---------------------------------- ---------------------------- * 2015-03-13 Jie Zhou <*****@*****.**> Initialization * 2015-03-20 Xin Su <*****@*****.**> Modify the logic of forcing to write the requested page back * Add comments **************************************************************************************/ RC forcePage(BM_BufferPool * const bm, BM_PageHandle * const page) { PageList *queue = (PageList *) bm->mgmtData; RC rc = -99; // Require lock pthread_rwlock_init(&rwlock, NULL); pthread_rwlock_wrlock(&rwlock); // Open file rc = -99; rc = openPageFile(bm->pageFile, F_HANDLE); if (rc != RC_OK) { return rc; } // First set numWriteIO queue->current->numWriteIO = 1; // Write the requested page back to the disk rc = -99; rc = writeBlock(page->pageNum, F_HANDLE, page->data); NUM_WRITE_IOS++; if (rc != RC_OK) { // Do not change fixCount and NumWriteIO back, for this indicates write IO error and need more info to proceed // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release unlock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return rc; } // Set the page back to clean queue->current->dirtyFlag = FALSE; // The write completes without error, then set numWriteIO back queue->current->numWriteIO = 0; // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release lock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return RC_OK; } // forcePage
//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; } }
RC pinPage (BM_BufferPool *const bm, BM_PageHandle *const page, const PageNumber pageNum) { int i; resetPages(); int spotFound = -1; for(i = 0; i < bm->numPages; i++){ if(pages->pageNum == -1){ spotFound = i; break; } if(pages->pageNum == pageNum){ spotFound = i; break; } if(i < bm->numPages-1){ pages = pages->nextPage; } } int min = 999999; if (spotFound == -1) { resetPages(); for (i = 0; i < bm->numPages; i++) { if (pages->fixCount == 0 && pages->repStrat < min) { min = pages->repStrat; spotFound = i; } if(i < bm->numPages-1){ pages = pages->nextPage; } } } resetPages(); for(i = 0; i < bm->numPages; i++){ if(i == spotFound) break; if(i < bm->numPages-1){ pages = pages->nextPage; } } SM_FileHandle fH; openPageFile(bm->pageFile, &fH); if(pages->pageNum == pageNum){ if(bm->strategy == RS_LRU) pages->repStrat = ++(metaData.totalRepStrat); pages->fixCount++; page->pageNum = pageNum; strcpy(page->data, pages->pageData); }else { page->data = malloc(PAGE_SIZE); page->pageNum = pageNum; readBlock(pageNum, &fH, page->data); metaData.numReadIO++; pages->pageNum = pageNum; pages->fixCount = 1; pages->repStrat = ++(metaData.totalRepStrat); pages->isMark = false; } closePageFile(&fH); return RC_OK; }
/************************************************************************************** * Function Name: appendPage * * Description: * Read the requested page from the disk and append it to the tail of the PageList * * Parameters: * BM_BufferPool * const bm: Buffer Pool Handler * BM_PageHandle * const page: Buffer Page Handler * PageNumber pageNum: the page number of the requested page * * Return: * RC: return code * * Author: * Xin Su <*****@*****.**> * * History: * Date Name Content * ---------- ---------------------------------- ------------------------ * 2015-03-15 Xin Su <*****@*****.**> Initialization * 2015-03-26 Xin Su <*****@*****.**> Add thread read-write lock **************************************************************************************/ RC appendPage(BM_BufferPool * const bm, BM_PageHandle * const page, PageNumber pageNum) { PageList *queue = (PageList *) bm->mgmtData; RC rc; // init return code // Require lock pthread_rwlock_init(&rwlock, NULL); pthread_rwlock_wrlock(&rwlock); // Open File rc = -99; rc = openPageFile(bm->pageFile, F_HANDLE); if (rc != RC_OK) { return rc; } // if the size of the PageList = 0, then the PageList is empty, add this requested page as the head // else, the PageList is neither empty nor full, add the requested page to next of the tail of the PageList if (queue->size == 0) { queue->head->fixCount = 1; queue->head->numWriteIO = 1; // if the page does not exist, then call ensureCapacity to add the requested page to the file if (F_HANDLE->totalNumPages < pageNum + 1) { int totalPages = F_HANDLE->totalNumPages; rc = -99; rc = ensureCapacity(pageNum + 1, F_HANDLE); NUM_WRITE_IOS += pageNum + 1 - totalPages; if (rc != RC_OK) { // Do not change fixCount and NumWriteIO back, for this indicates write IO error and need more info to proceed // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release lock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return rc; } } queue->head->numWriteIO = 0; // After ensureCapacity, now we can read the requested page from the file queue->head->numReadIO++; rc = -99; rc = readBlock(pageNum, F_HANDLE, queue->head->page->data); NUM_READ_IOS++; queue->head->numReadIO--; if (rc != RC_OK) { // Do not change fixCount and NumWriteIO back, for this indicates write IO error and need more info to proceed // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release lock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return rc; } // Now the fixCount = 1, the numReadIO = 0, and the numWriteIO = 0 queue->head->page->pageNum = pageNum; queue->head->dirtyFlag = FALSE; queue->head->clockFlag = FALSE; // Now there is only 1 page in the PageList, and all pointers , including the current pointer, are pointing to it } else { queue->tail->next->fixCount = 1; queue->tail->next->numWriteIO = 1; // if the page does not exist, then call ensureCapacity to add the requested page to the file if (F_HANDLE->totalNumPages < pageNum + 1) { int totalPages = F_HANDLE->totalNumPages; rc = -99; rc = ensureCapacity(pageNum + 1, F_HANDLE); NUM_WRITE_IOS += pageNum + 1 - totalPages; if (rc != RC_OK) { // Do not change fixCount and NumWriteIO back, for this indicates write IO error and need more info to proceed // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release lock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return rc; } } queue->tail->next->numWriteIO = 0; // After ensureCapacity, now we can read the requested page from the file queue->tail->next->numReadIO++; rc = -99; rc = readBlock(pageNum, F_HANDLE, queue->tail->next->page->data); NUM_READ_IOS++; queue->tail->next->numReadIO--; if (rc != RC_OK) { // Do not change fixCount and NumWriteIO back, for this indicates write IO error and need more info to proceed // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release lock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return rc; } // Now the fixCount = 1, the numReadIO = 0, and the numWriteIO = 0 queue->tail->next->page->pageNum = pageNum; queue->tail->next->dirtyFlag = FALSE; queue->tail->next->clockFlag = FALSE; queue->tail = queue->tail->next; // Set the current pointer to the requested page, that is the tail of the PageList queue->current = queue->tail; } // After appending the requested page, Increment the size of the PageList queue->size++; // Load the requested page into BM_PageHandle page->data = queue->current->page->data; page->pageNum = queue->current->page->pageNum; // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release lock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return RC_OK; } // appendPage
void testReadWrite(void) { SM_FileHandle fh; SM_PageHandle ph; int i; ph = (SM_PageHandle) malloc(PAGE_SIZE); testName = "test read and write methods"; TEST_CHECK(createPageFile (TESTPF)); TEST_CHECK(openPageFile (TESTPF, &fh)); ASSERT_TRUE(strcmp(fh.fileName, TESTPF) == 0, "filename correct"); ASSERT_TRUE((fh.totalNumPages == 1), "expect 1 page in new file"); ASSERT_TRUE((fh.curPagePos == 0), "freshly opened file's page position should be 0"); //Writes A, B, C, D, E, F, G, H from 0th page to 7th page for(i = 0; i < 8; i ++) { memset(ph, 'A' + i, PAGE_SIZE); TEST_CHECK(writeBlock (i, &fh, ph)); printf("writing %d th block\n", fh.curPagePos); } // read first page into handle i.e. A TEST_CHECK(readFirstBlock (&fh, ph)); for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 'A'), "expected A"); printf("first block contains A\n"); // read last page into handle i.e. H TEST_CHECK(readLastBlock (&fh, ph)); for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 'H'), "expected H"); printf("last block contains H\n"); // read first page into handle i.e. A readFirstBlock (&fh, ph); // read next page into handle i.e. B TEST_CHECK(readNextBlock (&fh, ph)); for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 'B'), "expected B"); printf("block contains B\n"); readNextBlock (&fh, ph); //C readNextBlock (&fh, ph); //D // read previous page into handle i.e. C TEST_CHECK(readPreviousBlock (&fh, ph)); for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 'C'), "expected C"); printf("block contains C\n"); readNextBlock (&fh, ph); //D readNextBlock (&fh, ph); //E // read current page into handle i.e. E TEST_CHECK(readCurrentBlock (&fh, ph)); for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 'E'), "expected E"); printf("block contains E\n"); readPreviousBlock (&fh, ph); //D //Replace D with Z memset(ph, 'Z', PAGE_SIZE); TEST_CHECK(writeCurrentBlock (&fh, ph)); printf("writing D with Z\n"); // read current page into handle i.e. Z TEST_CHECK(readCurrentBlock (&fh, ph)); for (i=0; i < PAGE_SIZE; i++){ ASSERT_TRUE((ph[i] == 'Z'), "expected Z"); } printf("block contains Z\n"); TEST_CHECK(closePageFile (&fh)); TEST_CHECK(destroyPageFile (TESTPF)); free(ph); TEST_DONE(); }
/************************************************************************************** * Function Name: replacePage * * Description: * Replace the current page with the requested page read from the disk * * Parameters: * BM_BufferPool * const bm: Buffer Pool Handler * BM_PageHandle * const page: Buffer Page Handler * PageNumber pageNum: the page number of the requested page * * Return: * RC: return code * * Author: * Xin Su <*****@*****.**> * * History: * Date Name Content * ---------- ---------------------------------- ------------------------ * 2015-03-15 Xin Su <*****@*****.**> Initialization * 2015-03-26 Xin Su <*****@*****.**> Add thread read-write lock **************************************************************************************/ RC replacePage(BM_BufferPool * const bm, BM_PageHandle * const page, PageNumber pageNum) { PageList *queue = (PageList *) bm->mgmtData; RC rc; // init return code // Require lock pthread_rwlock_init(&rwlock, NULL); pthread_rwlock_wrlock(&rwlock); // Open file rc = -99; rc = openPageFile(bm->pageFile, F_HANDLE); if (rc != RC_OK) { return rc; } // If the removable page is dirty, then write it back to the disk before remove it. // Now the fixCount = 0, and the numReadIO = 0 and the numWriteIO = 0 queue->current->fixCount = 1; queue->current->numWriteIO = 1; // if the removable page is dirty, then write it back to the file if (queue->current->dirtyFlag == TRUE) { rc = -99; rc = writeBlock(queue->current->page->pageNum, F_HANDLE, queue->current->page->data); NUM_WRITE_IOS++; if (rc != RC_OK) { // Do not change fixCount and NumWriteIO back, for this indicates write IO error and need more info to proceed // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release unlock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return rc; } // After writeBlock, set the PageFrame back to clean queue->current->dirtyFlag = FALSE; } // if the page does not exist, then call ensureCapacity to add the requested page to the file if (F_HANDLE->totalNumPages < pageNum + 1) { int totalPages = F_HANDLE->totalNumPages; rc = -99; rc = ensureCapacity(pageNum + 1, F_HANDLE); NUM_WRITE_IOS += pageNum + 1 - totalPages; if (rc != RC_OK) { // Do not change fixCount and NumWriteIO back, for this indicates write IO error and need more info to proceed // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release unlock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return rc; } } queue->current->numWriteIO = 0; // After ensureCapacity, now we can read the requested page from the file queue->current->numReadIO++; rc = -99; rc = readBlock(pageNum, F_HANDLE, queue->current->page->data); NUM_READ_IOS++; queue->current->numReadIO--; if (rc != RC_OK) { // Do not change fixCount and NumWriteIO back, for this indicates write IO error and need more info to proceed // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release lock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return rc; } // Load the requested page to the current PageFrame in the BM_BufferPool // Now the fixCount = 1, the numReadIO = 0, and the numWriteIO = 0 queue->current->page->pageNum = pageNum; queue->current->clockFlag = FALSE; // Load the requested into BM_PageHandle page->data = queue->current->page->data; page->pageNum = queue->current->page->pageNum; // Close file rc = -99; rc = closePageFile(F_HANDLE); if (rc != RC_OK) { return rc; } // Release lock pthread_rwlock_unlock(&rwlock); pthread_rwlock_destroy(&rwlock); return RC_OK; } // replacePage
void testAppendEnsureCapMetaData() { SM_FileHandle fh; SM_PageHandle ph; ph = (SM_PageHandle) malloc(PAGE_SIZE); TEST_CHECK(createPageFile (TESTPF)); TEST_CHECK(openPageFile (TESTPF, &fh)); //Append an empty block to the file. appendEmptyBlock(&fh); //Check whether the appended block has only 4096 '\0' in the currentBlock. readBlock(getBlockPos(&fh),&fh,ph); int i; for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 0), "expected zero byte in first page of freshly initialized page"); printf("Appended Block was empty\n"); //Page File should contain only 2 blocks.first block during createPage and second during appendBlock ASSERT_TRUE((fh.totalNumPages == 2), "Number of Blocks : 2"); //Current Block postion should be 1 ASSERT_TRUE((fh.curPagePos == 1), "Current Page Position is 1"); //add 3 more blocks to the Page File. ensureCapacity(5,&fh); //Verify whether the freshly added 3 blocks are of '\0' characters //[START] readBlock(2,&fh,ph); for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 0), "expected zero byte in first page of freshly initialized page"); readBlock(3,&fh,ph); for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 0), "expected zero byte in first page of freshly initialized page"); readBlock(4,&fh,ph); for (i=0; i < PAGE_SIZE; i++) ASSERT_TRUE((ph[i] == 0), "expected zero byte in first page of freshly initialized page"); printf("Freshly appended 3 blocks are empty\n"); //[END] //Page File should contain only 5 blocks, as we have called ensureCapacity(5) ASSERT_TRUE((fh.totalNumPages == 5), "Number of Blocks : 5"); //Current Block postion should be 4 ASSERT_TRUE((fh.curPagePos == 4), "Current Page Position is 4"); //Store the metaData into the file and close the pagefile. int totalNoOfPages = fh.totalNumPages; char fileName[100]; memset(fileName,'\0',100); strcpy(fileName,fh.fileName); char metaDataFromFile[100]; memset(metaDataFromFile,'\0',100); closePageFile(&fh); //Verify whether the written MetaData is correct or not //[START] char metaDataToBeVerified[100]; memset(metaDataToBeVerified,'\0',100); char returnData[100]; memset(returnData,'\0',100); metaDataToBeVerified[0]= 'P';metaDataToBeVerified[1]= 'S';metaDataToBeVerified[2]= ':';metaDataToBeVerified[3]= '\0'; getString(PAGE_SIZE,returnData); strcat(metaDataToBeVerified,returnData); strcat(metaDataToBeVerified,";"); memset(returnData,'\0',100); strcat(metaDataToBeVerified,"NP:"); getString(totalNoOfPages,returnData); strcat(metaDataToBeVerified,returnData); strcat(metaDataToBeVerified,";"); readMetaDataFromFile(fileName,metaDataFromFile); ASSERT_TRUE((strcmp(metaDataToBeVerified, metaDataFromFile) == 0), "MetaData read from file is correct"); printf("Read Meta Data from file is :: %s\n",metaDataToBeVerified); //[END] TEST_CHECK(destroyPageFile(TESTPF)); free(ph); TEST_DONE(); }