BadgerDB
|
00001 00008 #include "btree.h" 00009 #include "filescan.h" 00010 #include "exceptions/bad_index_info_exception.h" 00011 #include "exceptions/bad_opcodes_exception.h" 00012 #include "exceptions/bad_scanrange_exception.h" 00013 #include "exceptions/no_such_key_found_exception.h" 00014 #include "exceptions/scan_not_initialized_exception.h" 00015 #include "exceptions/index_scan_completed_exception.h" 00016 #include "exceptions/file_not_found_exception.h" 00017 #include "exceptions/end_of_file_exception.h" 00018 #include "exceptions/page_not_pinned_exception.h" 00019 00020 00021 //#define DEBUG 00022 00023 namespace badgerdb 00024 { 00025 // ----------------------------------------------------------------------------- 00026 // BTreeIndex::fillLeafNodes 00027 // ----------------------------------------------------------------------------- 00028 template <class T> 00029 int BTreeIndex::fillLeafNodes( 00030 std::deque< PageKeyPair< T > > &thisLevelNodes, 00031 std::deque< RIDKeyPair< T > > &dataList) 00032 { 00033 bool firstPage = true; 00034 PageKeyPair< T > tempPair; 00035 PageId pageNo = 0; 00036 PageId lastPageNo=0; 00037 Page* currentPage = NULL; 00038 Page* lastPage = NULL; 00039 int currentPageIndex = 0; 00040 00041 //while there are elements on list 00042 while( dataList.size() != 0 ) 00043 { 00044 //allocate a page if no space left on current page and then put 1st value and page number into list 00045 if( currentPage == NULL || currentPageIndex >= (leafOccupancy+1)/2 ) 00046 { 00047 //save the value of the last page allocated so that its right sib 00048 //ptr can be set once we allocate this new page 00049 lastPageNo = pageNo; 00050 lastPage = currentPage; 00051 //allocate a new page 00052 bufMgr->allocPage( file, pageNo, currentPage ); 00053 00054 zeroOutLeaf(currentPage); 00055 //can only set the right sib ptr once the second page has been 00056 //allocated. so skip the first time 00057 if( !firstPage) 00058 { 00059 copySibPtr( pageNo, lastPage ); 00060 bufMgr->unPinPage( file, lastPageNo, true); 00061 } 00062 currentPageIndex = 0; 00063 //so entries in thisLevelNodes have keys corresponding to first entries in leaf nodes 00064 tempPair.set( pageNo, dataList.front().key ); 00065 thisLevelNodes.push_back( tempPair ); 00066 } 00067 #ifdef DEBUG 00068 std::cout << "Adding data: " << dataList.front().key << " to page " << pageNo << std::endl; 00069 #endif 00070 00071 // put the values into the page 00072 copyKey<T>( dataList.front().key, currentPage, currentPageIndex, true); 00073 copyRid( dataList.front().rid, currentPage, currentPageIndex); 00074 firstPage = false; 00075 00076 //delete data off of list 00077 dataList.pop_front(); 00078 currentPageIndex++; 00079 } 00080 //set the right sib ptr of the last page allocated to 0 00081 if( currentPage!= NULL ) copySibPtr( 0, currentPage ); 00082 if( currentPage!= NULL ) bufMgr->unPinPage( file, pageNo, true); 00083 return pageNo; 00084 } 00085 00086 // ----------------------------------------------------------------------------- 00087 // BTreeIndex::fillNonLeafNodes 00088 // ----------------------------------------------------------------------------- 00089 template <class T> 00090 int BTreeIndex::fillNonLeafNodes( 00091 std::deque< PageKeyPair< T > > &thisLevelNodes, 00092 std::deque< PageKeyPair< T > > &lastLevelNodes, 00093 const int level) 00094 { 00095 PageKeyPair< T > tempPair; 00096 PageId pageNo; 00097 PageId lastPageNo; 00098 Page* currentPage = NULL; 00099 int currentPageIndex = 0; 00100 bool firstPage = true; 00101 00102 //while there are elements on list 00103 while( lastLevelNodes.size() != 0 ) 00104 { 00105 //allocate a page if no space left on current page and then put 1st value and page number into list 00106 if( currentPage == NULL || currentPageIndex >= (nodeOccupancy+1)/2 ) 00107 { 00108 lastPageNo = pageNo; 00109 bufMgr->allocPage( file, pageNo, currentPage ); 00110 zeroOutNonLeaf(currentPage); 00111 if( !firstPage) 00112 { 00113 bufMgr->unPinPage( file, lastPageNo, true); 00114 } 00115 currentPageIndex = 0; 00116 tempPair.set( pageNo, lastLevelNodes.front().key ) ; 00117 thisLevelNodes.push_back( tempPair ); 00118 //first entry is just the pageno, key corresponding to it is passed to the parent page, 00119 //so first page has keys greater than or equal to parent's key for this page 00120 copyPageNo( lastLevelNodes.front().pageNo, currentPage, 0 ); 00121 copyLevel( level, currentPage ); 00122 #ifdef DEBUG 00123 std::cout << "Creating Page # " << pageNo << std::endl; 00124 #endif 00125 } 00126 // Otherwise, copy key as well 00127 else 00128 { 00129 copyPageNo( lastLevelNodes.front().pageNo, currentPage, currentPageIndex ); 00130 //NOTE -1 BELOW 00131 copyKey( lastLevelNodes.front().key, currentPage, currentPageIndex-1, false ); 00132 } 00133 //delete data off of list 00134 #ifdef DEBUG 00135 std::cout << "Adding data: " << lastLevelNodes.front().key << " that points to Page: " 00136 << lastLevelNodes.front().pageNo << std::endl; 00137 #endif 00138 lastLevelNodes.pop_front(); 00139 currentPageIndex++; 00140 firstPage = false; 00141 } 00142 if( currentPage!= NULL ) bufMgr->unPinPage( file, pageNo, true); 00143 return pageNo; 00144 } 00145 00146 // ----------------------------------------------------------------------------- 00147 // BTreeIndex::BtreeTemplateConstructor 00148 // ----------------------------------------------------------------------------- 00149 template <class T> 00150 void BTreeIndex::BTreeTemplateConstructor(const std::string & relationName, 00151 std::string & outIndexName, 00152 const int attrByteOffset, 00153 const Datatype attrType) 00154 { 00155 Page* metap; 00156 IndexMetaInfo* metaPage; 00157 scanExecuting = false; 00158 00159 #ifdef DEBUG 00160 std::cout << "Initializing constructor" << std::endl; 00161 #endif 00162 // Set Class values 00163 switch( attrType ){ 00164 case INTEGER: 00165 leafOccupancy = INTARRAYLEAFSIZE; 00166 nodeOccupancy = INTARRAYNONLEAFSIZE; 00167 break; 00168 case DOUBLE: 00169 leafOccupancy = DOUBLEARRAYLEAFSIZE; 00170 nodeOccupancy = DOUBLEARRAYNONLEAFSIZE; 00171 break; 00172 case STRING: 00173 leafOccupancy = STRINGARRAYLEAFSIZE; 00174 nodeOccupancy = STRINGARRAYNONLEAFSIZE; 00175 break; 00176 default: break; 00177 } 00178 attributeType = attrType; 00179 00180 //create indexfile name 00181 std::ostringstream idxStr; 00182 idxStr << relationName << '.' << attrByteOffset; 00183 outIndexName = idxStr.str(); // indexName is the name of the index file 00184 00185 //check to see if the indexfile already exists and if so open it 00186 //Sandeep::TODO delete file when done 00187 file = 0; 00188 try 00189 { 00190 file = new BlobFile(outIndexName, false/*open*/); //open file 00191 00192 //if the file opened successfully return from constructor 00193 bufMgr->readPage( file, 1, metap); 00194 metaPage = (IndexMetaInfo*) metap; 00195 00196 //check to make sure that the relationname input matches the relation 00197 //name stored in the metapage for the index 00198 if( strncmp(metaPage->relationName, relationName.c_str(), 20) ) 00199 { 00200 throw BadIndexInfoException("Index relation name doesn't match parameters"); 00201 } 00202 //check the attrByteOffset input with the one stored for the key value 00203 //for which the tree was created. 00204 else if( metaPage->attrByteOffset != attrByteOffset ) 00205 { 00206 throw BadIndexInfoException("Index attrByteOffset doesn't match parameters"); 00207 } 00208 //make sure the types match 00209 else if( metaPage->attrType != attrType ) 00210 { 00211 throw BadIndexInfoException("Index attribute type doesn't match parameters"); 00212 } 00213 else 00214 { 00215 //if the index was openned and is indeed for this relation 00216 //store the value of the rootpageno so that the tree can be 00217 //searched and inserted into 00218 rootPageNum = metaPage->rootPageNo; 00219 } 00220 00221 bufMgr->unPinPage( file, 1, false); 00222 return; 00223 } 00224 catch(FileNotFoundException e) 00225 { 00226 } 00227 00228 //if the file did not open create a file and store the index 00229 #ifdef DEBUG 00230 std::cout << "File " << outIndexName << " does not exist." << std::endl; 00231 #endif 00232 00233 file = new BlobFile(outIndexName, true/*create*/); //create file 00234 00235 //scan the heap file for all records and store the <index key,rid> 00236 //in an array 00237 FileScan fileScan(relationName, bufMgr); 00238 00239 RecordId currentRID; 00240 std::string currentRecord; 00241 00242 std::deque< RIDKeyPair< T > > dataList; 00243 00244 try 00245 { 00246 while(1) 00247 { 00248 fileScan.scanNext(currentRID); 00249 currentRecord = fileScan.getRecord(); 00250 dataList.push_back( copyRecordToRidKeyPair<T>( currentRecord, currentRID, attrByteOffset) ); 00251 } 00252 } 00253 catch(EndOfFileException e) 00254 { 00255 //THIS IS EXPECTED 00256 //if an error occured and we didnt reach the end of the file 00257 //delete file; //this will call the file destructor and close the file 00258 //file = 0; 00259 //File::remove(outIndexName); 00260 //return; 00261 } 00262 00263 //sort the datalist deque 00264 sort(dataList.begin(), dataList.end()); 00265 if(dataList.size() == 0) 00266 { 00267 bufMgr->flushFile(file); 00268 delete file; //this will call the file destructor and close the file 00269 file = 0; 00270 File::remove(outIndexName); 00271 return; 00272 } 00273 00274 PageId pageNo = 0; 00275 //allocate a page for the meta information - will always be page 1 00276 bufMgr->allocPage( file, pageNo, metap ); 00277 metaPage = (IndexMetaInfo*)(metap); 00278 headerPageNum = pageNo; 00279 PageId nextLevelNode = 1; 00280 00281 //when creating a level each value not placed into node is placed into 00282 //this deqeu and then once the current level is created this deque becomes 00283 //lastlevelnodes and is used to create the next level 00284 std::deque< PageKeyPair< T > > thisLevelNodes; 00285 //contains the values that will be used to create a level above the last level created 00286 std::deque< PageKeyPair< T > > lastLevelNodes; 00287 #ifdef DEBUG 00288 std::cout << "Filling Leaf Nodes" << std::endl; 00289 #endif 00290 pageNo = fillLeafNodes( lastLevelNodes, dataList); 00291 //Create all non-root nodes 00292 //keeps creating levels of the tree till we dont reach a point where 00293 // the lastLevelNodes only has enough entries to make one node 00294 //for the next level as that means that level is the root and we done. 00295 while( lastLevelNodes.size() > static_cast<unsigned int>((nodeOccupancy+1)/2) ) 00296 { 00297 fillNonLeafNodes<T>( thisLevelNodes, lastLevelNodes, nextLevelNode); 00298 lastLevelNodes = thisLevelNodes; 00299 thisLevelNodes.clear(); 00300 nextLevelNode = 0; 00301 } 00302 00303 // Create root node 00304 rootPageNum = fillNonLeafNodes<T>( thisLevelNodes, lastLevelNodes, nextLevelNode); 00305 // assign pageNo and other information to metapage 00306 strncpy( metaPage->relationName, relationName.c_str(), 20); 00307 metaPage->attrByteOffset = attrByteOffset; 00308 metaPage->attrType = attrType; 00309 metaPage->rootPageNo = rootPageNum; 00310 bufMgr->unPinPage( file, headerPageNum, true); 00311 //printTreeExternal(); 00312 } 00313 00314 // ----------------------------------------------------------------------------- 00315 // BTreeIndex::BTreeIndex -- Constructor 00316 // ----------------------------------------------------------------------------- 00317 BTreeIndex::BTreeIndex(const std::string & relationName, 00318 std::string & outIndexName, 00319 BufMgr *bufMgrIn, 00320 const int attrByteOffset, 00321 const Datatype attrType) 00322 { 00323 bufMgr = bufMgrIn; 00324 //call the appropriate templated version of the BtreeTemplateConstructor based 00325 //on the attr type 00326 switch( attrType ){ 00327 case INTEGER: 00328 BTreeTemplateConstructor< int >(relationName, outIndexName, attrByteOffset, attrType); 00329 break; 00330 case DOUBLE: 00331 BTreeTemplateConstructor< double >(relationName, outIndexName, attrByteOffset, attrType); 00332 break; 00333 case STRING: 00334 BTreeTemplateConstructor< std::string >(relationName, outIndexName, attrByteOffset, attrType); 00335 break; 00336 default: 00337 // Print Error 00338 break; 00339 } 00340 } 00341 00342 00343 // ----------------------------------------------------------------------------- 00344 // BTreeIndex::~BTreeIndex -- destructor 00345 // ----------------------------------------------------------------------------- 00346 00347 BTreeIndex::~BTreeIndex() 00348 { 00349 if( scanExecuting ) 00350 { 00351 try 00352 { 00353 endScan(); 00354 } 00355 catch(ScanNotInitializedException e) 00356 { 00357 } 00358 } 00359 00360 if(file) 00361 bufMgr->flushFile(file); 00362 00363 delete file; 00364 } 00365 00366 // ----------------------------------------------------------------------------- 00367 // BTreeIndex::insertEntry 00368 // ----------------------------------------------------------------------------- 00369 00370 const void BTreeIndex::insertEntry(const void *value, const RecordId rid) 00371 { 00372 //helps keep track of what level of the tree we are at during the 00373 //execution of insertEntry 00374 //if the value at the top of the stack is 1 we know that we are handling 00375 //leaf nodes. otherwise we handling non leaf nodes. 00376 std::stack<int> treePath; 00377 RecordId ridValue = rid; 00378 00379 #ifdef DEBUG 00380 std::cout<<"*******************************************"<<std::endl; 00381 std::cout << "Root Page Number: " << rootPageNum <<std::endl; 00382 #endif 00383 00384 //call the templated insertEntry function with values based on the type 00385 //of tree we are working with here 00386 if(attributeType == INTEGER) 00387 { 00388 #ifdef DEBUG 00389 std::cout <<" Inserting integer"<<std::endl; 00390 #endif 00391 int key = *((int*)value); 00392 PageKeyPair<int> newPageKeyPair; 00393 //pageNo for this dummy newPageKeyPair will be set to 0 in insertInto as necessary, might be safe doing that in the constructor 00394 insertInto<int>(rootPageNum, key, newPageKeyPair, 00395 ridValue, treePath); 00396 } 00397 if(attributeType == DOUBLE) 00398 { 00399 #ifdef DEBUG 00400 std::cout <<" Inserting double"<<std::endl; 00401 #endif 00402 double key = *((double*)value); 00403 PageKeyPair<double> newPageKeyPair; 00404 insertInto<double>(rootPageNum, key, newPageKeyPair, 00405 ridValue, treePath); 00406 } 00407 if(attributeType == STRING) 00408 { 00409 #ifdef DEBUG 00410 std::cout <<" Inserting string"<<std::endl; 00411 #endif 00412 std::string key; 00413 for(int i=0; i<10; i++) 00414 key+= *( ((char*)value)+i ); 00415 00416 PageKeyPair<std::string> newPageKeyPair; 00417 insertInto<std::string>(rootPageNum, key, newPageKeyPair, 00418 ridValue, treePath); 00419 } 00420 } 00421 00422 // ----------------------------------------------------------------------------- 00423 // BTreeIndex::startScan 00424 // ----------------------------------------------------------------------------- 00425 const void BTreeIndex::startScan(const void* lowValParm, 00426 const Operator lowOpParm, 00427 const void* highValParm, 00428 const Operator highOpParm) 00429 { 00430 //make sure that there's no current scan. If there is, end it. 00431 if( scanExecuting ) 00432 endScan(); 00433 //check to make sure the op values are used the correct way for ranges 00434 if( ( lowOpParm != GT && lowOpParm != GTE ) || ( highOpParm != LT && highOpParm != LTE ) ) 00435 throw BadOpcodesException(); 00436 00437 // Set member variables for scan 00438 lowOp = lowOpParm; 00439 highOp = highOpParm; 00440 00441 //set to root before scan starts 00442 currentPageNum = rootPageNum; 00443 00444 switch( attributeType ){ 00445 case INTEGER: 00446 setHighLowVal<int>(highValParm, true); 00447 setHighLowVal<int>(lowValParm, false); 00448 templateStartScan<int>(); 00449 return; 00450 break; 00451 case DOUBLE: 00452 setHighLowVal<double>(highValParm, true); 00453 setHighLowVal<double>(lowValParm, false); 00454 templateStartScan<double>(); 00455 return; 00456 break; 00457 case STRING: 00458 setHighLowVal<std::string>(highValParm, true); 00459 setHighLowVal<std::string>(lowValParm, false); 00460 templateStartScan<std::string>(); 00461 return; 00462 break; 00463 default: break; 00464 } 00465 } 00466 00467 // ----------------------------------------------------------------------------- 00468 // BTreeIndex::templateStartScan 00469 // ----------------------------------------------------------------------------- 00470 00471 template <class T> 00472 const void BTreeIndex::templateStartScan() 00473 { 00474 #ifdef DEBUG 00475 std::cout << "Begin: Start Scan." << std::endl 00476 << "Low = " << getHighLowVal<T>( false ) << " High = " << getHighLowVal<T>( true ) << std::endl; 00477 #endif 00478 // set local variables 00479 int nextLevelLeaf = 0; 00480 PageId lastPageNum; 00481 nextEntry = 0; 00482 RecordId tempRid; 00483 T tempKey; 00484 PageId tempPageNo; 00485 00486 //make sure the upper bound specified is greater than the lower bound specified 00487 if( getHighLowVal<T>( false ) > getHighLowVal<T>( true ) ) 00488 throw BadScanrangeException(); 00489 00490 scanExecuting = true; 00491 00492 //go down the tree along the appropriate path based on the lower bound value input 00493 //loop goes through all the non leaf nodes in the path 00494 do 00495 { 00496 #ifdef DEBUG 00497 std::cout << "Searching Node" << std::endl; 00498 #endif 00499 //read page for node in path 00500 bufMgr->readPage( file, currentPageNum, currentPageData ); 00501 00502 //get the level so that we only go upto the last non leaf level 00503 extractLevel( nextLevelLeaf, currentPageData ); 00504 lastPageNum = currentPageNum; 00505 //figure out next node to go to in the path 00506 currentPageNum = findPageNoInNonLeaf( currentPageData, getHighLowVal<T>( false ) ); 00507 bufMgr->unPinPage( file, lastPageNum, false ); 00508 }while( nextLevelLeaf != 1 ); 00509 00510 // currentPageNum is now a leaf 00511 bufMgr->readPage( file, currentPageNum, currentPageData ); 00512 nextEntry = 0; 00513 //figure out the first value for the scan 00514 while( extractKey<T>( tempKey, currentPageData, nextEntry, true ) < getHighLowVal<T>( false ) 00515 && extractRid( tempRid, currentPageData, nextEntry ).page_number != 0 00516 && nextEntry < INTARRAYLEAFSIZE ) 00517 { 00518 nextEntry++; 00519 } 00520 00521 //if we went beyond the page this means the first value of the scan is the first value 00522 //of the next page. 00523 //if there is no right sib it means the lower bound is the larger than all values in the index 00524 //???????????????? why so 00525 if( extractRid( tempRid, currentPageData, nextEntry ).page_number == 0 || nextEntry >= INTARRAYLEAFSIZE ) 00526 { 00527 // If it is last entry of last page, return error 00528 if(extractSibPtr( tempPageNo, currentPageData) == 0) 00529 { 00530 bufMgr->unPinPage( file, currentPageNum, false ); 00531 00532 scanExecuting = false; 00533 throw NoSuchKeyFoundException(); 00534 } 00535 else 00536 { 00537 //set next entry to the first entry of the right sib page 00538 lastPageNum = currentPageNum; 00539 currentPageNum = extractSibPtr( tempPageNo, currentPageData); 00540 bufMgr->unPinPage( file, lastPageNum, false ); 00541 bufMgr->readPage( file, currentPageNum, currentPageData ); 00542 nextEntry = 0; 00543 } 00544 } 00545 else 00546 { 00547 // If we wanted greater than and we are at an equal, move nextEntry over 00548 if( extractKey<T>( tempKey, currentPageData, nextEntry, true ) == getHighLowVal<T>( false ) 00549 && lowOp == GT ) 00550 { 00551 #ifdef DEBUG 00552 std::cout << "Shifting nextEntry" << std::endl; 00553 #endif 00554 try 00555 { 00556 scanNext(tempRid); 00557 } 00558 catch(IndexScanCompletedException e) 00559 { 00560 bufMgr->unPinPage( file, currentPageNum, false ); 00561 scanExecuting = false; 00562 throw NoSuchKeyFoundException(); 00563 } 00564 } 00565 } 00566 #ifdef DEBUG 00567 std::cout << "End: Start Scan" << std::endl; 00568 #endif 00569 } 00570 00571 // ----------------------------------------------------------------------------- 00572 // BTreeIndex::scanNext 00573 // ----------------------------------------------------------------------------- 00574 //throws and rethrows IndexScanCompletedException 00575 const void BTreeIndex::scanNext(RecordId& outRid) 00576 { 00577 //check to make sure a scan is in progress 00578 if(!scanExecuting ) 00579 throw ScanNotInitializedException(); 00580 00581 //to check if the scan is over 00582 if(nextEntry == -1) 00583 throw IndexScanCompletedException(); 00584 00585 //call templated function with the appropriate type 00586 switch(attributeType){ 00587 case INTEGER: 00588 templateScanNext<int>( outRid ); 00589 return; 00590 break; 00591 case DOUBLE: 00592 templateScanNext<double>( outRid ); 00593 return; 00594 break; 00595 case STRING: 00596 templateScanNext<std::string>( outRid ); 00597 return; 00598 break; 00599 default: break; 00600 } 00601 } 00602 00603 // ----------------------------------------------------------------------------- 00604 // BTreeIndex::templateScanNext 00605 // ----------------------------------------------------------------------------- 00606 template <class T> 00607 const void BTreeIndex::templateScanNext(RecordId& outRid) 00608 { 00609 #ifdef DEBUG 00610 std::cout << "Begin: Scan Next" << std::endl; 00611 #endif 00612 00613 PageId lastPageNum = 0; 00614 T tempKey; 00615 PageId tempPageNo; 00616 RecordId tempRid; 00617 00618 // See if we've gone beyond range 00619 if( ( highOp == LTE && extractKey<T>( tempKey, currentPageData, nextEntry, true ) > getHighLowVal<T>(true) ) 00620 || ( highOp == LT && extractKey<T>( tempKey, currentPageData, nextEntry, true ) >= getHighLowVal<T>(true) ) ) 00621 { 00622 nextEntry = -1; 00623 throw IndexScanCompletedException(); 00624 } 00625 00626 //otherwise, set outRid and increment nextEntry 00627 #ifdef DEBUG 00628 std::cout << "key = " << extractKey<T>( tempKey, currentPageData, nextEntry, true ) << std::endl 00629 << "RID = " << extractRid( outRid, currentPageData, nextEntry).page_number << std::endl; 00630 #endif 00631 00632 extractRid(outRid, currentPageData, nextEntry); 00633 nextEntry++; 00634 00635 //see if we have to change the page 00636 if( nextEntry >= INTARRAYLEAFSIZE || extractRid( tempRid, currentPageData, nextEntry).page_number == 0 ) 00637 { 00638 //if there is no right sib the scan has ended 00639 if( extractSibPtr( tempPageNo, currentPageData) == 0) 00640 { 00641 nextEntry = -1; 00642 } 00643 else 00644 { 00645 #ifdef DEBUG 00646 std::cout << "Moving to sibling page : " << extractSibPtr( tempPageNo, currentPageData ) << std::endl; 00647 #endif 00648 lastPageNum = currentPageNum; 00649 currentPageNum = extractSibPtr( tempPageNo, currentPageData); 00650 nextEntry = 0; 00651 bufMgr->readPage( file, currentPageNum, currentPageData ); 00652 bufMgr->unPinPage( file, lastPageNum, false ); 00653 } 00654 } 00655 #ifdef DEBUG 00656 std::cout << "End: Scan Next" << std::endl; 00657 #endif 00658 } 00659 00660 // ----------------------------------------------------------------------------- 00661 // BTreeIndex::endScan 00662 // ----------------------------------------------------------------------------- 00663 const void BTreeIndex::endScan() 00664 { 00665 //check to make sure there is a scan running 00666 if( !scanExecuting ) 00667 throw ScanNotInitializedException(); 00668 00669 bufMgr->unPinPage( file, currentPageNum, false ); 00670 00671 scanExecuting = false; 00672 } 00673 00674 // ----------------------------------------------------------------------------- 00675 // BTreeIndex::insertInto 00676 // ----------------------------------------------------------------------------- 00677 template <class T> 00678 void BTreeIndex::insertInto(PageId pageNo, T key, PageKeyPair<T> &newPageKeyPair, 00679 RecordId &rid, std::stack<int> &treePath) 00680 { 00681 //this function will always be called with the pageNo set to 00682 //the root page no to begin with and then subsequent recursive calls 00683 //will set the appropriate pageNo values depending on the path followed 00684 PageId tempPageNo; 00685 T tempKey; 00686 Page* currentNode; 00687 int level; 00688 bool isLeaf = false; 00689 bool isRoot = false; 00690 00691 //variable to figure out if a given node is full or not 00692 //if not full it indicated which index can be used next to add data 00693 //it represents the index in the pageNo array - NOT THE KEY ARRAY 00694 int lastIndexUsed = 0; 00695 00696 //read the page in from the buffer manager 00697 bufMgr->readPage(file, pageNo, currentNode); 00698 00699 #ifdef DEBUG 00700 std::cout << "InsertInto called on pageNo: " << pageNo <<std::endl; 00701 #endif 00702 00703 //check to see if its a leaf node or non leaf node 00704 if( treePath.size() != 0 && treePath.top() == 1) 00705 { 00706 #ifdef DEBUG 00707 std::cout << "Recursive call has reached the leaf node level." <<std::endl; 00708 #endif 00709 isLeaf = true; 00710 } 00711 else 00712 { 00713 memcpy( &level, currentNode, sizeof(int) ); 00714 treePath.push(level); 00715 #ifdef DEBUG 00716 std::cout << "Inserting level: " <<level<<" into the treePath stack" << std::endl; 00717 #endif 00718 } 00719 00720 //if node is a non leaf node 00721 if( !isLeaf ) 00722 { 00723 #ifdef DEBUG 00724 std::cout << "Current level is a non leaf level" <<std::endl; 00725 #endif 00726 00727 //find the next pageno to determine the path down the btree 00728 PageId nextPageNo = findPageNoInNonLeaf<T>( currentNode, key ); 00729 00730 #ifdef DEBUG 00731 std::cout << "Next page in path being followed is: " << nextPageNo << std::endl; 00732 #endif 00733 00734 //call insert on the page number found above, the key input and 00735 //newPageNo) 00736 #ifdef DEBUG 00737 std::cout << "Making recursive call with for the above pageNo" <<std::endl; 00738 #endif 00739 00740 insertInto<T>(nextPageNo, key, newPageKeyPair, rid, treePath); 00741 00742 #ifdef DEBUG 00743 std::cout << std::endl << "Returning from recursive call for pageNo:" << nextPageNo <<std::endl; 00744 #endif 00745 00746 /*if(status != OK ) 00747 { 00748 #ifdef DEBUG 00749 std::cout << "Error occured on return from recursive call" <<endl; 00750 #endif 00751 //even though error has occured need to make sure we unpin the page 00752 //no change was made to this page, so hasnt been dirtied 00753 bufMgr->unPinPage(file, pageNo, 0); 00754 return; 00755 }*/ 00756 00757 //check if we have been through all the recursive calls and have reached the 00758 //the root 00759 if( treePath.size() == 1 ) 00760 { 00761 #ifdef DEBUG 00762 std::cout << "We have reached back to the root after going all the way down" <<std::endl; 00763 #endif 00764 isRoot = true; 00765 } 00766 00767 treePath.pop(); 00768 00769 //on return from this recursive call check to see if a split occured 00770 //in the level below by checking the value of pageNo in newPageKeyPair 00771 //if newPageKeyPair.pageNo =0 then no split occured 00772 if( newPageKeyPair.pageNo == 0 ) 00773 { 00774 #ifdef DEBUG 00775 std::cout << "Lower level was not split" <<std::endl; 00776 #endif 00777 //no change was made to this page, so hasnt been dirtied 00778 bufMgr->unPinPage(file, pageNo, 0); 00779 return; 00780 } 00781 // else a split has occured 00782 00783 //check to see if there is space in this level to 00784 //accomadate the split and place the key in the parent node 00785 isNonLeafFull(currentNode, lastIndexUsed); 00786 if( lastIndexUsed < nodeOccupancy ) 00787 { 00788 #ifdef DEBUG 00789 std::cout << "non leaf node is not full, inserting into the node" <<std::endl; 00790 #endif 00791 //there is place in the node to add the new key 00792 insertPageKeyPair<T>( currentNode, newPageKeyPair, lastIndexUsed ); 00793 00794 //set the newPageKeyPair.pageNo = 0 so that if no further split 00795 //the higher recursive calls dont think there are more splits 00796 newPageKeyPair.pageNo = 0; 00797 00798 //change has been made to this page, so set dirty flag while unpinning 00799 bufMgr->unPinPage(file, pageNo, 1); 00800 return; 00801 } 00802 00803 //the currentNode needs to be split due to lack of space to add new 00804 //keypageno pair 00805 #ifdef DEBUG 00806 std::cout << "Need to split node, creating new node" <<std::endl; 00807 #endif 00808 //allocate a new page for the new node 00809 PageId newPageNo; 00810 Page *newNode; 00811 bufMgr->allocPage( file, newPageNo, newNode ); 00812 00813 //set the level 00814 #ifdef DEBUG 00815 std::cout << "Setting the level of the new node to: " <<*(int*)currentNode<<std::endl; 00816 #endif 00817 00818 //first item in all NonLeafNodeInt/Double/String structs is the level variable 00819 //it is just called a page* though its actually not pointing to object of Page class 00820 //or even though it is we are not using that Page as a Page object instead we are using that as a NonLeafNode pointer 00821 //since its also of the same size as Page object but then calls to any method on these modified objects would fail????? 00822 *(int*)(newNode) = *(int*)currentNode; 00823 extractKey<T>(tempKey, currentNode , nodeOccupancy/2, false); 00824 00825 #ifdef DEBUG 00826 std::cout << "Value being pushed up one level:" << tempKey << std::endl; 00827 #endif 00828 00829 //put all the remaining elements of the node being split into new node 00830 splitNonLeafNode<T>(currentNode, newNode ); 00831 00832 //check to see if the key from lower level goes into old node or the new node created 00833 if( newPageKeyPair.key < tempKey ) 00834 { 00835 #ifdef DEBUG 00836 std::cout <<" Inserting page no:"<<newPageKeyPair.key<<std::endl; 00837 #endif 00838 isNonLeafFull( currentNode, lastIndexUsed); 00839 insertPageKeyPair<T>( currentNode, newPageKeyPair, lastIndexUsed ); 00840 } 00841 else 00842 { 00843 isNonLeafFull( newNode, lastIndexUsed); 00844 insertPageKeyPair<T>( newNode, newPageKeyPair, lastIndexUsed ); 00845 } 00846 00847 //set the newPageKeyPair.pageNo to the 00848 //the new pageno that has been just allocated for the split 00849 newPageKeyPair.pageNo = newPageNo; 00850 newPageKeyPair.key = tempKey; 00851 00852 //if the node that was just split was the root 00853 if( isRoot ) 00854 { 00855 #ifdef DEBUG 00856 std::cout << "splitting the root" <<std::endl; 00857 #endif 00858 00859 //allocate a new page for the new root node 00860 PageId newRootPageNo; 00861 Page *newRootNode; 00862 bufMgr->allocPage( file, newRootPageNo, newRootNode ); 00863 00864 zeroOutNonLeaf(newRootNode); 00865 00866 //set the level 00867 *(int*)(newRootNode) = 0; 00868 00869 //set the p0 pointer to the pageno that was split 00870 copyPageNo(pageNo, newRootNode , 0); 00871 00872 //set the key value to the element being pushed up to the new root 00873 copyKey<T>(tempKey, newRootNode , 0 , false); 00874 00875 //set the p1 pointer to the the pageno of new node resulting from the split 00876 copyPageNo(newPageNo, newRootNode , 1); 00877 00878 //update the meta information - need to decide when this is written back 00879 //to the meta information page !!!! 00880 /****************************************************************/ 00881 rootPageNum = newRootPageNo; 00882 00883 //change was made to this page, so has been dirtied 00884 bufMgr->unPinPage(file, newRootPageNo, 1); 00885 00886 //dont return here as the only thing happening next is the unpinning and return of status 00887 //which is what would be done in the return here anyways 00888 00889 Page* metaPage; 00890 bufMgr->readPage(file, 1, metaPage); 00891 ((IndexMetaInfo*)metaPage)->rootPageNo = rootPageNum; 00892 bufMgr->unPinPage(file, 1, 1); 00893 } 00894 //change was made to this page, so has been dirtied 00895 #ifdef DEBUG 00896 std::cout << "unpinning "<< pageNo<<std::endl; 00897 #endif 00898 bufMgr->unPinPage(file, pageNo, 1); 00899 //change was made to this page, so has been dirtied 00900 #ifdef DEBUG 00901 std::cout << "unpinning "<< newPageNo<<std::endl; 00902 #endif 00903 bufMgr->unPinPage(file, newPageNo, 1); 00904 return; 00905 } 00906 00907 //HANDLE INSERTION INTO A LEAF NODE 00908 00909 #ifdef DEBUG 00910 std::cout << "Handling leaf level" <<std::endl; 00911 #endif 00912 00913 //make an ridkey pair 00914 RIDKeyPair<T> keyRidPair; 00915 keyRidPair.set( rid, key); 00916 00917 isLeafFull(currentNode, lastIndexUsed); 00918 00919 //check to see if there is place in the node to add the key value 00920 if( lastIndexUsed < leafOccupancy-1 ) 00921 { 00922 #ifdef DEBUG 00923 std::cout << "Inserting into the leaf level node" <<std::endl; 00924 #endif 00925 00926 insertKeyRidPair<T>( currentNode, keyRidPair, lastIndexUsed ); 00927 newPageKeyPair.pageNo = 0; 00928 bufMgr->unPinPage(file, pageNo, 1); 00929 return; 00930 } 00931 00932 //need to split the currentNode 00933 #ifdef DEBUG 00934 std::cout << "Splitting leaf level node" <<std::endl; 00935 #endif 00936 00937 00938 //create a new node 00939 PageId newPageNo; 00940 Page *newLeafNode; 00941 bufMgr->allocPage( file, newPageNo, newLeafNode ); 00942 00943 //first split the the node and then figure out where the new keyRidPair should go 00944 00945 //split the node 00946 splitLeafNode<T>( currentNode, newLeafNode, lastIndexUsed); 00947 00948 //set the sibling pointer in the new node to the sibling pointer in the old 00949 //node and set the old nodes sibling pointer to this new node 00950 extractSibPtr( tempPageNo, currentNode); 00951 copySibPtr( tempPageNo, newLeafNode); 00952 copySibPtr( newPageNo, currentNode); 00953 00954 //figure out which node , current or new node created is going to be used 00955 //to insert the new key value into by looking at the first value in the new node 00956 00957 extractKey<T>(tempKey, newLeafNode , 0, true); 00958 if( keyRidPair.key < tempKey ) 00959 { 00960 #ifdef DEBUG 00961 std::cout << "!!!placing into in old page" <<std::endl; 00962 #endif 00963 isLeafFull( currentNode,lastIndexUsed); 00964 insertKeyRidPair<T>( currentNode, keyRidPair, lastIndexUsed ); 00965 } 00966 else 00967 { 00968 #ifdef DEBUG 00969 std::cout << "!!!placing into in new page" <<std::endl; 00970 #endif 00971 isLeafFull( newLeafNode,lastIndexUsed); 00972 insertKeyRidPair<T>( newLeafNode, keyRidPair, lastIndexUsed ); 00973 } 00974 00975 #ifdef DEBUG 00976 std::cout <<"after insert"<<std::endl; 00977 #endif 00978 00979 extractKey<T>(tempKey, newLeafNode , 0, true); 00980 newPageKeyPair.key = tempKey; 00981 newPageKeyPair.pageNo = newPageNo; 00982 00983 bufMgr->unPinPage(file, pageNo, 1); 00984 bufMgr->unPinPage(file, newPageNo, 1); 00985 return; 00986 } 00987 00988 // ----------------------------------------------------------------------------- 00989 // BTreeIndex::splitNonLeafNode 00990 // ----------------------------------------------------------------------------- 00991 template <class T> 00992 void BTreeIndex::splitNonLeafNode(Page* currentNode, Page* newNode ) 00993 { 00994 int nonLeafNodeSize = nodeOccupancy; 00995 T tempKey; 00996 PageId tempPageNo; 00997 char zero[11] = "0000000000"; 00998 //INTARRAYNONLEAFSIZE = 4 00999 //0 0 1 1 2 2 3 3 4 01000 //p0 k1 p1 k2 p2 k3 p3 k4 p4 01001 01002 //copy the second half of the node being split ( minus the first element 01003 //that has been pushed up) in this new node 01004 01005 //zero out the key at this index as it is the one being pushed up to 01006 //the non leaf level above the level at which this split is taking place 01007 if( attributeType != STRING) 01008 copyKey<T>(0, currentNode , nonLeafNodeSize/2, false); 01009 else 01010 copyKey<std::string>(zero, currentNode , nonLeafNodeSize/2, false); 01011 01012 int j =0; 01013 for( int i = nonLeafNodeSize/2 + 1; i < nonLeafNodeSize ; ++i) 01014 { 01015 extractKey<T>(tempKey, currentNode, i , false); 01016 copyKey<T>(tempKey, newNode , j, false); 01017 01018 extractPageNo(tempPageNo, currentNode, i); 01019 copyPageNo(tempPageNo, newNode , j); 01020 ++j; 01021 01022 //zero out the values that have been copied to the new node 01023 if(attributeType != STRING) 01024 copyKey<T>(0, currentNode , i, false); 01025 else 01026 copyKey<std::string>(zero, currentNode , i, false); 01027 01028 copyPageNo(0, currentNode , i); 01029 } 01030 01031 //set the last pointer in the new node 01032 extractPageNo(tempPageNo, currentNode, nonLeafNodeSize); 01033 copyPageNo(tempPageNo, newNode , j); 01034 copyPageNo(0, currentNode , nonLeafNodeSize); 01035 01036 if( attributeType != STRING) 01037 { 01038 //zero out the rest of the node entries 01039 copyKey<T>(0, newNode , j, false); 01040 for(int i = j+1; i<nonLeafNodeSize;++i) 01041 { 01042 copyKey<T>(0, newNode , i, false); 01043 copyPageNo(0, newNode , i); 01044 } 01045 01046 copyPageNo(0, newNode , nonLeafNodeSize); 01047 } 01048 else 01049 { 01050 //zero out the rest of the node entries 01051 copyKey<std::string>(zero, newNode , j, false); 01052 for(int i = j+1; i<nonLeafNodeSize;++i) 01053 { 01054 copyKey<std::string>(zero, newNode , i, false); 01055 copyPageNo(0, newNode , i); 01056 } 01057 01058 copyPageNo(0, newNode , nonLeafNodeSize); 01059 } 01060 } 01061 01062 // ----------------------------------------------------------------------------- 01063 // BTreeIndex::splitLeafNode 01064 // ----------------------------------------------------------------------------- 01065 template <class T> 01066 void BTreeIndex::splitLeafNode(Page* currentNode, Page* newLeafNode, int &newNodeIndexNotUsed) 01067 { 01068 int leafNodeSize = leafOccupancy; 01069 T tempKey; 01070 RecordId tempRid; 01071 newNodeIndexNotUsed = 0; 01072 RecordId zeroRid; 01073 zeroRid.page_number = 0; 01074 char zero[11] = "0000000000"; 01075 01076 for( int i = leafNodeSize/2 + 1; i < leafNodeSize ; ++i ) 01077 { 01078 extractKey<T>(tempKey, currentNode, i , true); 01079 copyKey<T>(tempKey, newLeafNode , newNodeIndexNotUsed, true); 01080 01081 extractRid(tempRid, currentNode, i); 01082 copyRid(tempRid, newLeafNode , newNodeIndexNotUsed++); 01083 01084 if(attributeType != STRING) 01085 copyKey<T>(0, currentNode , i, true); 01086 else 01087 copyKey<std::string>(zero, currentNode , i, true); 01088 01089 copyRid(zeroRid, currentNode , i); 01090 } 01091 01092 if( attributeType != STRING ) 01093 { 01094 //zero out the rest of the new leaf node entries 01095 copyKey<T>(0, newLeafNode , newNodeIndexNotUsed, true); 01096 copyRid(zeroRid, newLeafNode , newNodeIndexNotUsed); 01097 01098 for(int i = newNodeIndexNotUsed+1; i<leafNodeSize;++i) 01099 { 01100 copyKey<T>(0, newLeafNode , i, true); 01101 copyRid(zeroRid, newLeafNode , i); 01102 } 01103 } 01104 else 01105 { 01106 //zero out the rest of the new leaf node entries 01107 copyKey<std::string>(zero, newLeafNode , newNodeIndexNotUsed, true); 01108 copyRid(zeroRid, newLeafNode , newNodeIndexNotUsed); 01109 01110 for(int i = newNodeIndexNotUsed+1; i<leafNodeSize;++i) 01111 { 01112 copyKey<std::string>(zero, newLeafNode , i, true); 01113 copyRid(zeroRid, newLeafNode , i); 01114 } 01115 } 01116 } 01117 01118 // ----------------------------------------------------------------------------- 01119 // BTreeIndex::isNonLeafFull 01120 // ----------------------------------------------------------------------------- 01121 void BTreeIndex::isNonLeafFull(Page* currentNode, int &lastIndexUsed) 01122 { 01123 int nonLeafNodeSize = nodeOccupancy; 01124 PageId tempPageNo; 01125 int indexCounter = 0; 01126 for( indexCounter = 0; indexCounter < nonLeafNodeSize; ++indexCounter ) 01127 { 01128 extractPageNo(tempPageNo, currentNode, indexCounter + 1); 01129 //if page no is 0 the last page no index was the last index with 01130 //valid data in it 01131 if( tempPageNo == 0 ) 01132 { 01133 lastIndexUsed = indexCounter; 01134 return; 01135 } 01136 } 01137 //the node is full, so set the lastIndexUsed to the nonLeafNodeSize 01138 lastIndexUsed = nonLeafNodeSize; 01139 } 01140 01141 // ----------------------------------------------------------------------------- 01142 // BTreeIndex::isLeafFull 01143 // ----------------------------------------------------------------------------- 01144 void BTreeIndex::isLeafFull( Page* currentNode, int &lastIndexUsed) 01145 { 01146 int leafNodeSize = leafOccupancy; 01147 RecordId tempRid; 01148 int indexCounter = 0; 01149 for( indexCounter = 0; indexCounter < leafNodeSize; ++indexCounter ) 01150 { 01151 //if the page no is 0 the last page no index was the last index with valid 01152 //data in it 01153 extractRid(tempRid, currentNode, indexCounter); 01154 if( tempRid.page_number == 0 ) 01155 { 01156 lastIndexUsed = indexCounter-1; 01157 return; 01158 } 01159 } 01160 //the node is full and so set the lastIndexUsed to the leafNodeSize - 1 01161 lastIndexUsed = leafNodeSize-1; 01162 } 01163 01164 // ----------------------------------------------------------------------------- 01165 // BTreeIndex::insertKeyRidPair 01166 // ----------------------------------------------------------------------------- 01167 template <class T> 01168 void BTreeIndex::insertKeyRidPair( Page* currentNode, RIDKeyPair<T> keyRidPair, int lastIndexUsed ) 01169 { 01170 int keyIter; 01171 int ridIter = 0; 01172 01173 T tempKey; 01174 RecordId rid; 01175 01176 for( keyIter = 0; keyIter <= lastIndexUsed; ++keyIter) 01177 { 01178 extractKey<T>( tempKey, currentNode, keyIter, true); 01179 if( keyRidPair.key < tempKey ) 01180 { 01181 //shift everything starting from lastIndexUsed to the right 01182 //to make place for the values being inserted 01183 for(int subIter = lastIndexUsed; subIter >= keyIter ; --subIter ) 01184 { 01185 extractKey<T>(tempKey, currentNode, subIter , true); 01186 copyKey<T>(tempKey, currentNode , subIter+1, true); 01187 01188 extractRid(rid, currentNode, subIter); 01189 copyRid(rid, currentNode , subIter+1); 01190 } 01191 01192 //insert the new values in the appropriate position 01193 copyKey<T>(keyRidPair.key, currentNode , keyIter, true); 01194 copyRid(keyRidPair.rid, currentNode, keyIter); 01195 01196 return; 01197 } 01198 ++ridIter; 01199 } 01200 01201 //key being inserted is the largest in the node 01202 copyKey<T>(keyRidPair.key, currentNode , lastIndexUsed+1, true); 01203 copyRid(keyRidPair.rid, currentNode, lastIndexUsed+1); 01204 } 01205 01206 01207 // ----------------------------------------------------------------------------- 01208 // BTreeIndex::insertPageKeyPair 01209 // ----------------------------------------------------------------------------- 01210 template <class T> 01211 void BTreeIndex::insertPageKeyPair( Page* currentNode, PageKeyPair<T> keyPagePair, int lastIndexUsed ) 01212 { 01213 int pageNoIter = 0; 01214 01215 T tempValue; 01216 PageId pageNo; 01217 01218 for( int keyIter=0; keyIter < lastIndexUsed; ++keyIter ) 01219 { 01220 extractKey<T>(tempValue, currentNode, keyIter, false); 01221 if( keyPagePair.key < tempValue ) 01222 { 01223 //shift everything starting from lastIndexUsed to the right 01224 //to make place for the values being inserted 01225 for(int subIter = lastIndexUsed; subIter >= keyIter ; --subIter ) 01226 { 01227 extractKey<T>(tempValue, currentNode, subIter-1 , false); 01228 copyKey<T>(tempValue, currentNode , subIter, false); 01229 01230 extractPageNo(pageNo, currentNode, subIter ); 01231 copyPageNo(pageNo, currentNode , subIter+1 ); 01232 } 01233 01234 //insert the new values in the appropriate position 01235 copyKey<T>(keyPagePair.key, currentNode , keyIter, false); 01236 copyPageNo(keyPagePair.pageNo, currentNode , keyIter+1); 01237 return; 01238 } 01239 ++pageNoIter; 01240 } 01241 01242 //value to be inserted is bigger than everything else in the node 01243 #ifdef DEBUG 01244 std::cout << "lastIndex Value being inserted into" << lastIndexUsed << std::endl; 01245 std::cout << "keyPagePair.key value "<< keyPagePair.key<<std::endl; 01246 std::cout << "keyPagePair.pageNo "<< keyPagePair.pageNo<<std::endl; 01247 #endif 01248 copyKey<T>(keyPagePair.key, currentNode , lastIndexUsed, false); 01249 copyPageNo(keyPagePair.pageNo, currentNode , lastIndexUsed+1); 01250 } 01251 01252 // ----------------------------------------------------------------------------- 01253 // BTreeIndex::findPageNoInNonLeaf 01254 // ----------------------------------------------------------------------------- 01255 template <class T> 01256 PageId BTreeIndex::findPageNoInNonLeaf( Page *currentNode, T key ) 01257 { 01258 PageId pageNo; 01259 int lastIndexUsed; 01260 //figure out the last valid index in the node 01261 isNonLeafFull( currentNode, lastIndexUsed); 01262 01263 T higherValue; 01264 for( int i=0; i <= lastIndexUsed ; i++) 01265 { 01266 extractKey<T>(higherValue, currentNode, i, false); 01267 //if the current value of i is the same as the lastindex used then 01268 //this is the path we must follow, or if the value of the key 01269 //at this index is less than the higherValue we know that this 01270 //is the path we want to follow 01271 if( i == lastIndexUsed || key < higherValue ) 01272 { 01273 extractPageNo( pageNo, currentNode, i); 01274 #ifdef DEBUG 01275 std::cout << "$$pageNo chosen" << pageNo << std::endl; 01276 #endif 01277 return pageNo; 01278 } 01279 } 01280 return 0; 01281 } 01282 01283 // ----------------------------------------------------------------------------- 01284 // BTreeIndex::setHighLowVal 01285 // ----------------------------------------------------------------------------- 01286 template <class T> 01287 void BTreeIndex::setHighLowVal( const void* val, bool high) 01288 { 01289 //set the appropriate member values depending on the type of 01290 //index being scanned at this point 01291 if( attributeType == INTEGER ) 01292 { 01293 if( high ) highValInt = *(int*)( (char*)val ); 01294 else lowValInt = *(int*)( (char*)val ); 01295 } 01296 else if( attributeType == DOUBLE ) 01297 { 01298 if( high ) highValDouble = *(double*)( (char*)val ); 01299 else lowValDouble = *(double*)( (char*)val ); 01300 } 01301 else if( attributeType == STRING ) 01302 { 01303 if( high ) 01304 { 01305 highValString.clear(); 01306 for( int i = 0; i < 10; i++ ) 01307 highValString += *((char*)val + i ); 01308 } 01309 else 01310 { 01311 lowValString.clear(); 01312 for( int i = 0; i < 10; i++ ) 01313 lowValString += *((char*)val + i ); 01314 } 01315 } 01316 } 01317 01318 // ----------------------------------------------------------------------------- 01319 // BTreeIndex::copyRecordToRidKeyPair 01320 // ----------------------------------------------------------------------------- 01321 template <class T> 01322 RIDKeyPair<T> BTreeIndex::copyRecordToRidKeyPair(std::string rec, RecordId rid, const int attrByteOffset ) 01323 { 01324 RIDKeyPair<T> ridKeyVal; 01325 T key; 01326 01327 //copy the key and rid value for the given RID into a ridKeyVal object 01328 key = *(T*)(rec.c_str() + attrByteOffset); 01329 ridKeyVal.set( rid, key); 01330 return ridKeyVal; 01331 } 01332 01333 // ----------------------------------------------------------------------------- 01334 // BTreeIndex::copyRecordToRidKeyPair 01335 // string version of above templatized function 01336 // ----------------------------------------------------------------------------- 01337 template <> 01338 RIDKeyPair<std::string> BTreeIndex::copyRecordToRidKeyPair<std::string>(std::string rec, RecordId rid ,const int attrByteOffset ) 01339 { 01340 RIDKeyPair<std::string> ridKeyVal; 01341 std::string key = rec.substr(attrByteOffset, 10); 01342 ridKeyVal.set(rid, key); 01343 return ridKeyVal; 01344 } 01345 01346 // ----------------------------------------------------------------------------- 01347 // BTreeIndex::getHighLowVal 01348 // ----------------------------------------------------------------------------- 01349 template <class T> 01350 T BTreeIndex::getHighLowVal(bool high) 01351 { 01352 if( high ) return highValInt; 01353 else return lowValInt; 01354 } 01355 01356 // ----------------------------------------------------------------------------- 01357 // BTreeIndex::getHighLowVal 01358 // double version of above templatized function 01359 // ----------------------------------------------------------------------------- 01360 template<> 01361 double BTreeIndex::getHighLowVal<double>(bool high) 01362 { 01363 if( high ) return highValDouble; 01364 else return lowValDouble; 01365 } 01366 01367 // ----------------------------------------------------------------------------- 01368 // BTreeIndex::getHighLowVal 01369 // string version of above templatized function 01370 // ----------------------------------------------------------------------------- 01371 template<> 01372 std::string BTreeIndex::getHighLowVal<std::string>(bool high) 01373 { 01374 if( high ) return highValString; 01375 else return lowValString; 01376 } 01377 01378 // ----------------------------------------------------------------------------- 01379 // BTreeIndex::copyKey 01380 // ----------------------------------------------------------------------------- 01381 template <class T> 01382 void BTreeIndex::copyKey( T key, Page *nodePagePtr , int index, bool leaf) 01383 { 01384 if( leaf ) ( (LeafNodeInt*)(nodePagePtr) ) -> keyArray[index] = key; 01385 else ( (NonLeafNodeInt*)(nodePagePtr) ) -> keyArray[index] = key; 01386 } 01387 01388 // ----------------------------------------------------------------------------- 01389 // BTreeIndex::copyKey 01390 // double version of above templatized function 01391 // ----------------------------------------------------------------------------- 01392 template <> 01393 void BTreeIndex::copyKey<double>( double key, Page *nodePagePtr, int index, bool leaf) 01394 { 01395 if( leaf ) ( (LeafNodeDouble*)(nodePagePtr) ) -> keyArray[index] = key; 01396 else ( (NonLeafNodeDouble*)(nodePagePtr) ) -> keyArray[index] = key; 01397 } 01398 01399 // ----------------------------------------------------------------------------- 01400 // BTreeIndex::copyKey 01401 // string version of above templatized function 01402 // ----------------------------------------------------------------------------- 01403 template <> 01404 void BTreeIndex::copyKey<std::string>( std::string key, Page *nodePagePtr, int index, bool leaf) 01405 { 01406 if( leaf ) 01407 { 01408 for( int i = 0; i < 10; i++ ) 01409 ( (LeafNodeString*)(nodePagePtr) ) -> keyArray[index][i] = key[i]; 01410 } 01411 else 01412 { 01413 for( int i = 0; i < 10; i++ ) 01414 ( (NonLeafNodeString*)(nodePagePtr) ) -> keyArray[index][i] = key[i]; 01415 } 01416 key.clear(); 01417 } 01418 01419 // ----------------------------------------------------------------------------- 01420 // BTreeIndex::extractKey 01421 // ----------------------------------------------------------------------------- 01422 template <class T> 01423 T BTreeIndex::extractKey(T &value, Page *nodePagePtr , int index, bool leaf) 01424 { 01425 if( leaf ) value = ( (LeafNodeInt*)(nodePagePtr) ) -> keyArray[index]; 01426 else value = ( (NonLeafNodeInt*)(nodePagePtr) ) -> keyArray[index]; 01427 return value; 01428 } 01429 01430 // ----------------------------------------------------------------------------- 01431 // BTreeIndex::extractKey 01432 // double version of above templatized function 01433 // ----------------------------------------------------------------------------- 01434 template <> 01435 double BTreeIndex::extractKey<double>( double &value, Page *nodePagePtr, int index, bool leaf) 01436 { 01437 if( leaf ) value = ( (LeafNodeDouble*)(nodePagePtr) ) -> keyArray[index]; 01438 else value = ( (NonLeafNodeDouble*)(nodePagePtr) ) -> keyArray[index]; 01439 return value; 01440 } 01441 01442 // ----------------------------------------------------------------------------- 01443 // BTreeIndex::extractKey 01444 // string version of above templatized function 01445 // ----------------------------------------------------------------------------- 01446 template <> 01447 std::string BTreeIndex::extractKey<std::string>( std::string &value, Page *nodePagePtr, int index, bool leaf) 01448 { 01449 value.clear(); 01450 if( leaf ) 01451 { 01452 for( int i = 0; i < 10; i++ ) 01453 value+= ( (LeafNodeString*)(nodePagePtr) ) -> keyArray[index][i]; 01454 } 01455 else 01456 { 01457 for( int i = 0; i < 10; i++ ) 01458 value+= ( (NonLeafNodeString*)(nodePagePtr) ) -> keyArray[index][i]; 01459 } 01460 return value; 01461 } 01462 01463 // ----------------------------------------------------------------------------- 01464 // BTreeIndex::extractPageNo 01465 // ----------------------------------------------------------------------------- 01466 PageId BTreeIndex::extractPageNo( PageId &pageNo, Page *nodePagePtr, int index) 01467 { 01468 if( attributeType == INTEGER ) 01469 pageNo = ( (NonLeafNodeInt*)(nodePagePtr) ) -> pageNoArray[index]; 01470 if( attributeType == DOUBLE ) 01471 pageNo = ( (NonLeafNodeDouble*)(nodePagePtr) ) -> pageNoArray[index]; 01472 if( attributeType == STRING ) 01473 pageNo = ( (NonLeafNodeString*)(nodePagePtr) ) -> pageNoArray[index]; 01474 return pageNo; 01475 } 01476 01477 // ----------------------------------------------------------------------------- 01478 // BTreeIndex::copyPageNo 01479 // ----------------------------------------------------------------------------- 01480 void BTreeIndex::copyPageNo( PageId pageNo, Page *nodePagePtr, int index) 01481 { 01482 if( attributeType == INTEGER ) 01483 ( (NonLeafNodeInt*)(nodePagePtr) ) -> pageNoArray[index] = pageNo; 01484 if( attributeType == DOUBLE ) 01485 ( (NonLeafNodeDouble*)(nodePagePtr) ) -> pageNoArray[index] = pageNo; 01486 if( attributeType == STRING ) 01487 ( (NonLeafNodeString*)(nodePagePtr) ) -> pageNoArray[index] = pageNo; 01488 } 01489 01490 // ----------------------------------------------------------------------------- 01491 // BTreeIndex::extractLevel 01492 // ----------------------------------------------------------------------------- 01493 int BTreeIndex::extractLevel( int &level, Page *nodePagePtr) 01494 { 01495 if( attributeType == INTEGER ) 01496 level = ( (NonLeafNodeInt*)(nodePagePtr) ) -> level; 01497 if( attributeType == DOUBLE ) 01498 level = ( (NonLeafNodeDouble*)(nodePagePtr) ) -> level; 01499 if( attributeType == STRING ) 01500 level = ( (NonLeafNodeString*)(nodePagePtr) ) -> level; 01501 return level; 01502 } 01503 01504 // ----------------------------------------------------------------------------- 01505 // BTreeIndex::copyLevel 01506 // ----------------------------------------------------------------------------- 01507 void BTreeIndex::copyLevel( int level, Page *nodePagePtr) 01508 { 01509 if( attributeType == INTEGER ) 01510 ( (NonLeafNodeInt*)(nodePagePtr) ) -> level = level; 01511 if( attributeType == DOUBLE ) 01512 ( (NonLeafNodeDouble*)(nodePagePtr) ) -> level = level; 01513 if( attributeType == STRING ) 01514 ( (NonLeafNodeString*)(nodePagePtr) ) -> level = level; 01515 } 01516 01517 // ----------------------------------------------------------------------------- 01518 // BTreeIndex::copyRid 01519 // ----------------------------------------------------------------------------- 01520 void BTreeIndex::copyRid( RecordId rid, Page *nodePagePtr, int index) 01521 { 01522 if( attributeType == INTEGER ) 01523 ( (LeafNodeInt*)(nodePagePtr) ) -> ridArray[index] = rid; 01524 if( attributeType == DOUBLE ) 01525 ( (LeafNodeDouble*)(nodePagePtr) ) -> ridArray[index] = rid; 01526 if( attributeType == STRING ) 01527 ( (LeafNodeString*)(nodePagePtr) ) -> ridArray[index] = rid; 01528 } 01529 01530 // ----------------------------------------------------------------------------- 01531 // BTreeIndex::extractRid 01532 // ----------------------------------------------------------------------------- 01533 RecordId BTreeIndex::extractRid( RecordId &rid, Page *nodePagePtr, int index) 01534 { 01535 if( attributeType == INTEGER ) 01536 rid = ( (LeafNodeInt*)(nodePagePtr) ) -> ridArray[index]; 01537 if( attributeType == DOUBLE ) 01538 rid = ( (LeafNodeDouble*)(nodePagePtr) ) -> ridArray[index]; 01539 if( attributeType == STRING ) 01540 rid = ( (LeafNodeString*)(nodePagePtr) ) -> ridArray[index]; 01541 return rid; 01542 } 01543 01544 // ----------------------------------------------------------------------------- 01545 // BTreeIndex::copySibPtr 01546 // ----------------------------------------------------------------------------- 01547 void BTreeIndex::copySibPtr(PageId pageNo, Page *nodePagePtr) 01548 { 01549 if( attributeType == INTEGER ) 01550 ( (LeafNodeInt*)(nodePagePtr) ) -> rightSibPageNo = pageNo; 01551 if( attributeType == DOUBLE ) 01552 ( (LeafNodeDouble*)(nodePagePtr) ) -> rightSibPageNo = pageNo; 01553 if( attributeType == STRING ) 01554 ( (LeafNodeString*)(nodePagePtr) ) -> rightSibPageNo = pageNo; 01555 } 01556 01557 // ----------------------------------------------------------------------------- 01558 // BTreeIndex::extractSibPtr 01559 // ----------------------------------------------------------------------------- 01560 PageId BTreeIndex::extractSibPtr(PageId &pageNo, Page *nodePagePtr) 01561 { 01562 if( attributeType == INTEGER ) 01563 pageNo = ( (LeafNodeInt*)(nodePagePtr) ) -> rightSibPageNo; 01564 if( attributeType == DOUBLE ) 01565 pageNo = ( (LeafNodeDouble*)(nodePagePtr) ) -> rightSibPageNo; 01566 if( attributeType == STRING ) 01567 pageNo = ( (LeafNodeString*)(nodePagePtr) ) -> rightSibPageNo; 01568 return pageNo; 01569 } 01570 01571 // ----------------------------------------------------------------------------- 01572 // BTreeIndex::zeroOutNonLeaf 01573 // ----------------------------------------------------------------------------- 01574 void BTreeIndex::zeroOutNonLeaf(Page *currentNode) 01575 { 01576 char zero[11] = "0000000000"; 01577 if( attributeType == INTEGER ) 01578 { 01579 for(int i = 0; i<INTARRAYNONLEAFSIZE; ++i) 01580 { 01581 copyKey<int>(0, currentNode , i, false); 01582 copyPageNo(0, currentNode , i); 01583 } 01584 } 01585 01586 if( attributeType == DOUBLE ) 01587 { 01588 for(int i = 0; i<DOUBLEARRAYNONLEAFSIZE; ++i) 01589 { 01590 copyKey<double>(0, currentNode , i, false); 01591 copyPageNo(0, currentNode , i); 01592 } 01593 } 01594 01595 if( attributeType == STRING ) 01596 { 01597 for(int i = 0; i<STRINGARRAYNONLEAFSIZE; ++i) 01598 { 01599 copyKey<std::string>(zero, currentNode , i, false); 01600 copyPageNo(0, currentNode , i); 01601 } 01602 } 01603 } 01604 01605 // ----------------------------------------------------------------------------- 01606 // BTreeIndex::zeroOutNonLeaf 01607 // ----------------------------------------------------------------------------- 01608 void BTreeIndex::zeroOutLeaf(Page *currentNode) 01609 { 01610 RecordId zeroRid; 01611 zeroRid.page_number = 0; 01612 char zero[11] = "0000000000"; 01613 if( attributeType == INTEGER ) 01614 { 01615 for(int i = 0; i<INTARRAYLEAFSIZE; ++i) 01616 { 01617 copyKey<int>(0, currentNode , i, true); 01618 copyRid(zeroRid, currentNode , i); 01619 } 01620 } 01621 01622 if( attributeType == DOUBLE ) 01623 { 01624 for(int i = 0; i<DOUBLEARRAYLEAFSIZE; ++i) 01625 { 01626 copyKey<double>(0, currentNode , i, true); 01627 copyRid(zeroRid, currentNode , i); 01628 } 01629 } 01630 01631 if( attributeType == STRING ) 01632 { 01633 for(int i = 0; i<STRINGARRAYLEAFSIZE; ++i) 01634 { 01635 copyKey<std::string>(zero, currentNode , i, true); 01636 copyRid(zeroRid, currentNode , i); 01637 } 01638 } 01639 } 01640 01641 // ----------------------------------------------------------------------------- 01642 // BTreeIndex::printTreeExternal 01643 // ----------------------------------------------------------------------------- 01644 void BTreeIndex::printTreeExternal() 01645 { 01646 switch(attributeType) 01647 { 01648 case INTEGER: printTree<int>( rootPageNum, false); break; 01649 case DOUBLE: printTree<double>( rootPageNum, false); break; 01650 case STRING: printTree<std::string>( rootPageNum, false); break; 01651 default: break; 01652 } 01653 } 01654 01655 // ----------------------------------------------------------------------------- 01656 // BTreeIndex::printTree 01657 // ----------------------------------------------------------------------------- 01658 template <class T> 01659 void BTreeIndex::printTree(PageId pageNum , bool isLeaf) 01660 { 01661 int lastIndexUsed; 01662 Page *currentNode; 01663 PageId pNum1; 01664 T tKey1; 01665 bufMgr->readPage( file, pageNum , currentNode ); 01666 01667 if( !isLeaf ) 01668 { 01669 if(*(int*)currentNode == 0) 01670 { 01671 isNonLeafFull( currentNode, lastIndexUsed); 01672 01673 for(int i=0; i< lastIndexUsed;i++) 01674 { 01675 extractPageNo(pNum1, currentNode, i ); 01676 std::cout << pNum1 << " | "; 01677 extractKey<T>(tKey1, currentNode, i , false); 01678 std::cout << tKey1 << " | "; 01679 } 01680 extractPageNo(pNum1, currentNode, lastIndexUsed ); 01681 std::cout << pNum1 << " "; 01682 std::cout << std::endl; 01683 01684 for(int i=0; i< lastIndexUsed;i++) 01685 { 01686 extractPageNo(pNum1, currentNode, i ); 01687 printTree<T>(pNum1, false); 01688 } 01689 extractPageNo(pNum1, currentNode, lastIndexUsed ); 01690 printTree<T>(pNum1, false); 01691 bufMgr->unPinPage(file, pageNum, 0); 01692 } 01693 else 01694 { 01695 isNonLeafFull( currentNode, lastIndexUsed); 01696 01697 for(int i=0; i< lastIndexUsed;i++) 01698 { 01699 extractPageNo(pNum1, currentNode, i ); 01700 std::cout << pNum1 << " | "; 01701 extractKey<T>(tKey1, currentNode, i , false); 01702 std::cout << tKey1 << " | "; 01703 } 01704 extractPageNo(pNum1, currentNode, lastIndexUsed ); 01705 std::cout << pNum1 << " "; 01706 std::cout << std::endl; 01707 01708 for(int i=0; i< lastIndexUsed;i++) 01709 { 01710 extractPageNo(pNum1, currentNode, i ); 01711 printTree<T>(pNum1, true); 01712 } 01713 extractPageNo(pNum1, currentNode, lastIndexUsed ); 01714 printTree<T>(pNum1, true); 01715 bufMgr->unPinPage(file, pageNum, 0); 01716 } 01717 return; 01718 } 01719 01720 //for leafNode 01721 isLeafFull( currentNode,lastIndexUsed); 01722 for(int i=0; i<= lastIndexUsed;i++) 01723 { 01724 extractKey<T>(tKey1, currentNode, i , true); 01725 std::cout << tKey1 << " "; 01726 } 01727 std::cout << std::endl; 01728 bufMgr->unPinPage(file, pageNum, 0); 01729 } 01730 01731 }