//------------------------------------------------------------------- // Sort::PassOneAndBeyond // // Input : Number of files generated by Pass 0 // Output : None // Return : OK if Pass 1 and beyond succeed, FAIL otherwise //------------------------------------------------------------------- Status Sort::PassOneAndBeyond(int numFiles) { passOneBeyondRuns = 0; int numPass = 1, numStartFiles = passZeroRuns, numEndFiles; do { numEndFiles = 0; if (OneMergePass(numStartFiles, numPass, numEndFiles) != OK ) return ReturnFAIL("OneMergePass failed."); numStartFiles = numEndFiles; numPass++; } while (numEndFiles > 1); // Write out Status s; RecordID rid; char *recPtr = (char *)malloc(_recLength); int recLen = _recLength; char *fileName = CreateTempFilename(_outFile,numPass-1,passOneBeyondRuns); HeapFile file(fileName,s); // read temp file if (s != OK) return ReturnFAIL("Opening PassOneAndBeyond temp file failed."); Scan *scan = file.OpenScan(s); if (s != OK) return ReturnFAIL("Opening scan in PassOneAndBeyond failed."); HeapFile output(_outFile, s); if (s != OK) return ReturnFAIL("Opening output file in PassOneAndBeyond failed."); while (scan->GetNext(rid,recPtr,recLen) == OK) { output.InsertRecord(recPtr,recLen,rid); } delete fileName; delete scan; free(recPtr); file.DeleteFile(); return OK; }
HeapFile *SortFile(HeapFile *S, int len, int offset) { Status s; Scan *scan; scan = S->OpenScan(s); if (s != OK) { cerr << "ERROR : cannot open scan on the heapfile to sort.\n"; } // // Scan the HeapFile S, new a B+Tree and insert the records into B+Tree. // BTreeFile *btree; btree = new BTreeFile (s, "BTree", ATTR_INT, sizeof(int)); char *recPtr = new char[len]; int recLen = len; RecordID rid; while (scan->GetNext(rid, recPtr, recLen) == OK) { btree->Insert(recPtr + offset, rid); } delete scan; HeapFile *sorted; sorted = new HeapFile(NULL, s); // create a temp HeapFile if (s != OK) { cerr << "Cannot create new file for sortedS\n"; } // // Now scan the B+-Tree and insert the records into a // new (sorted) HeapFile. // BTreeFileScan *btreeScan; btreeScan = (BTreeFileScan *)btree->OpenScan(NULL, NULL); int key; while (btreeScan->GetNext(rid, &key) == OK) { S->GetRecord (rid, recPtr, recLen); sorted->InsertRecord (recPtr, recLen, rid); } btree->DestroyFile(); delete btree; delete btreeScan; delete [] recPtr; return sorted; }
//********************************************* //*** Test 5: Test some error conditions *** bool HeapDriver::Test5() { cout << "\n Test 5: Test some error conditions\n"; Status status = OK; Scan* scan = 0; RecordID rid; // Open the heap file HeapFile f("file_1", status); if (status != OK) cerr << "*** Error opening heap file\n"; if ( status == OK ) { cout << " - Try to change the size of a record\n"; scan = f.OpenScan(status); if (status != OK) cerr << "*** Error opening scan\n"; } // Try to change the size of a record -- should fail if ( status == OK ) { int len; Rec rec; len = sizeof(rec); status = scan->GetNext(rid, (char *)&rec, len); if ( status != OK ) cerr << "*** Error reading first record\n"; else { status = f.UpdateRecord( rid, (char*)&rec, len-1 ); TestFailure( status, HEAPFILE, "Shortening a record" ); if ( status == OK ) { status = f.UpdateRecord( rid, (char*)&rec, len+1 ); TestFailure( status, HEAPFILE, "Lengthening a record" ); } } } delete scan; // Try to insert a too long record -- should fail if ( status == OK ) { cout << " - Try to insert a record that's too long\n"; char record[MINIBASE_PAGESIZE] = ""; status = f.InsertRecord( record, MINIBASE_PAGESIZE, rid ); TestFailure( status, HEAPFILE, "Inserting a too-long record" ); } if ( status == OK ) cout << " Test 5 completed successfully.\n"; return (status == OK); }
Sort::Sort( char *inFile, // Name of unsorted heapfile. char *outFile, // Name of sorted heapfile. int numFields, // Number of fields in input records. AttrType fieldTypes[], // Array containing field types of input records. // i.e. index of in[] ranges from 0 to (len_in - 1) short fieldSizes[], // Array containing field sizes of input records. int sortKeyIndex, // The number of the field to sort on. // fld_no ranges from 0 to (len_in - 1). TupleOrder sortOrder, // ASCENDING, DESCENDING int numBufPages, // Number of buffer pages available for sorting. Status &s) { // Initialize private instance variables _recLength = 0; for (int i=0;i<numFields;i++) { _recLength += fieldSizes[i]; } for (int i=0;i<sortKeyIndex;i++) { _sortKeyOffset += fieldSizes[i]; } _numBufPages = numBufPages; _inFile = inFile; _outFile = outFile; _fieldSizes = fieldSizes; _sortKeyIndex = sortKeyIndex; _sortType = fieldTypes[_sortKeyIndex]; _sortOrder = sortOrder; // Pass 0 int numTempFiles = 0; if (PassZero(numTempFiles) != OK) { std::cerr << "PassZero failed." << std::endl; return; } if (numTempFiles == 1) { // done, write out RecordID rid; char *recPtr = (char *)malloc(_recLength); int recLen = _recLength; char *fileName = CreateTempFilename(_outFile,0,0); HeapFile passZeroFile(fileName,s); // read temp file if (s != OK) { std::cerr << "Opening PassZero temp file failed." << std::endl; return; } Scan *scan = passZeroFile.OpenScan(s); if (s != OK) { std::cerr << "Opening scan in PassZero failed." << std::endl; return; } HeapFile output(_outFile, s); if (s != OK) { std::cerr << "Opening output file in PassZero failed." << std::endl; return; } while (scan->GetNext(rid,recPtr,recLen) == OK) { output.InsertRecord(recPtr,recLen,rid); } delete fileName; delete scan; free(recPtr); passZeroFile.DeleteFile(); s = OK; } else { // more passes if (PassOneAndBeyond(numTempFiles) != OK) { std::cerr << "PassOneAndBeyond failed." << std::endl; return; } s = OK; } }
//-------------------------------------------------------------------- // JoinSpec::PrintRelation // // Purpose : Prints the relation represented by a JoinSpec. // Input : filename - The file to which to write the output. When NULL (default) // output is written to the screen. // Output : None // Return : None //-------------------------------------------------------------------- void JoinSpec::PrintRelation(const char* filename) { Status s; Scan *scan = file->OpenScan(s); if (s != OK) { std::cerr << "Cannot open scan on HeapFile in PrintRelation."<< std::endl; return; } FILE* f; if(filename == NULL) { f = stdout; } else { f = fopen(filename, "w"); if (f == NULL) { std::cerr << "Cannot open file " << filename << " for writing.\n"; return; } } char* rec = new char[recLen]; int len = recLen; RecordID rid; while(scan->GetNext(rid, rec, len) != DONE) { if(len != recLen) { std::cerr << "Unexpected record length in print method." << std::endl; return; } for(int i = 0; i < numOfAttr; i++) { fprintf(f, "%d ", *(((int*)(rec)) + i)); } fprintf(f, "\n"); } if(filename != NULL) { fclose(f); } delete [] rec; }
//-------------------------------------------------------------------- // JoinMethod::SortFile // // Purpose : Sorts a relation by an integer attribute. // Input : file - pointer to the HeapFile to be sorted. // len - length of the records in the file. (assume fixed size). // offset - offset of the sort attribute from the beginning of the record. // Method : We create a B+-Tree using that attribute as the key. Then // we scan the B+-Tree and insert the records into a new // HeapFile. he HeapFile guarantees that the order of // insertion will be the same as the order of scan later. // Return : The new sorted relation/HeapFile. //-------------------------------------------------------------------- HeapFile* JoinMethod::SortHeapFile(HeapFile *file, int len, int offset) { Status s; Scan *scan; scan = file->OpenScan(s); if (s != OK) { std::cerr << "ERROR : cannot open scan on the heapfile to sort." << std::endl; } // // Scan the HeapFile S, create a new B+Tree and insert the records into B+Tree. // BTreeFile *btree; btree = new BTreeFile (s, "BTree"); char* recPtr = new char[len]; int recLen = len; RecordID rid; char* recKey = new char[100]; while (scan->GetNext(rid, recPtr, recLen) == OK) { int* valPtr = (int*)(recPtr+offset); int val = *valPtr; toString(val,recKey); btree->Insert(recKey, rid); } delete scan; delete [] recKey; //std::cout << "created B+ tree!" << std::endl; HeapFile *sorted = new HeapFile(NULL, s); // create a temp HeapFile if (s != OK) { std::cerr << "Cannot create new file for sortedS\n"; } // Now scan the B+-Tree and insert the records into a // new (sorted) HeapFile. BTreeFileScan* btreeScan = btree->OpenScan(NULL, NULL); //int key; char* keyPtr; while (btreeScan->GetNext(rid, keyPtr) == OK) { //std::cout << "scanning " << rid << " " << keyPtr << std::endl; file->GetRecord (rid, recPtr, recLen); sorted->InsertRecord (recPtr, recLen, rid); } btree->DestroyFile(); delete btree; delete btreeScan; delete [] recPtr; return sorted; }
HeapFile* IndexNestedLoopJoin(JoinSpec specOfR, JoinSpec specOfS) { Status status = OK; // Create a HeapFile for join results HeapFile* joinedFile = new HeapFile(NULL, status); if (OK != status) { cerr << "ERROR: cannot create a file for the joined relation.\n"; return NULL; } int recLenR = specOfR.recLen; int recLenS = specOfS.recLen; int recLenJoined = recLenR + recLenS; char* recR = new char[recLenR]; char* recS = new char[recLenS]; char* recJoined = new char[recLenJoined]; RecordID ridR, ridS, ridJoined; // Build the B+-tree index on the inner relation (S) Scan* scanS = specOfS.file->OpenScan(status); if (OK != status) { cerr << "ERROR: cannot open scan on the relation S heap file.\n"; return NULL; } BTreeFile* bTree = new BTreeFile(status, "IJBT", ATTR_INT, sizeof(int)); while (OK == scanS->GetNext(ridS, recS, recLenS)) { bTree->Insert(recS + specOfS.offset, ridS); } delete scanS; // Iterate through the outer relation (R) and join Scan* scanR = specOfR.file->OpenScan(status); if (OK != status) { cerr << "ERROR: cannot open scan on the relation R heap file.\n"; return NULL; } while (OK == scanR->GetNext(ridR, recR, recLenR)) { int* joinArgR = (int*)&recR[specOfR.offset]; BTreeFileScan* bTreeScan = (BTreeFileScan*)bTree->OpenSearchScan(joinArgR, joinArgR); int key; while (OK == bTreeScan->GetNext(ridS, &key)) { specOfS.file->GetRecord(ridS, recS, recLenS); MakeNewRecord(recJoined, recR, recS, recLenR, recLenS); joinedFile->InsertRecord(recJoined, recLenJoined, ridJoined); } delete bTreeScan; } // Release the allocated resources delete scanR; delete[] recR; delete[] recS; delete[] recJoined; delete bTree; return joinedFile; }
//***************************************************** //*** Test 1: Insert and scan fixed-size records *** bool HeapDriver::Test1() { cout << "\n Test 1: Insert and scan fixed-size records\n"; Status status = OK; RecordID rid; // Initalize the heap file cout << " - Create a heap file\n"; HeapFile f("file_1", status); if (status != OK) cerr << "*** Could not create heap file\n"; else if ( MINIBASE_BM->GetNumOfUnpinnedBuffers() != MINIBASE_BM->GetNumOfBuffers() ) { cerr << "*** The heap file has left pages pinned\n"; status = FAIL; } if ( status == OK ) { // Insert records into the HeapFile cout << " - Add " << choice << " records to the file\n"; for (int i =0; i<choice && status == OK; i++) { Rec rec = { i, i*2.5 }; sprintf(rec.name, "record %i",i); status = f.InsertRecord((char *)&rec, reclen, rid); if (status != OK) cerr << "*** Error inserting record " << i << endl; else if ( MINIBASE_BM->GetNumOfUnpinnedBuffers() != MINIBASE_BM->GetNumOfBuffers() ) { cerr << "*** Insertion left a page pinned\n"; status = FAIL; } } // Check the total number of records if ( f.GetNumOfRecords() != choice ) { status = FAIL; cerr << "*** File reports " << f.GetNumOfRecords() << " records, not " << choice << endl; } } // Prepare to scan the records in the HeapFile Scan* scan = 0; if ( status == OK ) { cout << " - Scan the records just inserted\n"; scan = f.OpenScan(status); if (status != OK) cerr << "*** Error opening scan\n"; else if ( MINIBASE_BM->GetNumOfUnpinnedBuffers() == MINIBASE_BM->GetNumOfBuffers() ) { cerr << "*** The heap-file scan has not pinned the first page\n"; status = FAIL; } } // Scan the records in heap file and check them. // The scan must return the insertion order. if ( status == OK ) { int len, i = 0; Rec rec; // State the length of allocated memory len = sizeof(rec); // Scan the next record while ( (status = scan->GetNext(rid, (char *)&rec, len)) == OK ) { // Check the record if ( len != reclen ) { cerr << "*** Record " << i << " had unexpected length " << len << endl; status = FAIL; break; } else if ( MINIBASE_BM->GetNumOfUnpinnedBuffers() == MINIBASE_BM->GetNumOfBuffers() && i != choice - 1) { cerr << "*** The heap-file scan has not left its page pinned\n"; status = FAIL; break; } char name[ sizeof rec.name ]; sprintf( name, "record %i", i ); if( rec.ival != i || rec.fval != i*2.5 || 0 != strcmp( rec.name, name ) ) { cerr << "*** Record " << i << " differs from what we inserted\n"; status = FAIL; break; } ++i; len = sizeof(rec); } // Finish scan if ( status == DONE ) { if ( MINIBASE_BM->GetNumOfUnpinnedBuffers() != MINIBASE_BM->GetNumOfBuffers() ) cerr << "*** The heap-file scan has not unpinned its page after finishing\n"; else if ( i == choice ) status = OK; else cerr << "*** Scanned " << i << " records instead of " << choice << endl; } } delete scan; if ( status == OK ) cout << " Test 1 completed successfully.\n"; return (status == OK); }
//********************************************************************* //*** Test 4: Temporary heap files and variable-length records *** bool HeapDriver::Test4() { cout << "\n Test 4: Temporary heap files and variable-length records\n"; Status status = OK; Scan* scan = 0; RecordID rid; cout << " - Create a temporary heap file\n"; HeapFile f( 0, status ); if (status != OK) cerr << "*** Error creating temp file\n"; if ( status == OK ) cout << " - Add variable-sized records\n"; unsigned recSize = MINIBASE_PAGESIZE / 2; /* We use half a page as the starting size so that a single page won't hold more than one record. We add a series of records at this size, then halve the size and add some more, and so on. We store the index number of each record on the record itself. */ unsigned numRecs = 0; char record[MINIBASE_PAGESIZE] = ""; for ( ; recSize >= (sizeof numRecs + sizeof recSize) && status == OK; recSize /= 2 ) for ( unsigned i=0; i < 10 && status == OK; ++i, ++numRecs ) { memcpy( record, &numRecs, sizeof numRecs ); memcpy( record+(sizeof numRecs), &recSize, sizeof recSize ); status = f.InsertRecord( record, recSize, rid ); if ( status != OK ) cerr << "*** Failed inserting record " << numRecs << ", of size " << recSize << endl; } int *seen = new int[numRecs]; for (int i = 0; i < (int)numRecs; i++) { seen[i] = false; } memset( seen, 0, sizeof seen ); if ( status == OK ) { cout << " - Check that all the records were inserted\n"; scan = f.OpenScan(status); if (status != OK) cerr << "*** Error opening scan\n"; } if ( status == OK ) { int len; while (true) { // State the length of allocated memory len = sizeof(char) * 4096; if ((status = scan->GetNext(rid, record, len)) != OK ) break; unsigned recNum; memcpy( &recNum, record, sizeof recNum ); // Check duplicate records if ( seen[recNum]) { cerr << "*** Found record " << recNum << " twice!\n"; status = FAIL; break; } seen[recNum] = true; // Check size memcpy( &recSize, record + sizeof recNum, sizeof recSize ); if ( recSize != (unsigned)len ) { cerr << "*** Record size mismatch: stored " << recSize << ", but retrieved " << len << endl; status = FAIL; break; } --numRecs; } if ( status == DONE ) if ( numRecs ) cerr << "*** Scan missed " << numRecs << " records\n"; else status = OK; } delete scan; if ( status == OK ) cout << " Test 4 completed successfully.\n"; return (status == OK); }
//***************************************************** //*** Test 3: Update fixed-size records *** bool HeapDriver::Test3() { cout << "\n Test 3: Update fixed-size records\n"; Status status = OK; Scan* scan = 0; RecordID rid; // Open heap file cout << " - Open the same heap file as tests 1 and 2\n"; HeapFile f("file_1", status); if (status != OK) cerr << "*** Error opening heap file\n"; if ( status == OK ) { cout << " - Change the records\n"; scan = f.OpenScan(status); if (status != OK) cerr << "*** Error opening scan\n"; } if ( status == OK ) { int len, i = 0; Rec rec; // State the length of allocated memory len = sizeof(rec); while ( (status = scan->GetNext(rid, (char *)&rec, len)) == OK ) { rec.fval = (float)7*i; // We'll check that i==rec.ival below. status = f.UpdateRecord( rid, (char*)&rec, len ); if ( status != OK ) { cerr << "*** Error updating record " << i << endl; break; } i += 2; // Recall, we deleted every other record above. len = sizeof(rec); } if ( status == DONE ) status = OK; } delete scan; scan = 0; if ( status == OK && MINIBASE_BM->GetNumOfUnpinnedBuffers() != MINIBASE_BM->GetNumOfBuffers() ) { cerr << "*** Updating left pages pinned\n"; status = FAIL; } if ( status == OK ) { cout << " - Check that the updates are really there\n"; scan = f.OpenScan(status); if (status != OK) cerr << "*** Error opening scan\n"; } // Check whether the records are really updated if ( status == OK ) { int len, i = 0; Rec rec, rec2; len = sizeof(rec); while ( (status = scan->GetNext(rid, (char *)&rec, len)) == OK ) { // While we're at it, Test the getRecord method too. status = f.GetRecord( rid, (char*)&rec2, len ); if ( status != OK ) { cerr << "*** Error getting record " << i << endl; break; } if( rec.ival != i || rec.fval != i*7 || rec2.ival != i || rec2.fval != i*7 ) { cerr << "*** Record " << i << " differs from our " "update\n"; status = FAIL; break; } i += 2; // Because we deleted the odd ones... len = sizeof(rec); } if ( status == DONE ) status = OK; } delete scan; if ( status == OK ) cout << " Test 3 completed successfully.\n"; return (status == OK); }
//***************************************************** //*** Test 2: Delete fixed-size records *** bool HeapDriver::Test2() { cout << "\n Test 2: Delete fixed-size records\n"; Status status = OK; Scan* scan = 0; RecordID rid; // Open the heap file created by test case 1 cout << " - Open the same heap file as Test 1\n"; HeapFile f("file_1", status); if (status != OK) cerr << "*** Error opening heap file\n"; if ( status == OK ) { cout << " - Delete half the records\n"; scan = f.OpenScan(status); if (status != OK) cerr << "*** Error opening scan\n"; } // Delete half of the records if ( status == OK ) { int len, i = 0; Rec rec; // State the length of allocated memory len = sizeof(rec); while ( (status = scan->GetNext(rid, (char *)&rec, len)) == OK ) { if ( i & 1 ) // Delete the odd-numbered ones. { status = f.DeleteRecord( rid ); if ( status != OK ) { cerr << "*** Error deleting record " << i << endl; break; } } ++i; len = sizeof(rec); } if ( status == DONE ) status = OK; } delete scan; scan = 0; if ( status == OK && MINIBASE_BM->GetNumOfUnpinnedBuffers() != MINIBASE_BM->GetNumOfBuffers() ) { cerr << "*** Deletion left a page pinned\n"; status = FAIL; } if ( status == OK ) { cout << " - Scan the remaining records\n"; scan = f.OpenScan(status); if (status != OK) cerr << "*** Error opening scan\n"; } // Check the remaining records if ( status == OK ) { int len, i = 0; Rec rec; // State the length of allocated memory len = sizeof(rec); while ( (status = scan->GetNext(rid, (char *)&rec, len)) == OK ) { // Check retrieved record if( rec.ival != i || rec.fval != i*2.5 ) { cerr << "*** Record " << i << " differs from what we " "inserted\n"; status = FAIL; break; } i += 2; // Because we deleted the odd ones... len = sizeof(rec); } if ( status == DONE ) status = OK; } delete scan; if ( status == OK ) cout << " Test 2 completed successfully.\n"; return (status == OK); }
//--------------------------------------------------------------- // TupleNestedLoop::Execute // // Input: left - The left relation to join. // right - The right relation to join. // Output: out - The relation to hold the ouptut. // Return: OK if join completed succesfully. FAIL otherwise. // // Purpose: Performs a nested loop join on relations left and right // a tuple a time. You can assume that left is the outer // relation and right is the inner relation. //--------------------------------------------------------------- Status TupleNestedLoops::Execute(JoinSpec& left, JoinSpec& right, JoinSpec& out) { JoinMethod::Execute(left, right, out); // Create the temporary heapfile Status st; HeapFile *tmpHeap = new HeapFile(NULL, st); if (st != OK) { std::cerr << "Failed to create output heapfile." << std::endl; return FAIL; } // Open scan on left relation Status leftStatus; Scan *leftScan = left.file->OpenScan(leftStatus); if (leftStatus != OK) { std::cerr << "Failed to open scan on left relation." << std::endl; return FAIL; } // Loop over the left relation char *leftRec = new char[left.recLen]; while (true) { RecordID leftRid; leftStatus = leftScan->GetNext(leftRid, leftRec, left.recLen); if (leftStatus == DONE) break; if (leftStatus != OK) return FAIL; // The join attribute on left relation int *leftJoinValPtr = (int*)(leftRec + left.offset); // Open scan on right relation Status rightStatus; Scan *rightScan = right.file->OpenScan(rightStatus); if (rightStatus != OK) { std::cerr << "Failed to open scan on right relation." << std::endl; return FAIL; } // Loop over right relation char *rightRec = new char[right.recLen]; while (true) { RecordID rightRid; rightStatus = rightScan->GetNext(rightRid, rightRec, right.recLen); if (rightStatus == DONE) break; if (rightStatus != OK) return FAIL; // Compare join attribute int *rightJoinValPtr = (int*)(rightRec + right.offset); if (*leftJoinValPtr == *rightJoinValPtr) { // Create the record and insert into tmpHeap... char *joinedRec = new char[out.recLen]; MakeNewRecord(joinedRec, leftRec, rightRec, left, right); RecordID insertedRid; Status tmpStatus = tmpHeap->InsertRecord(joinedRec, out.recLen, insertedRid); if (tmpStatus != OK) { std::cerr << "Failed to insert tuple into output heapfile." << std::endl; return FAIL; } delete [] joinedRec; } } delete [] rightRec; delete rightScan; } out.file = tmpHeap; delete leftScan; delete [] leftRec; return OK; }
HeapFile* BlockNestedLoopJoin(JoinSpec specOfR, JoinSpec specOfS, int B) { Status status = OK; // Create a HeapFile for join results HeapFile* joinedFile = new HeapFile(NULL, status); if (OK != status) { cerr << "ERROR: cannot create a file for the joined relation.\n"; return NULL; } int recLenR = specOfR.recLen; int recLenS = specOfS.recLen; int recLenJoined = recLenR + recLenS; char* recBlockR = new char[B]; // Allocate memory for the block char* recS = new char[recLenS]; char* recJoined = new char[recLenJoined]; RecordID ridR, ridS, ridJoined; Scan* scanR = specOfR.file->OpenScan(status); if (OK != status) { cerr << "ERROR: cannot open scan on the relation R heap file.\n"; return NULL; } const int recordsPerBlock = B / recLenR; bool lastBlock = false; while (!lastBlock) { // Fill the block int i; for (i = 0; i < recordsPerBlock; i++) { if (OK != scanR->GetNext(ridR, recBlockR + i*recLenR, recLenR)) { lastBlock = true; break; } } int lastRecordIndex = i; Scan* scanS = specOfS.file->OpenScan(status); if (OK != status) { cerr << "ERROR: cannot open scan on the relation S heap file.\n"; return NULL; } while (OK == scanS->GetNext(ridS, recS, recLenS)) { int* joinArgS = (int*)&recS[specOfS.offset]; for (int currentRecordIndex = 0; currentRecordIndex < lastRecordIndex; currentRecordIndex++) { char* currentRecordPtr = recBlockR + (currentRecordIndex * recLenR); int* joinArgR = (int*)(currentRecordPtr + specOfR.offset); if (*joinArgR == *joinArgS) { MakeNewRecord(recJoined, currentRecordPtr, recS, recLenR, recLenS); joinedFile->InsertRecord(recJoined, recLenJoined, ridJoined); } } } delete scanS; } // Release the allocated resources delete scanR; delete[] recBlockR; delete[] recS; delete[] recJoined; return joinedFile; }
//--------------------------------------------------------------- // BlockNestedLoop::Execute // // Input: left - The left relation to join. // right - The right relation to join. // Output: out - The relation to hold the ouptut. // Return: OK if join completed succesfully. FAIL otherwise. // // Purpose: Performs a block nested loops join on the specified relations. // You can find a specification of this algorithm on page 455. You should // choose the smaller of the two relations to be the outer relation, but you // should make sure to concatenate the tuples in order <left, right> when // producing output. The block size can be specified in the constructor, // and is stored in the variable blockSize. //--------------------------------------------------------------- Status BlockNestedLoops::Execute(JoinSpec& left, JoinSpec& right, JoinSpec& out) { JoinMethod::Execute(left, right, out); Status s; HeapFile* tmpHeap = new HeapFile(NULL, s); if (s != OK) { std::cout << "Creating new Heap File Failed" << std::endl; return FAIL; } Scan * leftScan = left.file->OpenScan(s); if (s != OK) { std::cout << "Open scan left failed" << std::endl; return FAIL; } Scan * rightScan = right.file->OpenScan(s); if (s != OK) { std::cout << "Open scan left failed" << std::endl; return FAIL; } RecordID leftRid, rightRid, rightFirstRid, outRid; // array to hold the "block" in memory char* blockArray = new char[left.recLen * blockSize]; int blockArraySize = 0; // size in case of half full block int* leftCurrRec = (int *)blockArray; int* leftRec = new int[left.numOfAttr]; int* rightRec = new int[right.numOfAttr]; int leftRecLen = left.recLen; int rightRecLen = right.recLen; char* newRec = new char[left.recLen + right.recLen]; rightFirstRid = rightScan->currRid; Status st = OK; while (true) { // fill the block with as many records as possible if (blockArraySize < blockSize) { st = leftScan->GetNext(leftRid, (char *)leftRec, leftRecLen); if (st != DONE) { memcpy(blockArray + left.recLen * blockArraySize, leftRec, left.recLen); blockArraySize++; continue; } } // scan through the right, and scan the block in memory for joins while (rightScan->GetNext(rightRid, (char *)rightRec, rightRecLen) != DONE) { for (int j = 0; j < blockSize; j++) { if (j >= blockArraySize) { break; } leftCurrRec = (int *) (blockArray + left.recLen * j); if (leftCurrRec[left.joinAttr] == rightRec[right.joinAttr]) { MakeNewRecord(newRec, (char *)leftCurrRec, (char *)rightRec, left, right); tmpHeap->InsertRecord(newRec, left.recLen + right.recLen, outRid); } } } rightScan->MoveTo(rightFirstRid); blockArraySize = 0; if (st == DONE) { break; } } out.file = tmpHeap; //std::cout << "NUM BNL: " << tmpHeap->GetNumOfRecords() << std::endl; delete leftScan; delete rightScan; delete blockArray; delete leftRec; delete rightRec; delete newRec; return OK; }
//------------------------------------------------------------------- // Sort::PassZero // // Input : None // Output : Number of temp files generated after this pass // Return : OK if Pass 0 succeeds, FAIL otherwise //------------------------------------------------------------------- Status Sort::PassZero(int &numTempFiles) { // Get input file Status status; HeapFile inputFile(_inFile, status); if (status != OK) return ReturnFAIL("Opening input file in PassZero function failed."); int numRecords = inputFile.GetNumOfRecords(); int recCounter = 0, globalRecCounter = 0; // Allocate memory int areaSize = MINIBASE_PAGESIZE * _numBufPages; char *area = (char *)malloc(areaSize); char *areaPtr = area; RecordID rid; char *recPtr = (char *)malloc(_recLength); int recLen = _recLength; int numRecForSort = std::min(areaSize/_recLength,numRecords); // number of rec in sorting area at once // Open Scan Scan *scan = inputFile.OpenScan(status); if (status != OK) return ReturnFAIL("Opening scan in PassZero function failed."); // Sort passZeroRuns = 0; if (areaSize >= _recLength) { // can fit at least one record while (scan->GetNext(rid,recPtr,recLen) == OK) { recCounter++; globalRecCounter++; // add to memory if (memcpy(areaPtr,recPtr,recLen) != areaPtr) return ReturnFAIL("Reading records to memory in PassZero function failed."); areaPtr += recLen; areaSize -= recLen; if (areaSize < _recLength || globalRecCounter == numRecords) { // can't fit another rec or all recs have been added // sort switch (_sortType) { case attrInteger: std::qsort(area,recCounter,_recLength,CompareInt); break; case attrString: std::qsort(area,recCounter,_recLength,CompareString); default: break; } // write out char *fileName = CreateTempFilename(_outFile,0,passZeroRuns); passZeroRuns++; HeapFile *tempFile = new HeapFile(fileName,status); if (status != OK) return ReturnFAIL("Opening temp file in PassZero function failed."); areaPtr = area; while (recCounter > 0) { // insert tempFile->InsertRecord(areaPtr,_recLength,rid); recCounter--; areaPtr += _recLength; } numTempFiles++; areaSize = MINIBASE_PAGESIZE * _numBufPages; areaPtr = area; // reset delete fileName; delete tempFile; } } } free(area); free(recPtr); delete scan; return OK; }