Пример #1
0
//-------------------------------------------------------------------
// 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;
}
Пример #2
0
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;
}
Пример #3
0
//*********************************************
//***	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);
}
Пример #4
0
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;
	}
}
Пример #5
0
//--------------------------------------------------------------------
// 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;
}
Пример #6
0
//--------------------------------------------------------------------
// 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;
}
Пример #7
0
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;
}
Пример #8
0
//*****************************************************
//***	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);
}
Пример #9
0
//*********************************************************************
//***	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);
}
Пример #10
0
//*****************************************************
//***	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);
}
Пример #11
0
//*****************************************************
//***	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);
}
Пример #12
0
//---------------------------------------------------------------
// 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;
}
Пример #13
0
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;
}
Пример #14
0
//---------------------------------------------------------------
// 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;
}
Пример #15
0
//-------------------------------------------------------------------
// 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;
}