Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
// **********************************************************
// 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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
// **********************************************************
// 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;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
// **********************************************************
// 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;
	}
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
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;
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
BTreeFile::~BTreeFile ()
{
	delete [] dbname;

	if (headerPageId != INVALID_PAGE) {
		Status st = MINIBASE_BM->unpinPage(headerPageId);
		if (st != OK)
			MINIBASE_FIRST_ERROR(BTREE, CANT_UNPIN_PAGE);
	}
}
Exemplo n.º 11
0
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;
}
Exemplo n.º 12
0
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;
			}
		}
	}
}
Exemplo n.º 13
0
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 );
}
Exemplo n.º 14
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;
}
Exemplo n.º 15
0
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;
}
Exemplo n.º 16
0
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;
}
Exemplo n.º 17
0
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;
}
Exemplo n.º 18
0
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;
}
Exemplo n.º 19
0
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;
}
Exemplo n.º 20
0
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;
}
Exemplo n.º 21
0
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;
}
Exemplo n.º 22
0
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;
}
Exemplo n.º 23
0
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
Exemplo n.º 24
0
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;
}
Exemplo n.º 25
0
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;
}
Exemplo n.º 26
0
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);
}
Exemplo n.º 27
0
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 );
}
Exemplo n.º 28
0
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;
}
Exemplo n.º 29
0
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;
}
Exemplo n.º 30
0
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 );
}