BTreeFile::BTreeFile (Status& returnStatus, const char *filename) { Status st; st = MINIBASE_DB->get_file_entry(filename, headerPageId); if (st != OK) { returnStatus = MINIBASE_FIRST_ERROR(BTREE, CANT_FIND_HEADER); return; } st = MINIBASE_BM->pinPage(headerPageId, (Page *&) headerPage); if (st != OK) { returnStatus = MINIBASE_FIRST_ERROR(BTREE, CANT_PIN_HEADER); return; } dbname = strcpy(new char[strlen(filename)+1],filename); assert(headerPage->magic0 == (unsigned)MAGIC0); // ASSERTIONS: /* * * - headerPageId is the PageId of this BTreeFile's header page; * - headerPage, headerPageId valid and pinned * - dbname contains a copy of the name of the database */ returnStatus = OK; }
// ********************************************************** // returns length and pointer to record with RID rid. The difference // between this and getRecord is that getRecord copies out the record // into recPtr, while this function returns a pointer to the record // in recPtr. Status HFPage::returnRecord(RID rid, char*& recPtr, int& recLen) { // fill in the body if(rid.slotNo < 0 || rid.pageNo < 0) return MINIBASE_FIRST_ERROR(HEAPFILE, INVALID_SLOTNO); //return FAIL; if(rid.slotNo >= this->slotCnt) return MINIBASE_FIRST_ERROR(HEAPFILE, INVALID_SLOTNO); //return FAIL; if(rid.slotNo == 0) { recLen = this->slot[0].length; if(recLen == EMPTY_SLOT) return DONE; recPtr = &(this->data[this->slot[0].offset]); } else { slot_t * tmpSlot = (slot_t *)&(this->data[(rid.slotNo - 1) * sizeof(slot_t)]); recLen = tmpSlot->length; if(recLen == EMPTY_SLOT) return DONE; recPtr = &(this->data[tmpSlot->offset]); } return OK; }
Status BTreeFile::destroyFile () { Status st; if (headerPage->root != INVALID_PAGE) { // if tree non-empty st = _destroyFile(headerPage->root); if (st != OK) return st; // if it encountered an error, it would've added it } st = MINIBASE_BM->unpinPage(headerPageId); if (st != OK) MINIBASE_FIRST_ERROR(BTREE, CANT_UNPIN_PAGE); PageId hdrId = headerPageId; // Deal with the possibility // that the freePage might fail. headerPageId = INVALID_PAGE; headerPage = NULL; st = MINIBASE_BM->freePage(hdrId); if (st != OK) MINIBASE_FIRST_ERROR(BTREE, CANT_FREE_PAGE); st = MINIBASE_DB->delete_file_entry(dbname); if (st != OK) MINIBASE_FIRST_ERROR(BTREE, CANT_DELETE_FILE_ENTRY); // the destructor will take care of freeing the memory at dbname return OK; }
// ********************************************************** // Delete a record from a page. Returns OK if everything went okay. // Compacts remaining records but leaves a hole in the slot array. // Use memmove() rather than memcpy() as space may overlap. Status HFPage::deleteRecord(const RID& rid) { // fill in the body //--- deal with errors ---- if(rid.pageNo < 0 || rid.slotNo < 0) return MINIBASE_FIRST_ERROR(HEAPFILE, INVALID_SLOTNO); //return FAIL; if(rid.slotNo >= this->slotCnt) return MINIBASE_FIRST_ERROR(HEAPFILE, INVALID_SLOTNO); //return FAIL; //--- deal with empty page case --- if(empty()) return MINIBASE_FIRST_ERROR(HEAPFILE, NO_RECORDS); //return FAIL; //--- get record offset --- int offset = getRecordOffset(rid); //--- clean corresponding slot & get record length--- int len = cleanSlot(rid); //--- deal with already deleted case --- if(offset == INVALID_SLOT || len == EMPTY_SLOT) return MINIBASE_FIRST_ERROR(HEAPFILE, ALREADY_DELETED); //return FAIL; //-- shrink slot directory --- shrinkSlotDir(); //--- delete record & relocate behind records & slot dir --- //--- & update usedPtr, freeSpace ----- deleteRec(offset, len); return OK; }
Status BufMgr::unpinPage(PageId page_num, int dirty=FALSE, int hate = FALSE){ int i = hashTable->find(page_num); ts++; if (i == -1) { MINIBASE_FIRST_ERROR(BUFMGR, FAIL); return FAIL; } else if (bufDescr[i]->pinCount == 0) { MINIBASE_FIRST_ERROR(BUFMGR, FAIL); return FAIL; } else { bufDescr[i]->ts = ts; bufDescr[i]->dirty |= dirty; bufDescr[i]->loved |= !hate; bufDescr[i]->pinCount--; if (bufDescr[i]->pinCount == 0) { lhm->put(page_num, bufDescr[i]->ts, bufDescr[i]->loved); } } return OK; }
// ********************************************************** // Add a new record to the page. Returns OK if everything went OK // otherwise, returns DONE if sufficient space does not exist // RID of the new record is returned via rid parameter. Status HFPage::insertRecord(char* recPtr, int recLen, RID& rid) { // fill in the body //--- check if does not have enough free Space ---- //--- get empty slot no --- int emptySlotNo = getEmptySlotNo(); if((int)this->freeSpace < recLen + (int)sizeof(slot_t) && emptySlotNo == -1) { return MINIBASE_FIRST_ERROR(HEAPFILE, NO_SPACE); //return DONE; } else if((int)this->freeSpace < recLen && emptySlotNo != -1) { return MINIBASE_FIRST_ERROR(HEAPFILE, NO_SPACE); //return DONE; } else { //--- check if is the first record on page--- if(this->slotCnt == 0) { //--- modify RID value ---- rid.pageNo = this->curPage; rid.slotNo = this->slotCnt; //--- add new slot ---- modifySlot(0, recLen); //--- add the record data into page ---- addData(0, recPtr, recLen); //--- update HFpage info --- this->slotCnt ++; } else { if(emptySlotNo == -1) { emptySlotNo = this->slotCnt; this->slotCnt ++; } //--- modify RID value --- rid.pageNo = this->curPage; rid.slotNo = emptySlotNo; //--- add new slot ---- modifySlot(emptySlotNo, recLen); //--- add the record data into page --- addData(emptySlotNo, recPtr, recLen); } //--- update HFpage info --- this->usedPtr = this->usedPtr - recLen; if(this->slotCnt == 1) this->freeSpace = MAX_SPACE - DPFIXED - recLen; else this->freeSpace = this->usedPtr - (this->slotCnt - 1) * sizeof(slot_t); return OK; } }
Status BufMgr::unpinPage(PageId page_num, int dirty=FALSE, int hate = FALSE){ // put your code here void *qptr; Status st; int framein = h.lookup(page_num); //cout << "framein :: "<< framein << endl; if(framein !=-1){ // set dirty bit fro fram if its true if(dirty==TRUE){ bufDescr[framein].dirtybit = dirty; st =MINIBASE_DB->write_page(page_num, &bufPool[framein]); if(st!=OK){ return MINIBASE_CHAIN_ERROR(BUFMGR, st); } } // decrement pin count for frame if its greater than 0 if(bufDescr[framein].pin_count>0){ --(bufDescr[framein].pin_count); }else{ return FAIL; } st = blist.insert(!hate, page_num, framein); if(st!=OK){ MINIBASE_FIRST_ERROR(BUFMGR,LISTINSERT_ERROR); }return OK; } return FAIL; }
Status BTreeFile::_destroyFile (PageId pageno) { Status st; SortedPage *pagep; st = MINIBASE_BM->pinPage(pageno, (Page *&) pagep); if (st != OK) return MINIBASE_FIRST_ERROR(BTREE, CANT_PIN_PAGE); NodeType ndtype = pagep->get_type(); if (ndtype == INDEX) { RID rid; PageId childId; BTIndexPage* ipagep = (BTIndexPage *) pagep; for (st = ipagep->get_first(rid, NULL, childId); st != NOMORERECS; st = ipagep->get_next(rid, NULL, childId)) { Status tmpst = _destroyFile(childId); if (tmpst != OK) { MINIBASE_FIRST_ERROR(BTREE, CANT_DELETE_SUBTREE); } } } else { assert(ndtype == LEAF); } // ASSERTIONS: // - if pagetype == INDEX: the subtree rooted at pageno is completely // destroyed st = MINIBASE_BM->unpinPage(pageno); if (st != OK) return MINIBASE_FIRST_ERROR(BTREE, CANT_UNPIN_PAGE); st = MINIBASE_BM->freePage(pageno); if (st != OK) return MINIBASE_FIRST_ERROR(BTREE, CANT_FREE_PAGE); // ASSERTIONS: // - pageno invalid and set free return OK; }
Status DB::read_page(PageId pageno, Page* pageptr) { #ifdef DEBUG cout << "Reading page " << pageno << endl; #endif if ((pageno < 0) || (pageno >= (int) num_pages)) return MINIBASE_FIRST_ERROR( DBMGR, BAD_PAGE_NO ); // Seek to the correct page if ( ::lseek( fd, pageno*MINIBASE_PAGESIZE, SEEK_SET ) < 0 ) return MINIBASE_FIRST_ERROR( DBMGR, UNIX_ERROR ); // Read the appropriate number of bytes. if ( ::read( fd, pageptr, MINIBASE_PAGESIZE ) != MINIBASE_PAGESIZE ) return MINIBASE_FIRST_ERROR( DBMGR, FILE_IO_ERROR ); return OK; }
BTreeFile::~BTreeFile () { delete [] dbname; if (headerPageId != INVALID_PAGE) { Status st = MINIBASE_BM->unpinPage(headerPageId); if (st != OK) MINIBASE_FIRST_ERROR(BTREE, CANT_UNPIN_PAGE); } }
Status DB::delete_file_entry(const char* fname) { #ifdef DEBUG cout << "Deleting the file entry for " << fname << endl; #endif char* pg = 0; Status status; directory_page* dp = 0; bool found = false; unsigned slot = 0; PageId hpid, nexthpid = 0; do { hpid = nexthpid; // Pin the header page. status = MINIBASE_BM->pinPage( hpid, (Page*&)pg ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); // This complication is because the first page has a different // structure from that of subsequent pages. dp = (hpid == 0)? &((first_page*)pg)->dir : (directory_page*)pg; nexthpid = dp->next_page; unsigned entry = 0; while ((entry < dp->num_entries) && ((dp->entries[entry].pagenum == INVALID_PAGE) || (strcmp(fname,dp->entries[entry].fname) != 0)) ) ++entry; if ( entry < dp->num_entries ) { slot = entry; found = true; } else { status = MINIBASE_BM->unpinPage( hpid ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); } } while ( nexthpid != INVALID_PAGE && !found ); if ( !found ) // Entry not found - nothing deleted return MINIBASE_FIRST_ERROR( DBMGR, FILE_NOT_FOUND ); // Have to delete record at hpnum:slot dp->entries[slot].pagenum = INVALID_PAGE; status = MINIBASE_BM->unpinPage( hpid, true /*dirty*/ ); if ( status != OK ) status = MINIBASE_CHAIN_ERROR( DBMGR, status ); return OK; }
void BTreeFile::printLeafPages() { Status st; BTLeafPage *leafp; RID dummy; // Find first leaf node. st = findRunStart( NULL, &leafp, &dummy ); if ( st != OK ) { cerr << "Error finding start of b-tree" << endl; return; } while ( leafp ) { printPage( leafp->page_no() ); PageId next = leafp->getNextPage(); st = MINIBASE_BM->unpinPage( leafp->page_no() ); if (st != OK) { MINIBASE_FIRST_ERROR(BTREE, BTreeFile::CANT_UNPIN_PAGE); cerr << "Can't unpin a b-tree page" << endl; return; } if ( next == INVALID_PAGE ) leafp = NULL; else { st = MINIBASE_BM->pinPage( next, (Page *&) leafp ); if (st != OK) { MINIBASE_FIRST_ERROR(BTREE, BTreeFile::CANT_PIN_PAGE); cerr << "Can't pin a b-tree page" << endl; return; } } } }
Status DB::deallocate_page(PageId start_page_num, int run_size) { #ifdef DEBUG cout << "Deallocating a run of " << run_size << " pages starting at " << start_page_num << endl; #endif if ( run_size < 0 ) { cerr << "Allocating a negative run of pages.\n"; return MINIBASE_FIRST_ERROR ( DBMGR, NEG_RUN_SIZE); } return set_bits( start_page_num, run_size, 0 ); }
Status BTreeFile::updateHeader (PageId newRoot) { Status st; BTreeHeaderPage *pheader; PageId old_data; st = MINIBASE_BM->pinPage(headerPageId, (Page *&) pheader); if (st != OK) return MINIBASE_FIRST_ERROR(BTREE, CANT_PIN_HEADER); old_data = pheader->root; pheader->root = newRoot; // clock in dirty bit to bm so our dtor needn't have to worry about it st = MINIBASE_BM->unpinPage(headerPageId, 1 /* = DIRTY */ ); if (st != OK) return MINIBASE_FIRST_ERROR(BTREE, CANT_UNPIN_HEADER); // ASSERTIONS: // - headerPage, headerPageId valid, pinned and marked as dirty return OK; }
Status SortedPage::deleteRecord (const RID& rid) { Status status; status=HFPage::deleteRecord(rid); if (status == OK) HFPage::compact_slot_dir(); else return MINIBASE_FIRST_ERROR(SORTEDPAGE, DELETE_REC_FAILED); // ASSERTIONS: // - slot directory is compacted return OK; }
DB::DB(const char* fname, Status& status) { #ifdef DEBUG cout << "opening database "<< fname << endl; #endif name = strcpy(new char[strlen(fname)+1],fname); // Open the file in both input and output mode. fd = ::open( name, O_RDWR ); if ( fd < 0 ) { status = MINIBASE_FIRST_ERROR( DBMGR, UNIX_ERROR ); return; } MINIBASE_DB = this; //set the global variable to be this. Status s; first_page* fp; num_pages = 1; // We initialize it to this. // We will know the real size after we read page 0. #ifdef BM_TRACE s = MINIBASE_BM->pinPage( 0, (Page*&)fp, false /*not empty*/, "*** DB admin ***" ); #else s = MINIBASE_BM->pinPage( 0, (Page*&)fp ); #endif if ( s != OK ) { status = MINIBASE_CHAIN_ERROR( DBMGR, s ); return; } num_pages = fp->num_db_pages; s = MINIBASE_BM->unpinPage( 0 ); if ( s != OK ) { status = MINIBASE_CHAIN_ERROR( DBMGR, s ); return; } status = OK; }
Status BufMgr::pinPage(PageId PageId_in_a_DB, Page*& page, int emptyPage) { int i = hashTable->find(PageId_in_a_DB); if (i != -1) { if (bufDescr[i]->pinCount == 0) { lhm->erase(PageId_in_a_DB, bufDescr[i]->ts, bufDescr[i]->loved); } bufDescr[i]->pinCount++; } else { if (!freeFrames.empty()) { i = freeFrames.back(); freeFrames.pop_back(); } else { i = lhm->findVictim(); if (i == -1) { MINIBASE_FIRST_ERROR(BUFMGR, FAIL); return FAIL; } i = hashTable->find(i); assert(i != -1); deleteFrame(i); } if (!emptyPage) { Status s = MINIBASE_DB->read_page(PageId_in_a_DB, &bufPool[i]); if (s != OK) { MINIBASE_CHAIN_ERROR(BUFMGR, s); freeFrames.push_back(i); return s; } } bufDescr[i] = new Descriptor(PageId_in_a_DB, ts, 1); hashTable->put(PageId_in_a_DB, i); } page = &bufPool[i]; return OK; }
Status BufMgr::freePage(PageId globalPageId){ int i = hashTable->find(globalPageId); if (i != -1) { if (bufDescr[i]->pinCount > 0) { MINIBASE_FIRST_ERROR(BUFMGR, FAIL); return FAIL; } freeFrames.push_back(i); } Status s = MINIBASE_DB->deallocate_page(globalPageId); if (s != OK) { MINIBASE_CHAIN_ERROR(BUFMGR, s); return s; } return OK; }
Status BTIndexPage::insertKey (const void *key, AttrType key_type, PageId pageNo, RID& rid) { KeyDataEntry entry; int entry_len; Datatype d; d.pageNo = pageNo; make_entry(&entry, key_type, key, (nodetype) type, d, &entry_len); if (SortedPage::insertRecord(key_type, (char*)&entry, entry_len, rid ) != OK) { return MINIBASE_FIRST_ERROR(BTINDEXPAGE, INDEXINSERTRECFAILED); } return OK; }
BTreeFile::BTreeFile (Status& returnStatus, const char *filename, const AttrType keytype, const int keysize, int delete_fashion) { Status st; st = MINIBASE_DB->get_file_entry(filename, headerPageId); if (st != OK) { // create new BTreeFile; first, get a header page. st = MINIBASE_BM->newPage(headerPageId, (Page *&) headerPage); if (st != OK) { headerPageId = INVALID_PAGE; headerPage = NULL; returnStatus = MINIBASE_FIRST_ERROR(BTREE, CANT_ALLOC_HEADER); return; } // now add btreefile to the naming service of the database st = MINIBASE_DB->add_file_entry(filename, headerPageId); if (st != OK) { headerPageId = INVALID_PAGE; headerPage = NULL; MINIBASE_BM->freePage(headerPageId); returnStatus = MINIBASE_FIRST_ERROR(BTREE, CANT_ADD_FILE_ENTRY); return; } // initialize headerpage; we actually never reference // prevPage or nextPage, though. ((HFPage*) headerPage)->init(headerPageId); ((HFPage*) headerPage)->setNextPage(INVALID_PAGE); ((HFPage*) headerPage)->setPrevPage(INVALID_PAGE); ((SortedPage*) headerPage)->set_type(LEAF); headerPage->magic0 = MAGIC0; headerPage->root = INVALID_PAGE; headerPage->key_type = keytype; headerPage->keysize = keysize; headerPage->delete_fashion = delete_fashion; } else { // open an existing btreefile st = MINIBASE_BM->pinPage(headerPageId, (Page *&) headerPage); if (returnStatus != OK) { returnStatus = MINIBASE_FIRST_ERROR(BTREE, CANT_PIN_HEADER); return; } assert(headerPage->magic0 == (unsigned)MAGIC0); } dbname = strcpy(new char[strlen(filename)+1],filename); // ASSERTIONS: /* * - headerPageId is the PageId of this BTreeFile's header page; * - headerPage points to the pinned header page (headerPageId) * - dbname contains the name of the database */ returnStatus = OK; }
Status SortedPage::insertRecord (AttrType key_type, char * recPtr, int recLen, RID& rid) { Status status; int i; // ASSERTIONS: // - the slot directory is compressed -> inserts will occur at the end // - slotCnt gives the number of slots used // general plan: // 1. Insert the record into the page, // which is then not necessarily any more sorted // 2. Sort the page by rearranging the slots (insertion sort) status = HFPage::insertRecord(recPtr, recLen, rid); //fprintf(stderr, "###sorted page start###\n"); //dumpPage(); if (status != OK) return MINIBASE_FIRST_ERROR(SORTEDPAGE, INSERT_REC_FAILED); assert(rid.slotNo == (slotCnt-1)); #ifdef MULTIUSER char tmp_buf[DPFIXED]; memcpy(tmp_buf,(void*)&slot[0], DPFIXED); #endif // performs a simple insertion sort for (i=slotCnt-1; i > 0; i--) { char *key_i = data + slot[-i].offset; char *key_iplus1 = data + slot[-(i-1)].offset; if (keyCompare((void*)key_i, (void*) key_iplus1, key_type) < 0) { // switch slots: slot_t tmp_slot; tmp_slot = slot[-i]; slot[-i] = slot[-(i-1)]; slot[-(i-1)] = tmp_slot; } else { // end insertion sort break; } } // ASSERTIONS: // - record keys increase with increasing slot number (starting at slot 0) // - slot directory compacted rid.slotNo = i; #ifdef MULTIUSER status = MINIBASE_RECMGR->WriteUpdateLog(DPFIXED, curPage,sizeof data, tmp_buf,(char*)&slot[0], (Page*) this); if (status != OK) return MINIBASE_CHAIN_ERROR(BTREE,status); #endif //fprintf(stderr, "###sorted page end ###\n"); //dumpPage(); return OK; }
Status BTreeFile::insert (const void *key, const RID rid) { Status returnStatus; KeyDataEntry newRootEntry; int newRootEntrySize; KeyDataEntry* newRootEntryPtr = &newRootEntry; if (get_key_length(key, headerPage->key_type) > headerPage->keysize) return MINIBASE_FIRST_ERROR(BTREE, KEY_TOO_LONG); // TWO CASES: // 1. headerPage->root == INVALID_PAGE: // - the tree is empty and we have to create a new first page; // this page will be a leaf page // 2. headerPage->root != INVALID_PAGE: // - we call _insert() to insert the pair (key, rid) PageId shit; if (headerPage->root == INVALID_PAGE) { // TODO: fill the body PageId rootPageId = -1; BTLeafPage* rootLeafPage = NULL; Status st = MINIBASE_BM->newPage( (PageId&)rootPageId, (Page*&)rootLeafPage ); rootLeafPage->init( rootPageId); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); assert( st == OK); assert( rootPageId != -1); rootLeafPage->init( rootPageId); headerPage->root = rootPageId; st = MINIBASE_BM->unpinPage( headerPage->root, TRUE ); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); shit = rootPageId; // return OK; } returnStatus = _insert(key, rid, &newRootEntryPtr, &newRootEntrySize, headerPage->root); if (returnStatus != OK) MINIBASE_FIRST_ERROR(BTREE, INSERT_FAILED); // TWO CASES: // - newRootEntryPtr != NULL: a leaf split propagated up to the root // and the root split: the new pageNo is in // newChildEntry->data->pageNo // - newRootEntryPtr == NULL: no new root was created; // information on headerpage is still valid if (newRootEntryPtr != NULL) { // TODO: fill the body fprintf(stdout, "key_data_entry goingup: %d %d\n", newRootEntryPtr->key.intkey, newRootEntryPtr->data.pageNo); BTIndexPage* rootIndexPage = NULL; PageId rootPageId; Status st = MINIBASE_BM->newPage( (PageId&)rootPageId, (Page*&)rootIndexPage ); rootIndexPage->init( rootPageId); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); assert( st == OK); rootIndexPage->setLeftLink( headerPage->root ); RID dummyRid; st = rootIndexPage->insertKey( (void*)(&newRootEntryPtr->key), headerPage->key_type , newRootEntryPtr->data.pageNo, dummyRid); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); // headerPage->root = newRootEntryPtr->data.pageNo; headerPage->root = rootPageId; st = MINIBASE_BM->unpinPage( rootIndexPage->page_no(), TRUE ); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); fprintf(stdout, "end of new index first!!!\n"); } return OK; }
Status BufMgr::pinPage(PageId PageId_in_a_DB, Page*& page, int emptyPage) { // put your code here int result = h.lookup(PageId_in_a_DB); // Page is not in buffer pool if(result==-1){ int freefrm = -1; int frmno = -1; for ( int i = 0; i < numbuffer; ++i ) { if ( (bufDescr[i].PageNumber == INVALID_PAGE) ) { frmno = i; break; } } if ( (frmno != -1) && (frmno < numbuffer) ) { freefrm = frmno; }else{ // for ( int i = 0; i < numbuffer; ++i ) // { // if ( (bufDescr[i].pin_count == 0) ) // { // frmno = i; // break; // } // } Status st; st = blist.lookup(&freefrm); if(st!=OK){ return MINIBASE_FIRST_ERROR(BUFMGR,LISTSEARCH_ERROR); } if ( (frmno != -1) && (frmno < numbuffer) ) { freefrm = frmno; } Page *pageptr = &bufPool[freefrm]; //Status st; if(bufDescr[freefrm].dirtybit){ st = MINIBASE_DB->write_page(bufDescr[freefrm].PageNumber, pageptr); } if(st != OK){ return FAIL; } if(bufDescr[freefrm].pin_count>0){ return FAIL; } h.remove(bufDescr[freefrm].PageNumber); } page = &bufPool[freefrm]; Status st; st = MINIBASE_DB->read_page(PageId_in_a_DB,page); if(st !=OK){ return FAIL; } //bufPool[freefrm]=*page; h.insert(PageId_in_a_DB,freefrm); bufDescr[freefrm].PageNumber = PageId_in_a_DB; (bufDescr[freefrm].pin_count)++; bufDescr[freefrm].dirtybit = false; }else{ // Page is in buffer pool ++bufDescr[result].pin_count; int pno = bufDescr[result].PageNumber; Page *pptr = &bufPool[result]; if(bufDescr[result].dirtybit == true){ MINIBASE_DB->write_page(pno, pptr); } bufDescr[result].dirtybit = 0; page = &bufPool[result]; } return OK; }//end pinPage
Status BTreeFile::_insert (const void *key, const RID rid, KeyDataEntry **goingUp, int *goingUpSize, PageId currentPageId) { Status st; SortedPage* rpPtr; assert(currentPageId != INVALID_PAGE); assert(*goingUp != NULL); st = MINIBASE_BM->pinPage(currentPageId,(Page *&) rpPtr); if (st != OK) return MINIBASE_FIRST_ERROR(BTREE, CANT_PIN_PAGE); NodeType pageType = rpPtr->get_type(); cerr<< "currentPageId IN _INSERT "<< currentPageId<<" pageType "<< pageType<<endl; // TWO CASES: // - pageType == INDEX: // recurse and then split if necessary // - pageType == LEAF: // try to insert pair (key, rid), maybe split switch (pageType) { case INDEX: { // two cases: // - *goingUp == NULL: one level lower no split has occurred: // we are done. // - *goingUp != NULL: one of the children has split and // **goingUp is the new data entry which has // to be inserted on this index page // TODO: fill the body BTIndexPage* indexPage = (BTIndexPage*) rpPtr; RID myRid; KeyDataEntry* newEntry = new KeyDataEntry(); int newEntrySize; PageId pageId; indexPage->get_page_no( key, headerPage->key_type, pageId); printf("in index page insert to %d\n", pageId); fflush(stdout); Status returnStatus = _insert(key, rid, &newEntry , &newEntrySize, pageId); if (returnStatus != OK) MINIBASE_FIRST_ERROR(BTREE, INSERT_FAILED); if( newEntry != NULL){ if( indexPage->available_space() >= newEntrySize){ st = indexPage->insertKey( (void*)(&newEntry->key), headerPage->key_type, newEntry->data.pageNo, myRid); if(st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); } else{ //pageFUll: //new a Indexpage "RightSibling" cout<<"*************************index_split"<<endl; BTIndexPage* rightSiblingIndexPage; PageId rightPageId; Status st; st = MINIBASE_BM->newPage( rightPageId, (Page*&)rightSiblingIndexPage ); rightSiblingIndexPage->init( rightPageId); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); assert( st == OK); //chose a mediate_key to push up int numLeft = (indexPage->numberOfRecords()+1)/2; int numRight = indexPage->numberOfRecords()+1-numLeft; RID metaRid; Keytype iterKey; PageId iterPage; st = indexPage->get_first( metaRid, &iterKey, iterPage); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); assert( st == OK); RID dummyRid; RID leftLastRid; Keytype medKey; PageId medPage; bool entryInserted = false; for( int i = 0 ; i < numLeft-1 ; i++){ st = indexPage->get_next( metaRid, &iterKey, iterPage); } if( !entryInserted && keyCompare( &(newEntry->key), &iterKey, headerPage->key_type) <=0){ //newEntry is in the left half st = indexPage->insertKey( (void*)(&newEntry->key), headerPage->key_type, newEntry->data.pageNo, dummyRid ); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); medKey = iterKey; medPage = iterPage; st = indexPage->deleteKey( &iterKey, headerPage->key_type, dummyRid); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); st = indexPage->get_next( metaRid, &iterKey, iterPage); entryInserted = true; } else{ // this is the middle key st = indexPage->get_next( metaRid, &iterKey, iterPage); if( !entryInserted && keyCompare( &(newEntry->key), &iterKey, headerPage->key_type) <=0){ medKey = newEntry->key; medPage = newEntry->data.pageNo; } else{ medKey = iterKey; medPage = iterPage; rightSiblingIndexPage->insertKey( (void*)&(newEntry->key), headerPage->key_type, newEntry->data.pageNo, dummyRid ); indexPage->deleteKey( &iterKey, headerPage->key_type, dummyRid); st = indexPage->get_next( metaRid, &iterKey, iterPage); entryInserted = true; } } while( st == OK){ st = indexPage->deleteKey( &iterKey, headerPage->key_type, dummyRid); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); st = rightSiblingIndexPage->insertKey( (void*)&iterKey, headerPage->key_type, iterPage, dummyRid ); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); st = indexPage->get_next( metaRid, &iterKey, iterPage); } rightSiblingIndexPage->setLeftLink( medPage); KeyDataEntry newEntry; Datatype entryData; entryData.pageNo = rightSiblingIndexPage->page_no(); int entryLen; make_entry( &newEntry, headerPage->key_type, (void*)&medKey,INDEX, entryData, &entryLen); **goingUp = newEntry; *goingUpSize = entryLen; st = MINIBASE_BM->unpinPage( rightPageId, TRUE ); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); } } else{ *goingUp = NULL; printf("index do not split\n"); } break; } case LEAF: { BTLeafPage* leafPage = (BTLeafPage*) rpPtr; RID myRid; if( leafPage->available_space() >= sizeof(KeyDataEntry)){ Status myst = leafPage->insertRec(key, headerPage->key_type, rid, myRid); if(myst != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); *goingUp = NULL; } else{ //split fprintf(stderr, "leaf split start >>>>>>>>"); cout<<"**************************leaf_split"<<endl; printPage(currentPageId); int numberRec = leafPage->numberOfRecords(); BTLeafPage* newRight; // BTIndexPage* newRoot; Status myst; PageId newRightID; void* currentKey; RID currentDataRID; if((myst = MINIBASE_BM->newPage(newRightID, (Page*&)newRight)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); newRight->init(newRightID); RID firstRID; RID tmp; void* middleKey; RID middleDataRID; if((myst = leafPage->get_first(firstRID, currentKey, currentDataRID)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); int board = (numberRec)/2; for(int i = 1; i < board; i++){ if(myst != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); if((myst = leafPage->get_next(firstRID, currentKey, currentDataRID)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); } int k = 0; for(int j = board; j < numberRec; j++){ void* tmpKey = (void*) malloc(sizeof(currentKey)); memcpy(tmpKey, currentKey, sizeof(currentKey)); if(myst != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); if(j == board){ if((myst = leafPage->get_next(firstRID, currentKey, currentDataRID)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); } else{ leafPage->delUserRid(tmpKey, headerPage->key_type, currentDataRID); if((myst = leafPage->get_current(firstRID, currentKey, currentDataRID)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); } myst = newRight->insertRec(currentKey, headerPage->key_type, currentDataRID, tmp); if(myst != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); } leafPage->delUserRid(currentKey, headerPage->key_type, currentDataRID); if((myst = newRight->get_first(firstRID, currentKey, currentDataRID)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); middleKey = currentKey; middleDataRID = currentDataRID; if(keyCompare(key, middleKey, headerPage->key_type)>0){ myst = newRight->insertRec(key, headerPage->key_type, rid, tmp); if(myst != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); } else if(keyCompare(key, currentKey, headerPage->key_type) == 0){ assert("key values equal!!"); } else{ myst = leafPage->insertRec(key, headerPage->key_type, rid, tmp); if(myst != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); } PageId pre = leafPage->getPrevPage(); PageId nex = leafPage->getNextPage(); fprintf(stdout, "pre = %d\nnex = %d\n", pre, nex); newRight->setPrevPage(currentPageId); leafPage->setNextPage(newRightID); // fprintf(stdout, "c = %d\nn = %d\n", currentPageId, newRightID); BTLeafPage* tmpPage; if(nex >= 0){ if((myst = MINIBASE_BM->pinPage(nex,(Page *&) tmpPage)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); // tmpPage->init(newRightID); ((BTLeafPage*)tmpPage)->setPrevPage(newRightID); newRight->setNextPage(nex); fprintf(stdout, "before unpin\n"); if((myst = MINIBASE_BM->unpinPage(nex, TRUE)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); fprintf(stdout, "afterpin\n"); } fflush(stdout); if((myst = newRight->get_first(firstRID, currentKey, currentDataRID)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); fprintf(stderr, "\nysysys\n"); middleKey = currentKey; middleDataRID = currentDataRID; // KeyDataEntry* newEntry = (KeyDataEntry*)malloc(sizeof(KeyDataEntry)); KeyDataEntry newEntry; Datatype entryData; Keytype entryKey; entryData.pageNo = newRightID; fprintf(stderr, "sure:[%d]\n", entryData.pageNo); int entryLen; make_entry( &newEntry, headerPage->key_type, middleKey,INDEX,entryData, &entryLen); // make_entry( &newEntry, headerPage->key_type, middleKey,INDEX, newRightID, &entryLen); // (newEntry->key).intkey = *(int*)middleKey; // (newEntry->data).pageNo = newRightId; newEntry.data.pageNo=newRightID; // fprintf(stderr, "in leaf dataentry:should be [%d] [%d] but: [%d] [%d]\n",*((int*)middleKey), newRightID , newEntry.key.intkey, newEntry.data.pageNo); **goingUp = newEntry; // newEntry.data.pageNo = 1; *goingUpSize = entryLen; if((myst = MINIBASE_BM->unpinPage(newRightID, TRUE)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, myst); fprintf(stderr,"\t leaf split end\n"); printPage(currentPageId); printPage(newRightID); } break; } default: // in case memory is scribbled upon & type is hosed fprintf(stderr, "currentPageId = (%d) pagetype%d\n", currentPageId, pageType ); assert(false); } if((st = MINIBASE_BM->unpinPage(currentPageId, TRUE)) != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); return OK; }
Status DB::set_bits( PageId start_page, unsigned run_size, int bit ) { if ((start_page < 0) || (start_page+run_size > num_pages)) return MINIBASE_FIRST_ERROR( DBMGR, BAD_PAGE_NO ); #ifdef DEBUG printf("set_bits:: space_map_before \n"); dump_space_map(); #endif // Locate the run within the space map. int first_map_page = start_page / bits_per_page + 1; int last_map_page = (start_page+run_size-1) / bits_per_page + 1; unsigned first_bit_no = start_page % bits_per_page; // The outer loop goes over all space-map pages we need to touch. for ( PageId pgid=first_map_page; pgid <= last_map_page; ++pgid, first_bit_no=0 ) { Status status; // Pin the space-map page. char* pg; status = MINIBASE_BM->pinPage( pgid, (Page*&)pg ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); // Locate the piece of the run that fits on this page. unsigned first_byte_no = first_bit_no / 8; unsigned first_bit_offset = first_bit_no % 8; int last_bit_no = first_bit_no + run_size - 1; if ( last_bit_no >= bits_per_page ) last_bit_no = bits_per_page - 1; unsigned last_byte_no = last_bit_no / 8; // Find the start of this page's piece of the run. char* p = pg + first_byte_no; char* end = pg + last_byte_no; // This loop actually flips the bits on the current page. for ( ; p <= end; ++p, first_bit_offset=0 ) { unsigned max_bits_this_byte = 8 - first_bit_offset; unsigned num_bits_this_byte = (run_size > max_bits_this_byte? max_bits_this_byte : run_size); unsigned mask = ((1 << num_bits_this_byte) - 1) << first_bit_offset; if ( bit ) *p |= mask; else *p &= ~mask; run_size -= num_bits_this_byte; } // Unpin the space-map page. status = MINIBASE_BM->unpinPage( pgid, true /*dirty*/ ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); } #ifdef DEBUG printf("set_bits:: space_map_afterwards \n"); dump_space_map(); #endif return OK; }
Status BTreeFile::naiveDelete (const void *key, const RID rid) { BTLeafPage *leafp; RID curRid; // iterator Status st; Keytype curkey; RID dummyRid; PageId nextpage; bool deleted; #ifdef BT_TRACE cerr << "DELETE " << rid.pageNo << " " << rid.slotNo << " " << (char*)key << endl; cerr << "DO" << endl; cerr << "SEARCH" << endl; #endif st = findRunStart(key, &leafp, &curRid); // find first page,rid of key if (st != OK) return MINIBASE_FIRST_ERROR(BTREE, DELETE_DATAENTRY_FAILED); leafp->get_current(curRid, &curkey, dummyRid); while (keyCompare(key, &curkey, headerPage->key_type) == 0) { deleted = leafp->delUserRid(key, headerPage->key_type, rid); if (deleted) { // successfully found <key, rid> on this page and deleted it. // unpin dirty page and return OK. st = MINIBASE_BM->unpinPage(leafp->page_no(), TRUE /* = DIRTY */); if (st != OK) { fprintf(stdout, "error1\n"); MINIBASE_FIRST_ERROR(BTREE, CANT_UNPIN_PAGE); return MINIBASE_FIRST_ERROR(BTREE, DELETE_DATAENTRY_FAILED); } #ifdef BT_TRACE cerr << "TAKEFROM node " << leafp->page_no() << endl; cerr << "DONE" << endl; #endif return OK; } nextpage = leafp->getNextPage(); st = MINIBASE_BM->unpinPage(leafp->page_no()); if (st != OK) { fprintf(stdout, "error2\n"); MINIBASE_FIRST_ERROR(BTREE, CANT_UNPIN_PAGE); return MINIBASE_FIRST_ERROR(BTREE, DELETE_DATAENTRY_FAILED); } st = MINIBASE_BM->pinPage(nextpage, (Page *&) leafp); if (st != OK) { fprintf(stdout, "error3\n"); MINIBASE_FIRST_ERROR(BTREE, CANT_PIN_PAGE); return MINIBASE_FIRST_ERROR(BTREE, DELETE_DATAENTRY_FAILED); } leafp->get_first(curRid, &curkey, dummyRid); } /* * We reached a page with first key > `key', so return an error. * We should have got true back from delUserRid above. Apparently * the specified <key,rid> data entry does not exist. */ fprintf(stdout, "error4\n"); st = MINIBASE_BM->unpinPage(leafp->page_no()); if (st != OK) MINIBASE_FIRST_ERROR(BTREE, CANT_UNPIN_PAGE); return MINIBASE_FIRST_ERROR(BTREE, DELETE_DATAENTRY_FAILED); }
DB::DB( const char* fname, unsigned num_pgs, Status& status ) { #ifdef DEBUG cout << "Creating database " << fname << " with pages " << num_pgs <<endl; #endif name = strcpy(new char[strlen(fname)+1],fname); num_pages = (num_pgs > 2) ? num_pgs : 2; // Create the file; fail if it's already there; open it in read/write // mode. fd = ::open( name, O_RDWR | O_CREAT | O_EXCL, 0666 ); if ( fd < 0 ) { status = MINIBASE_FIRST_ERROR( DBMGR, UNIX_ERROR ); return; } // Make the file num_pages pages long, filled with zeroes. char zero = 0; ::lseek( fd, (num_pages*MINIBASE_PAGESIZE)-1, SEEK_SET ); ::write( fd, &zero, 1 ); // Initialize space map and directory pages. MINIBASE_DB = this; //set the global variable to be this. Status s; first_page* fp; #ifdef BM_TRACE s = MINIBASE_BM->pinPage( 0, (Page*&)fp, true /*==empty*/, "*** DB admin ***" ); #else s = MINIBASE_BM->pinPage( 0, (Page*&)fp, true /*==empty*/ ); #endif if ( s != OK ) { status = MINIBASE_CHAIN_ERROR( DBMGR, s ); return; } fp->num_db_pages = num_pages; init_dir_page( &fp->dir, sizeof *fp ); s = MINIBASE_BM->unpinPage( 0, true /*==dirty*/ ); if ( s != OK ) { status = MINIBASE_CHAIN_ERROR( DBMGR, s ); return; } // Calculate how many pages are needed for the space map. Reserve pages // 0 and 1 and as many additional pages for the space map as are needed. unsigned num_map_pages = (num_pages + bits_per_page - 1) / bits_per_page; status = set_bits( 0, 1 + num_map_pages, 1 ); }
Status DB::add_file_entry(const char* fname, PageId start_page_num) { #ifdef DEBUG cout << "Adding a file entry: " << fname << " : " << start_page_num << endl; #endif // Is the info kosher? if ( strlen(fname) >= MAX_NAME ) return MINIBASE_FIRST_ERROR( DBMGR, FILE_NAME_TOO_LONG ); if ((start_page_num < 0) || (start_page_num >= (int) num_pages) ) return MINIBASE_FIRST_ERROR( DBMGR, BAD_PAGE_NO ); // Does the file already exist? PageId tmp; if ( get_file_entry(fname,tmp) == OK ) return MINIBASE_FIRST_ERROR( DBMGR, DUPLICATE_ENTRY ); char *pg = 0; Status status; directory_page* dp = 0; bool found = false; unsigned free_slot = 0; PageId hpid, nexthpid = 0; do { hpid = nexthpid; // Pin the header page. status = MINIBASE_BM->pinPage( hpid, (Page*&)pg ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); // This complication is because the first page has a different // structure from that of subsequent pages. dp = (hpid == 0)? &((first_page*)pg)->dir : (directory_page*)pg; nexthpid = dp->next_page; unsigned entry = 0; while ( (entry < dp->num_entries) && (dp->entries[entry].pagenum != INVALID_PAGE)) ++entry; if ( entry < dp->num_entries ) { free_slot = entry; found = true; } else if ( nexthpid != INVALID_PAGE ) { // We only unpin if we're going to continue looping. status = MINIBASE_BM->unpinPage( hpid ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); } } while ( nexthpid != INVALID_PAGE && !found ); // Have to add a new header page if possible. if ( !found ) { status = allocate_page( nexthpid ); if ( status != OK ) { MINIBASE_BM->unpinPage( hpid ); return status; } // Set the next-page pointer on the previous directory page. dp->next_page = nexthpid; status = MINIBASE_BM->unpinPage( hpid, true /*dirty*/ ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); // Pin the newly-allocated directory page. hpid = nexthpid; status = MINIBASE_BM->pinPage( hpid, (Page*&)pg, true /*empty*/ ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); dp = (directory_page*)pg; init_dir_page( dp, sizeof(directory_page) ); free_slot = 0; } // At this point, "hpid" has the page id of the header page with the free // slot; "pg" points to the pinned page; "dp" has the directory_page // pointer; "free_slot" is the entry number in the directory where we're // going to put the new file entry. dp->entries[free_slot].pagenum = start_page_num; strcpy( dp->entries[free_slot].fname, fname ); status = MINIBASE_BM->unpinPage( hpid, true /*dirty*/ ); if ( status != OK ) status = MINIBASE_CHAIN_ERROR( DBMGR, status ); return status; }
Status BTreeFile::findRunStart (const void *lo_key, BTLeafPage **pppage, RID *pstartrid) { BTLeafPage *ppage; BTIndexPage *ppagei; PageId pageno; PageId curpage; // iterator PageId prevpage; PageId nextpage; RID metaRid, curRid; Keytype curkey; Status st; AttrType key_type = headerPage->key_type; KeyDataEntry curEntry; pageno = headerPage->root; if (pageno == INVALID_PAGE){ // no pages in the BTREE *pppage = NULL; // should be handled by pstartrid = NULL; // the caller return OK; } st = MINIBASE_BM->pinPage(pageno, (Page *&) ppagei); if (st != OK) return MINIBASE_FIRST_ERROR(BTREE, CANT_PIN_PAGE); while (ppagei->get_type() == INDEX) { // TODO: fill the body if( lo_key == NULL) st = ppagei->get_first( metaRid, (void*)&curkey, nextpage ); else{ st = ppagei->get_page_no( (void*)&curkey, headerPage->key_type, nextpage); } assert( st ==OK); st = MINIBASE_BM->pinPage( nextpage, (Page*&) ppagei); assert( st ==OK); } assert(ppagei); assert(ppagei->get_type() == LEAF); ppage = (BTLeafPage *) ppagei; st = ppage->get_first(metaRid, &curkey, curRid); while (st == NOMORERECS) { // TODO: fill the body PageId nextPageId = ppage->getNextPage(); if( nextPageId == INVALID_PAGE){ *pppage = NULL; return OK; } st = MINIBASE_BM->unpinPage( ppage->page_no(), TRUE ); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); st = MINIBASE_BM->pinPage(nextPageId, (Page *&) ppage); if( st != OK) return MINIBASE_CHAIN_ERROR(BTREE, st); st = ppage->get_first(metaRid, &curkey, curRid); } if (lo_key == NULL) { *pppage = ppage; *pstartrid = metaRid; return OK; // note that pageno/ppage is still pinned; scan will unpin it when done } while (keyCompare(&curkey, lo_key, key_type) < 0) { // TODO: fill the body st = ppage->get_next( metaRid, &curkey, curRid); if( st == NOMORERECS) break; } *pppage = ppage; *pstartrid = metaRid; return OK; }
Status DB::allocate_page(PageId& start_page_num, int run_size_int) { #ifdef DEBUG cout << "Allocating a run of "<< run_size << " pages." << endl; #endif if ( run_size_int < 0 ) { cerr << "Allocating a negative run of pages.\n"; return MINIBASE_FIRST_ERROR ( DBMGR, NEG_RUN_SIZE ); } unsigned run_size = run_size_int; unsigned num_map_pages = (num_pages + bits_per_page - 1) / bits_per_page; unsigned current_run_start = 0, current_run_length = 0; // This loop goes over each page in the space map. Status status; for( unsigned i=0; i < num_map_pages; ++i ) { PageId pgid = 1 + i; // The space map starts at page #1. // Pin the space-map page. char* pg; status = MINIBASE_BM->pinPage( pgid, (Page*&)pg ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); // How many bits should we examine on this page? int num_bits_this_page = num_pages - i*bits_per_page; if ( num_bits_this_page > bits_per_page ) num_bits_this_page = bits_per_page; // Walk the page looking for a sequence of 0 bits of the appropriate // length. The outer loop steps through the page's bytes, the inner // one steps through each byte's bits. for ( ; num_bits_this_page > 0 && current_run_length < run_size; ++pg ) for ( unsigned mask=1; (mask < 256) && (num_bits_this_page > 0) && (current_run_length < run_size); mask <<= 1, --num_bits_this_page ) if ( *pg & mask ) { current_run_start += current_run_length + 1; current_run_length = 0; } else ++current_run_length; // Unpin the space-map page. status = MINIBASE_BM->unpinPage( pgid ); if ( status != OK ) return MINIBASE_CHAIN_ERROR( DBMGR, status ); } if ( current_run_length >= run_size ) { start_page_num = current_run_start; #ifdef DEBUG cout<<"Page allocated in get_free_pages:: "<< start_page_num << endl; #endif return set_bits( start_page_num, run_size, 1 ); } return MINIBASE_FIRST_ERROR( DBMGR, DB_FULL ); }