Files
secondo/Algebras/FileIndexAlgebra/BPTree/BPTreeOperators.cpp
2026-01-23 17:03:45 +08:00

1344 lines
38 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
----
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 <cstring>
#include <fstream>
#include <iostream>
#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<TupleIdentifier>::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<BPTreeSearchEnumerator*>( 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<CcBool>();
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<CcBool*> (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;
}
}
}