/* ---- This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- */ #include "BPTreeOperators.h" #include #include #include #include "Algebra.h" #include "AlgebraManager.h" #include "Attribute.h" #include "Algebras/FText/FTextAlgebra.h" #include "ListUtils.h" #include "NestedList.h" #include "NList.h" #include "QueryProcessor.h" #include "Algebras/Relation-C++/RelationAlgebra.h" #include "Symbols.h" #include "StandardTypes.h" #include "Stream.h" #include "Algebras/TupleIdentifier/TupleIdentifier.h" #include "TypeConstructor.h" #include "BPTreeNode.h" #include "BPTreeSearchEnumerator.h" #include "TreeHeaderMarker.h" //#define DEBUG using listutils::isTupleStream; using std::memcpy; using namespace std; extern AlgebraManager *am; extern NestedList* nl; extern QueryProcessor* qp; namespace fialgebra { // Standard Cache-Groesse in Seiten size_t BPTreeOperators::defaultCacheSize = 1000; Operator& BPTreeOperators::GetCreatefbtreeOperator() { return createfbtreeOp; } Operator& BPTreeOperators::GetInsertfbtreeOperator() { return insertfbtreeOp; } Operator& BPTreeOperators::GetDeletefbtreeOperator() { return deletefbtreeOp; } Operator& BPTreeOperators::GetRebuildfbtreeOperator() { return rebuildfbtreeOp; } Operator& BPTreeOperators::GetBulkloadfbtreeOperator() { return bulkloadfbtreeOp; } // // Info siehe *.h // // Operators // // frange Operator& BPTreeOperators::GetFrangeOperator() { return frangeOp; } // fleftrange Operator& BPTreeOperators::GetFleftrangeOperator() { return fleftrangeOp; } // frightrange Operator& BPTreeOperators::GetFrightrangeOperator() { return frightrangeOp; } // fexactmatch Operator& BPTreeOperators::GetFexactmatchOperator() { return fexactmatchOp; } // // OperatorSpec // // frange OperatorSpec BPTreeOperators::frangeOperatorSpec = OperatorSpec( "{text , string} × T × T -> stream( tid )", "_ frange[_, _]", "Searches an B+-Tree file for values in an closed interval", "query 'index.bin' frange['A', 'B'] strassen gettuples consume" ); // fleftrange OperatorSpec BPTreeOperators::fleftrangeOperatorSpec = OperatorSpec( "{text , string} × T -> stream(tid)", "_ fleftrange[_]", "Searches an B+-Tree file for values smaller/equal to the parameter", "query 'index.bin' fleftrange['A'] strassen gettuples consume" ); // frightrange OperatorSpec BPTreeOperators::frightrangeOperatorSpec = OperatorSpec( "{text , string} × T -> stream(tid)", "_ frightrange[_]", "Searche an B+-Tree file for values greater/equal to the parameter", "query 'index.bin' frightrange['A'] strassen gettuples consume" ); // fexactmatch OperatorSpec BPTreeOperators::fexactmatchOperatorSpec = OperatorSpec( "{text , string} × T -> stream(tid)", "_ fexactmatch[_]", "Searches an B+-Tree for values equal to the parameter", "query 'index.bin' fexactmatch['A'] strassen gettuples consume" ); // // Type Mapping // // frange ListExpr BPTreeOperators::FrangeTM( ListExpr args ) { // args: ((string "fileindex1.bin") (int 100) (int 200)) int searchType = 1; return GenericFSearchTM( searchType, args ); } // fleftrange ListExpr BPTreeOperators::FleftrangeTM( ListExpr args ) { // args : ((string "fileindex1.bin") (int 20)) int searchType = 2; return GenericFSearchTM( searchType, args ); } // frightrange ListExpr BPTreeOperators::FrightrangeTM( ListExpr args ) { // args : ((string "fileindex1.bin") (int 20)) int searchType = 3; return GenericFSearchTM( searchType, args ); } // fexactmatch ListExpr BPTreeOperators::FexactmatchTM( ListExpr args ) { // args : ((string "fileindex1.bin") (int 20)) int searchType = 4; return GenericFSearchTM( searchType, args ); } // Generic f*[range|exactmatch] Type Mapping ListExpr BPTreeOperators::GenericFSearchTM( int searchType, ListExpr args ) { // searchType // 1 : frange // 2 : fleftrange // 3 : frightrange // 4 : fexactmatch int frange = 1; int fleftrange = 2; int frightrange = 3; int fexactmatch = 4; // args // frange : ((string "fileindex1.bin") (int 100) (int 200)) // fleftrange : ((string "fileindex1.bin") (int 100)) // frightrange : ((string "fileindex1.bin") (int 100)) // fexactmatch : ((string "fileindex1.bin") (int 100)) bool hasMinValue = true; bool hasMaxValue = true; // fleftrange hat keinen Min-Wert if ( searchType == fleftrange ) hasMinValue = false; // frightrange hat keinen Max-Wert if ( searchType == frightrange ) hasMaxValue = false; NList type( args ); // // Laenge // frange-Operator braucht 3 Argumente if ( searchType == frange && !type.hasLength( 3 ) ) return NList::typeError( "Expecting three arguments." ); // fleftrange-, frightrange-, fexactmatch-Operator brauchen nur 2 Argumente if ( searchType != frange && !type.hasLength( 2 ) ) return NList::typeError( "Expecting two arguments." ); // // Type checks // NList file = type.first(); // (string "fileindex1.bin") NList min; NList max; // // Abhaengig vom Operator sind min und max anders belegt if ( searchType == frange ) { // frange: min und max gegeben min = type.second(); max = type.third(); } else if ( searchType == fleftrange ) { // fleftrange: nur max gegeben, min ist dummy (int 0) min = NList( nl->TwoElemList( nl->SymbolAtom( "int" ), nl->IntAtom( 0 ) ) ); max = type.second(); } else if ( searchType == frightrange ) { // frightrange: min ist gegeben, max ist dummy (int 0) min = type.second(); max = NList( nl->TwoElemList( nl->SymbolAtom( "int" ), nl->IntAtom( 0 ) ) ); } else if ( searchType == fexactmatch ) { // fexactmatch: nur ein Wert ist gegeben, min und max sind identisch min = type.second(); max = type.second(); } else { return NList::typeError( "internal error" ); } // else // Alle Paramter muessen eine Laenge von 2 haben (type value) if ( !file.hasLength( 2 ) || !min.hasLength( 2 ) || !max.hasLength( 2 ) ) return NList::typeError( "internal error" ); // file : string|text if ( !CcString::checkType( file.first().listExpr() ) && !FText::checkType( file.first().listExpr() ) ) return NList::typeError( "String or Text in first argument expected." ); // Types von min und max ListExpr minType = min.first().listExpr(); ListExpr maxType = max.first().listExpr(); // Indexfile name string fileName = file.second().str(); // Baum pruefen: Marker, Algebra- und Type-ID bool correctTree = true; size_t algId = 0; size_t typeId = 0; size_t rootId = 0; // BPTree* tree = BPTree::Open( fileName.c_str(), 1 ); // TreeHeaderMarker.BPlusTree if ( tree->GetHeader().GetMarker() != BPlusTree ) correctTree = false; // Header-Werte koennen nur gelesen werden, wenn // der Baum den korrekten Typ hat if ( correctTree ) { algId = tree->GetHeader().GetAlgebraID(); typeId = tree->GetHeader().GetTypeID(); rootId = tree->GetHeader().GetRoot(); } // if // cleanup delete tree; // // Baum im file ist kein B+Tree if ( !correctTree ) return NList::typeError( "File contains no B+Tree" ); // Algebra- und Type-Id pruefen ListExpr errorInfo; if ( hasMinValue && !am->TypeCheck( algId, typeId, minType, errorInfo ) ) return NList::typeError( "Wrong type of min value" ); if ( hasMaxValue && !am->TypeCheck( algId, typeId, maxType, errorInfo ) ) return NList::typeError( "Wrong type of max value" ); // // Wenn die RootNode-ID 0 ist, ist der Baum leer if ( rootId == 0 ) return NList::typeError( "BPTree in is empty" ); // Result NList append; // Bei fleftrange oder frightrange fuegen wir einen // Dummy ein, damit die Indexe von args[] im VM passen. if ( searchType == fleftrange || searchType == frightrange ) append.append( nl->IntAtom( 0 ) ); // dummy // Bei fexactmatch fuegen wir den (einzigen) Wert // nochmal ein. if ( searchType == fexactmatch ) append.append( min.second() ); // min = max // (b b i i) append.append( nl->BoolAtom( hasMinValue ) ); append.append( nl->BoolAtom( hasMaxValue ) ); append.append( nl->IntAtom( (int)algId ) ); append.append( nl->IntAtom( (int)typeId ) ); // ListExpr res = NList( // (APPEND) NList( Symbol::APPEND() ), // append append, // (stream tid) nl->TwoElemList( nl->SymbolAtom( Stream::BasicType() ), nl->SymbolAtom( TupleIdentifier::BasicType() ) ) ).listExpr(); return res; } // // Value Mapping // int BPTreeOperators::FrangeVM( Word* args, Word& result, int message, Word& local, Supplier s ) { // Jetzt wird's interessant: Abhaengig vom Operator // enthaellt args[] unterschiedliche Werte. // // args[0] : string (filename) // // args[1] // hasMinValue : minValue // !hasMinValue : maxValue // // args[2] // hasMinValue && hasMaxValue : maxValue // // args[3] : hasMinValue // args[4] : hasMaxValue // args[5] : Algebra-Id // args[6] : Type-Id // Durch das "spezielle" APPEND im Type Mapping bleiben die // Indexe fuer hasMinValue etc. gleich. Darum koennen wir fuer // alle Search-Operatoren das selbe Value Mapping verwenden. BPTreeSearchEnumerator* enumerator = static_cast( local.addr ); switch( message ) { case OPEN: { if ( enumerator != 0 ) delete enumerator; string indexFile = ((Attribute*)args[0].addr)->toText(); bool hasMinValue = StdTypes::GetBool( args[3].addr ); bool hasMaxValue = StdTypes::GetBool( args[4].addr ); int algId = StdTypes::GetInt( args[5].addr ); int typeId = StdTypes::GetInt( args[6].addr ); // Castet Pointer in richtige Attribute ObjectCast cast = am->Cast( algId, typeId ); // min, max Attribute* minValue = NULL; Attribute* maxValue = NULL; // // Wenn es einen Min-Value gibt, steht der immer am Index 1. if ( hasMinValue ) minValue = (Attribute*)cast( args[1].addr ); // Wenn es keinen Min-Wert, aber einen Max-Wert gibt, // steht der Max-Wert am Index 1. if ( !hasMinValue && hasMaxValue ) maxValue = (Attribute*)cast( args[1].addr ); // Wenn es Min- und Max-Werte gibt, steht der Max-Wert // am Index 2. if ( hasMinValue && hasMaxValue ) maxValue = (Attribute*)cast( args[2].addr ); // Wenn max < min tauschen wir einfach die Werte if ( hasMinValue && hasMaxValue && maxValue->Compare( minValue ) < 0 ) { Attribute* tmp = maxValue; maxValue = minValue; minValue = tmp; } // if // Baum erzeugen und Suche beginnen // Beim Suchen wird kein Cache genutzt BPTree* tree = BPTree::Open( indexFile.c_str(), 0 ); enumerator = tree->SearchKeys( minValue, maxValue ); local.addr = enumerator; #ifdef DEBUG cout << "Open B+Tree : " << indexFile << endl; cout << "Tree height : " << tree->GetHeight() << endl; cout << "Tree page size : " << tree->GetHeader().GetPageSize() << endl; cout << "Tree value size : " << tree->GetHeader().GetValueSize() << endl; cout << endl; cout << "Tree:" << endl; cout << tree->ToString() << endl; #endif return 0; } // case OPEN case REQUEST: { if ( enumerator->MoveNext() ) { // Enumerator enthaellt weitere Elemente size_t id = enumerator->GetCurrentId(); TupleIdentifier* tid = new TupleIdentifier( true, id ); result.addr = tid; return YIELD; } else { // Ende des Enumerators erreicht result.addr = 0; return CANCEL; } // else } // case REQUEST case CLOSE: { if ( enumerator != 0 ) { BPTree* tree = enumerator->GetTree(); // Baum und Enumerator loeschen delete enumerator; enumerator = NULL; delete tree; tree = NULL; local.addr = 0; } // if return 0; } // case CLOSE default: { // should never happen return -1; } // default } // switch } // // Operators // // frange Operator BPTreeOperators::frangeOp = Operator( "frange", frangeOperatorSpec.getStr(), FrangeVM, Operator::SimpleSelect, FrangeTM ); // fleftrange Operator BPTreeOperators::fleftrangeOp = Operator( "fleftrange", fleftrangeOperatorSpec.getStr(), FrangeVM, Operator::SimpleSelect, FleftrangeTM ); // frightrange Operator BPTreeOperators::frightrangeOp = Operator( "frightrange", frightrangeOperatorSpec.getStr(), FrangeVM, Operator::SimpleSelect, FrightrangeTM ); // fexactmatch Operator BPTreeOperators::fexactmatchOp = Operator( "fexactmatch", fexactmatchOperatorSpec.getStr(), FrangeVM, Operator::SimpleSelect, FexactmatchTM ); Operator BPTreeOperators::createfbtreeOp = CreateCreatefbtreeOp(); Operator BPTreeOperators::insertfbtreeOp = CreateInsertfbtreeOp(); Operator BPTreeOperators::deletefbtreeOp = CreateDeletefbtreeOp(); Operator BPTreeOperators::bulkloadfbtreeOp = CreateBulkloadfbtreeOp(); Operator BPTreeOperators::rebuildfbtreeOp = CreateRebuildfbtreeOp(); Operator BPTreeOperators::CreateCreatefbtreeOp(){ OperatorSpec spec( "stream(tuple(X)) x {string, text} x Ident x Ident -> stream(tuple(X))", "_createfbtree[_,_,_]", "creates a file based B+-Tree index", "query straßen feed addid createfbtree" "['straßen_name.bin', Name, TID] count"); Operator op("createfbtree", spec.getStr(), CreatefbtreeVM, Operator::SimpleSelect, CreatefbtreeTM); op.SetUsesArgsInTypeMapping(); return op; } Operator BPTreeOperators::CreateInsertfbtreeOp(){ OperatorSpec spec( "stream(tuple(X)) x {string, text} x Ident x Ident -> stream(tuple(X))", "_insertfbtree[_,_,_]", "inserts values into a file based B+-Tree index", "query straßen feed addid insertfbtree" "['straßen_name.bin', Name, TID] count"); Operator op("insertfbtree", spec.getStr(), InsertfbtreeVM, Operator::SimpleSelect, InsertfbtreeTM); op.SetUsesArgsInTypeMapping(); return op; } Operator BPTreeOperators::CreateDeletefbtreeOp(){ OperatorSpec spec( "stream(tuple(X)) x {string, text} x Ident x Ident -> stream(tuple(X))", "_deletefbtree[_,_,_]", "removes values from a file based B+-Tree index", "query straßen feed addid deletefbtree" "['straßen_name.bin', Name, TID] count"); Operator op("deletefbtree", spec.getStr(), DeletefbtreeVM, Operator::SimpleSelect, InsertfbtreeTM); op.SetUsesArgsInTypeMapping(); return op; } Operator BPTreeOperators::CreateRebuildfbtreeOp(){ OperatorSpec spec( "{string, text} x {string, text} -> bool ", "rebuildfbtree(_,_)", "rebuilds a B+-Tree", "query rebuildfbtree('straßen_name.bin', 'straßen_name_neu.bin')"); Operator op("rebuildfbtree", spec.getStr(), RebuildfbtreeVM, Operator::SimpleSelect, RebuildfbtreeTM); op.SetUsesArgsInTypeMapping(); return op; } Operator BPTreeOperators::CreateBulkloadfbtreeOp(){ OperatorSpec spec( "stream(tuple(X)) x {string, text} x Ident x Ident -> stream(tuple(X))", "_bulkloadfbtree[_,_,_]", "creates a file based B+-Tree index with bulkload", "query straßen feed addid bulkloadfbtree" "['straßen_name.bin', Name, TID] count"); Operator op("bulkloadfbtree", spec.getStr(), BulkloadfbtreeVM, Operator::SimpleSelect, CreatefbtreeTM); op.SetUsesArgsInTypeMapping(); return op; } ListExpr BPTreeOperators::CreatefbtreeTM(ListExpr args){ NList type(args); if (!type.hasLength(4) && !(type.hasLength(5) && CcInt::checkType(type.fifth().first().listExpr()))) { return NList::typeError("Expecting four arguments."); } if (!isTupleStream(type.first().first().listExpr())) { return NList::typeError("Error in first argument! " "Stream of tuples expected."); } NList second = type.second(); if (!CcString::checkType(second.first().listExpr()) && !FText::checkType(second.first().listExpr())) { return NList::typeError("Error in second argument! " "String or text expected!"); } ifstream file(second.second().str()); if (file.good()){ return NList::typeError("Error in second argument! " "File allready exists!"); } file.close(); NList third = type.third(); if (!third.first().isSymbol()) { return NList::typeError("Error in third argument! " "Attribute name expected. " "Perhaps the attribute's name may be the name " "of a Secondo object!"); } string indexAttrName = third.first().str(); ListExpr attributeList = type.first().first().second().second().listExpr(), attrtype = nl->Empty(); int indexAttrIndex = FindAttribute(attributeList, indexAttrName, attrtype); indexAttrIndex--; if (indexAttrIndex < 0) { return NList::typeError("Error in third argument!" "Attribute name '" + indexAttrName + "' not found!"); } int algebraId, typeId; string typeName; ListExpr indexAttrTypeInfo = nl->Second(nl->Nth(indexAttrIndex + 1, attributeList)); if (!SecondoSystem::GetCatalog()->LookUpTypeExpr(indexAttrTypeInfo, typeName, algebraId, typeId)){ return NList::typeError("Error in first argument!" "Failed to determine algebraId and typeId of " "indexed attribute!"); } ObjectCreation creationFunction = am->CreateObj(algebraId, typeId); Attribute* attributeInstance = (Attribute*)creationFunction(indexAttrTypeInfo).addr; if (attributeInstance->NumOfFLOBs() > 0){ attributeInstance->DeleteIfAllowed(); return NList::typeError("Error in first argument! " "Indexed attribute contains FLOBs!"); } attributeInstance->DeleteIfAllowed(); attributeInstance = NULL; NList fourth = type.fourth(); if (!fourth.first().isSymbol()) { return NList::typeError("Error in fourth argument! " "Attribute name expected. " "Perhaps the attribute's name may be the name " "of a Secondo object!"); } string idAttrName = fourth.first().str(); attrtype = nl->Empty(); int idAttrIndex = FindAttribute(attributeList, idAttrName, attrtype); idAttrIndex--; if (idAttrIndex < 0) { return NList::typeError("Error in fourth argument!" "Attribute name '" + indexAttrName + "' not found!"); } if (!TupleIdentifier::checkType(attrtype)){ return NList::typeError("Error in fourth argument!" "Attribute '" + indexAttrName + "' isn't of type TupleIdentifier!"); } //On my machine this was close to the optimum int cacheSize = 200; if (type.hasLength(5) && CcInt::checkType(type.fifth().first().listExpr())){ cacheSize = type.fifth().second().intval(); return NList(NList(Symbol::APPEND()), nl->FourElemList(nl->IntAtom(indexAttrIndex), nl->IntAtom(idAttrIndex), nl->IntAtom(algebraId), nl->IntAtom(typeId)), type.first().first().listExpr()).listExpr(); } return NList(NList(Symbol::APPEND()), nl->FiveElemList(nl->IntAtom(cacheSize), nl->IntAtom(indexAttrIndex), nl->IntAtom(idAttrIndex), nl->IntAtom(algebraId), nl->IntAtom(typeId)), type.first().first().listExpr()).listExpr(); } ListExpr BPTreeOperators::InsertfbtreeTM(ListExpr args){ NList type(args); if (!type.hasLength(4)) { return NList::typeError("Expecting four arguments."); } if (!isTupleStream(type.first().first().listExpr())) { return NList::typeError("Error in first argument! " "Stream of tuples expected."); } NList second = type.second(); if (!CcString::checkType(second.first().listExpr()) && !FText::checkType(second.first().listExpr())) { return NList::typeError("Error in second argument! " "String or text expected!"); } NList third = type.third(); if (!third.first().isSymbol()) { return NList::typeError("Error in third argument! " "Attribute name expected. " "Perhaps the attribute's name may be the name " "of a Secondo object!"); } string indexAttrName = third.first().str(); ListExpr attributeList = type.first().first().second().second().listExpr(), attrtype = nl->Empty(); int indexAttrIndex = FindAttribute(attributeList, indexAttrName, attrtype); indexAttrIndex--; if (indexAttrIndex < 0) { return NList::typeError("Error in third argument!" "Attribute name '" + indexAttrName + "' not found!"); } int algebraId, typeId; string typeName; ListExpr indexAttrTypeInfo = nl->Second(nl->Nth(indexAttrIndex + 1, attributeList)); if (!SecondoSystem::GetCatalog()->LookUpTypeExpr(indexAttrTypeInfo, typeName, algebraId, typeId)){ return NList::typeError("Error in first argument!" "Failed to determine algebraId and typeId of " "indexed attribute!"); } NList fourth = type.fourth(); if (!fourth.first().isSymbol()) { return NList::typeError("Error in fourth argument! " "Attribute name expected. " "Perhaps the attribute's name may be the name " "of a Secondo object!"); } string idAttrName = fourth.first().str(); attrtype = nl->Empty(); int idAttrIndex = FindAttribute(attributeList, idAttrName, attrtype); idAttrIndex--; if (idAttrIndex < 0) { return NList::typeError("Error in fourth argument!" "Attribute name '" + indexAttrName + "' not found!"); } if (!TupleIdentifier::checkType(attrtype)){ return NList::typeError("Error in fourth argument!" "Attribute '" + indexAttrName + "' isn't of type TupleIdentifier!"); } BPTree* tree; try{ tree = BPTree::Open(type.second().second().str().c_str(), 0); } catch (exception& e){ return NList::typeError("Opening IndexFile failed! " + string(e.what())); } if (tree->GetAlgebraId() != algebraId || tree->GetTypeId() != typeId){ delete(tree); return NList::typeError("The indexed types in stream and file " "don't match!"); } delete(tree); return NList(NList(Symbol::APPEND()), nl->TwoElemList(nl->IntAtom(indexAttrIndex), nl->IntAtom(idAttrIndex)), type.first().first().listExpr()).listExpr(); } ListExpr BPTreeOperators::RebuildfbtreeTM( ListExpr args ){ string dat1; string dat2; string err = "string/text x string/text"; if (!nl->HasLength( args, 2 )) { return listutils::typeError(err + ": wrong number of arguments"); } ListExpr arg1 = nl->First(args); ListExpr arg2 = nl->Second(args); // Check first argument (name of source file) //if ( !( CcString::checkType(args.first().first()) if ( !( CcString::checkType(nl->First(arg1)) || FText::checkType(nl->First(arg1)))) { return NList::typeError(err + ": First argument is not string or text!"); } if ( !( nl -> AtomType(nl->Second(arg1)) == StringType || nl -> AtomType(nl->Second(arg1)) == TextType) ) { return NList::typeError(err + ": First argument is not string or text!"); } if ( nl -> AtomType(nl->Second(arg1)) == StringType ) { dat1 = nl->StringValue(nl->Second(arg1)); } if ( nl -> AtomType(nl->Second(arg1)) == TextType ) { dat1 = nl->Text2String(nl->Second(arg1)); } // Check if source file exists and can be opened std::ifstream file01; file01.open(dat1.c_str()); if (!file01) { return NList::typeError(err + ": First file couldn't be opened!"); } else { file01.close(); } // Check if source file contains B+-Tree BPTree* bpt1 = BPTree::Open(dat1.c_str(), 50); if ((bpt1->GetHeader()).GetMarker() != TreeHeaderMarker::BPlusTree) { return NList::typeError(err + ": First file doesn't contain a B+-Tree!"); } delete bpt1; // Check second argument (name of target file) if ( !( CcString::checkType(nl->First(arg2)) || FText::checkType(nl->First(arg2)))) { return NList::typeError(err + ": Second argument is not string or text!"); } if ( !( nl -> AtomType(nl->Second(arg2)) == StringType || nl -> AtomType(nl->Second(arg2)) == TextType) ) { return NList::typeError(err + ": Second argument is not string or text!"); } if ( nl -> AtomType(nl->Second(arg2)) == StringType ) { dat2 = nl->StringValue(nl->Second(arg2)); } if ( nl -> AtomType(nl->Second(arg2)) == TextType ) { dat2 = nl->Text2String(nl->Second(arg2)); } ListExpr resType = listutils::basicSymbol(); return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->TwoElemList(nl->TextAtom(dat1), nl->TextAtom(dat2)), resType ); } int BPTreeOperators::CreatefbtreeVM(Word* args, Word& result, int message, Word& local, Supplier s){ result.addr = NULL; switch(message) { case OPEN: { string path = ((Attribute*)args[1].addr)->toText(); int algebraId = ((CcInt*)args[7].addr)->GetValue(), typeId = ((CcInt*)args[8].addr)->GetValue(), cacheSize = ((CcInt*)args[4].addr)->GetValue(); BPTree* tree = NULL; try{ tree = BPTree::Create(path.c_str(), algebraId, typeId, cacheSize); } catch (exception& e){ cout << e.what() << '\n'; local.addr = NULL; return CANCEL; } local.addr = new OperatorContext(tree, 0); qp->Open(args[0].addr); return 0; } case REQUEST: { if (local.addr != NULL){ Word tupleWord(Address(NULL)); qp->Request(args[0].addr, tupleWord); while(qp->Received(args[0].addr)) { Tuple* tuple = (Tuple*)tupleWord.addr; int attributeIndex = ((CcInt*)args[5].addr)->GetValue(), idIndex = ((CcInt*)args[6].addr)->GetValue(); Attribute* attribute = tuple->GetAttribute(attributeIndex); TupleId id = ((TupleIdentifier*)tuple->GetAttribute(idIndex))->GetTid(); OperatorContext* context = (OperatorContext*)local.addr; if (attribute->NumOfFLOBs() > 0){ context->skipped++; } else{ context->tree->InsertValue(*attribute, id); //cout << context->tree->ToString() << '\n'; } result.addr = tupleWord.addr; return YIELD; } } return CANCEL; } case CLOSE: { qp->Close(args[0].addr); if (local.addr != NULL) { OperatorContext* context = (OperatorContext*)local.addr; //cout << context->tree->ToString() << '\n'; if (context->skipped > 0){ cout << "createfbtree: " << context->skipped; cout << " elements skipped!\n"; } delete(context); context = NULL; local.addr = NULL; } return 0; } } return 0; } int BPTreeOperators::DeletefbtreeVM (Word* args, Word& result, int message, Word& local, Supplier s){ result.addr = NULL; switch(message) { case OPEN: { string path = ((Attribute*)args[1].addr)->toText(); BPTree* tree = NULL; try{ tree = BPTree::Open(path.c_str(), 50); } catch (exception& e){ cout << e.what() << '\n'; local.addr = NULL; return CANCEL; } local.addr = new OperatorContext(tree, 0); qp->Open(args[0].addr); return 0; } case REQUEST: { if (local.addr != NULL){ Word tupleWord(Address(NULL)); qp->Request(args[0].addr, tupleWord); while(qp->Received(args[0].addr)) { Tuple* tuple = (Tuple*)tupleWord.addr; int attributeIndex = ((CcInt*)args[4].addr)->GetValue(), idIndex = ((CcInt*)args[5].addr)->GetValue(); Attribute* attribute = tuple->GetAttribute(attributeIndex); TupleId id = ((TupleIdentifier*)tuple->GetAttribute(idIndex))->GetTid(); OperatorContext* context = (OperatorContext*)local.addr; if (attribute->NumOfFLOBs() > 0 || !context->tree->DeleteValue(*attribute, id)) { context->skipped++; } result.addr = tupleWord.addr; return YIELD; } } return CANCEL; } case CLOSE: { qp->Close(args[0].addr); if (local.addr != NULL) { OperatorContext* context = (OperatorContext*)local.addr; //cout << context->tree->ToString(); if (context->skipped > 0){ cout << "deletefbtree: " << context->skipped; cout << " elements skipped!\n"; } delete(context); context = NULL; local.addr = NULL; } return 0; } } return 0; } int BPTreeOperators::InsertfbtreeVM (Word* args, Word& result, int message, Word& local, Supplier s){ result.addr = NULL; switch(message) { case OPEN: { string path = ((Attribute*)args[1].addr)->toText(); BPTree* tree = NULL; try{ tree = BPTree::Open(path.c_str(), 50); } catch (exception& e){ cout << e.what() << '\n'; local.addr = NULL; return CANCEL; } local.addr = new OperatorContext(tree, 0); qp->Open(args[0].addr); return 0; } case REQUEST: { if (local.addr != NULL){ Word tupleWord(Address(NULL)); qp->Request(args[0].addr, tupleWord); while(qp->Received(args[0].addr)) { Tuple* tuple = (Tuple*)tupleWord.addr; int attributeIndex = ((CcInt*)args[4].addr)->GetValue(), idIndex = ((CcInt*)args[5].addr)->GetValue(); Attribute* attribute = tuple->GetAttribute(attributeIndex); TupleId id = ((TupleIdentifier*)tuple->GetAttribute(idIndex))->GetTid(); OperatorContext* context = (OperatorContext*)local.addr; if (attribute->NumOfFLOBs() > 0){ context->skipped++; } else{ context->tree->InsertValue(*attribute, id); } result.addr = tupleWord.addr; return YIELD; } } return CANCEL; } case CLOSE: { qp->Close(args[0].addr); if (local.addr != NULL) { OperatorContext* context = (OperatorContext*)local.addr; //cout << context->tree->ToString(); if (context->skipped > 0){ cout << "insertfbtree: " << context->skipped; cout << " elements skipped!\n"; } delete(context); context = NULL; local.addr = NULL; } return 0; } } return 0; } int BPTreeOperators::BulkloadfbtreeVM (Word* args, Word& result, int message, Word& local, Supplier s){ result.addr = NULL; switch(message) { case OPEN: { string path = ((Attribute*)args[1].addr)->toText(); int algebraId = ((CcInt*)args[7].addr)->GetValue(), typeId = ((CcInt*)args[8].addr)->GetValue(), cacheSize = ((CcInt*)args[4].addr)->GetValue(); BPTree* tree; try{ tree = BPTree::Create(path.c_str(), algebraId, typeId, cacheSize); } catch (exception& e){ cout << e.what() << '\n'; local.addr = NULL; return CANCEL; } tree->StartBulkload(); local.addr = new BulkloadContext(tree, NULL, 0); qp->Open(args[0].addr); return 0; } case REQUEST: { if (local.addr != NULL){ Word tupleWord(Address(NULL)); qp->Request(args[0].addr, tupleWord); while(qp->Received(args[0].addr)) { Tuple* tuple = (Tuple*)tupleWord.addr; int attributeIndex = ((CcInt*)args[5].addr)->GetValue(), idIndex = ((CcInt*)args[6].addr)->GetValue(); Attribute* attribute = tuple->GetAttribute(attributeIndex); TupleId id = ((TupleIdentifier*)tuple->GetAttribute(idIndex))->GetTid(); BulkloadContext* context = (BulkloadContext*)local.addr; if (attribute->NumOfFLOBs() > 0 || (context->prevAttr != NULL && attribute->Compare(context->prevAttr) < 0)){ context->skipped++; } else{ context->tree->InsertBulkload(*attribute, id); if (context->prevAttr != NULL){ context->prevAttr->DeleteIfAllowed(); } context->prevAttr = attribute->Copy(); } result.setAddr(tupleWord.addr); return YIELD; } } return CANCEL; } case CLOSE: { qp->Close(args[0].addr); if (local.addr != NULL) { BulkloadContext* context = (BulkloadContext*)local.addr; context->tree->EndBulkload(); //CheckTree /*BPTreeSearchEnumerator* e = context->tree->SearchKeys(NULL, NULL); size_t index = 0; qp->Open(args[0].addr); Word tupleWord(Address(NULL)); qp->Request(args[0].addr, tupleWord); while (qp->Received(args[0].addr)){ Tuple* tuple = (Tuple*)tupleWord.addr; int attributeIndex = ((CcInt*)args[5].addr)->GetValue(), idIndex = ((CcInt*)args[6].addr)->GetValue(); Attribute* attribute = tuple->GetAttribute(attributeIndex); TupleId id = ((TupleIdentifier*)tuple->GetAttribute(idIndex))->GetTid(); if (!e->MoveNext()){ cout << "Missing Entry at " << index << '\n'; break; } else{ if (attribute->Compare(&(e->GetCurrentValue())) != 0){ cout << "Invalid Attribute at " << index << '\n'; } if (id != e->GetCurrentId()){ cout << "Invalid TupleId at " << index << '\n'; } } index++; qp->Request(args[0].addr, tupleWord); } delete(e); qp->Close(args[0].addr);*/ if (context->skipped > 0){ cout << "bulkloadfbtree: " << context->skipped; cout << " elements skipped!\n"; } delete(context); context = NULL; local.addr = NULL; } return 0; } } return 0; } int BPTreeOperators::RebuildfbtreeVM (Word* args, Word& result, int message, Word& local, Supplier s) { // Parameters 2 and 3 are delivered from the type mapping function // in text format, params 0 and 1 can thus be neglected FText* pre1 = (FText*) args[2].addr; // get the argument and cast it FText* pre2 = (FText*) args[3].addr; // get the argument and cast it // Cast file names to string (and later to char* for ctor) string dat1 = (pre1->GetValue()); string dat2 = (pre2->GetValue()); std::cout << "dat1: " << dat1.c_str() << endl; std::cout << "dat2: " << dat2.c_str() << endl; // Create source tree from first file BPTree* bpt1 = BPTree::Open(dat1.c_str(), 50); bpt1->Rebuild(dat2.c_str()); delete bpt1; // Delete source file //remove(dat1.c_str()); result = qp->ResultStorage(s); // use the result storage CcBool* b = static_cast (result.addr); // cast the result b->Set(true, true); // compute and set the result return 0; } BPTreeOperators::OperatorContext::OperatorContext(BPTree* tree, size_t skipped){ this->tree = tree; this->skipped = skipped; } BPTreeOperators::OperatorContext::~OperatorContext(){ if (tree != NULL){ delete(tree); tree = NULL; } } BPTreeOperators::BulkloadContext::BulkloadContext(BPTree* tree, Attribute* prevAttr, size_t skipped) : OperatorContext(tree, skipped){ if (prevAttr != NULL){ this->prevAttr = prevAttr->Copy(); } else{ this->prevAttr = NULL; } } BPTreeOperators::BulkloadContext::~BulkloadContext(){ if (this->prevAttr != NULL){ this->prevAttr->DeleteIfAllowed(); this->prevAttr = NULL; } } }