/*
* This file is part of rasdaman community.
*
* Rasdaman community 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 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community 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 rasdaman community. If not, see .
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see
* or contact Peter Baumann via .
*/
/*************************************************************
*
*
* PURPOSE:
* maintain the hierarchical index in the DBMS.
*
*
* COMMENTS:
* - relies on the same-name DBMS preprocessor sources for the
* various DBMSs supported.
*
************************************************************/
#include
#include "mymalloc/mymalloc.h"
#include "hierindex.hh"
#include "reladminif/objectbroker.hh"
#include "reladminif/dbref.hh"
#include "raslib/rmdebug.hh"
#include "reladminif/lists.h"
#include "reladminif/sqlerror.hh"
#include "reladminif/externs.h"
#include "relblobif/blobtile.hh"
#include "indexmgr/keyobject.hh"
#include "storagemgr/sstoragelayout.hh"
#include "raslib/endian.hh"
#include "debug.hh"
DBHierIndex::DBHierIndex(const OId& id)
: HierIndexDS(id),
currentDbRows(0),
myDomain((r_Dimension)0),
maxSize(0),
parent(0),
_isNode(false)
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << myOId << ")");
ENTER( "DBHierIndex::DBHierIndex(" << myOId << ")" );
if (id.getType() == OId::MDDHIERIXOID)
readFromDb();
maxSize = DBHierIndex::getOptimalSize(getDimension());
myKeyObjects.reserve(maxSize);
LEAVE( "DBHierIndex::DBHierIndex(" << myOId << ")" );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << myOId << ")");
}
DBHierIndex::DBHierIndex(r_Dimension dim, bool isNODE, bool makePersistent)
: HierIndexDS(),
maxSize(0),
myDomain(dim),
currentDbRows(-1),
parent(0),
_isNode(isNODE)
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << dim << ", " << (int)isNODE << ", " << makePersistent << ") " << myOId);
ENTER( "DBHierIndex::DBHierIndex( dim=" << dim << ", isNODE=" << (int) isNODE << ", makePersistent=" << makePersistent << " ) - myOId=" << myOId );
objecttype = OId::MDDHIERIXOID;
if (makePersistent)
setPersistent(true);
maxSize = getOptimalSize(dim);
myKeyObjects.reserve(maxSize);
setCached(true);
LEAVE( "DBHierIndex::DBHierIndex( dim=" << dim << ", isNODE=" << (int) isNODE << ", makePersistent=" << makePersistent << " ) - myOId=" << myOId );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << dim << ", " << (int)isNODE << ", " << makePersistent << ") " << myOId);
}
IndexDS*
DBHierIndex::getNewInstance() const
{
ENTER( "DBHierIndex::getNewInstance()" );
LEAVE( "DBHierIndex::getNewInstance() - dim=" << getDimension() << ", !isLeaf=" << (!isLeaf()) );
return new DBHierIndex(getDimension(), !isLeaf(), true);
}
OId::OIdPrimitive
DBHierIndex::getIdentifier() const
{
ENTER( "DBHierIndex::getIdentifier()" );
LEAVE( "DBHierIndex::getIdentifier() - myOId=" << myOId );
return myOId;
}
bool
DBHierIndex::removeObject(const KeyObject& entry)
{
RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << entry << ") " << myOId);
ENTER( "DBHierIndex::removeObject() - entry=" << entry << ", myOId=" << myOId );
bool found = false;
unsigned int pos = 0;
OId oid(entry.getObject().getOId());
for (KeyObjectVector::iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
{
RMDBGMIDDLE(9, RMDebug::module_indexif, "DBHierIndex", "at pos " << pos << " of " << myKeyObjects.size());
TALK( "DBHierIndex::removeObject() touching object in vector at pos " << pos << " of " << myKeyObjects.size());
if (oid == (*i).getObject().getOId())
{
found = true;
myKeyObjects.erase(i);
setModified();
break;
}
else {
RMDBGMIDDLE(9, RMDebug::module_indexif, "DBHierIndex", "did not match " << oid << " with " << *i);
}
}
LEAVE( "DBHierIndex::removeObject() - entry=" << entry << ", myOId=" << myOId << ", found=" << found );
RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << entry << ") " << myOId << " " << found);
return found;
}
bool
DBHierIndex::removeObject(unsigned int pos)
{
RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << pos << ") " << myOId);
ENTER( "DBHierIndex::removeObject() - pos=" << pos << ", myOId=" << myOId );
bool found = false;
if (pos <= myKeyObjects.size())
{
found = true;
myKeyObjects.erase(myKeyObjects.begin() + pos);
setModified();
}
LEAVE( "DBHierIndex::removeObject() - pos=" << pos << ", myOId=" << myOId << ", found=" << found );
RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << pos << ") " << myOId << " " << found);
return found;
}
void
DBHierIndex::insertObject(const KeyObject& theKey, unsigned int pos)
{
RMDBGENTER(8, RMDebug::module_indexif, "DBHierIndex", "insertObject(" << theKey << ", " << pos << ") " << myOId);
ENTER( "DBHierIndex::insertObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
if (!isLeaf())
DBHierIndexId(theKey.getObject())->setParent(this);
if (myKeyObjects.size() == 0)
{
// first tile to be inserted in the index, initialize domain
myDomain = theKey.getDomain();
}
else
extendCoveredDomain(theKey.getDomain());
myKeyObjects.insert(myKeyObjects.begin() + pos, theKey);
TALK( "now have " << myKeyObjects.size() << " objects in key object vector." );
setModified();
LEAVE( "DBHierIndex::insertObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId << ", CoveredDomain " << getCoveredDomain() << std::endl << std::endl );
TALK( " CoveredDomain=" << getCoveredDomain() << std::endl << std::endl );
RMDBGEXIT(8, RMDebug::module_indexif, "DBHierIndex", "insertObject(" << theKey << ", " << pos << ") " << myOId << " CoveredDomain " << getCoveredDomain());
}
void
DBHierIndex::setObjectDomain(const r_Minterval& dom, unsigned int pos)
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setObjectDomain(" << dom << ", " << pos << ") " << myOId);
ENTER( "DBHierIndex::setObjectDomain() - dom=" << dom << ", pos=" << pos << ", myOId=" << myOId );
myKeyObjects[pos].setDomain(dom);
//might be unneccessary/harmfull, check later
extendCoveredDomain(dom);
//setModified(); done in domain extension
if (!isLeaf())
{
DBHierIndexId t(myKeyObjects[pos].getObject());
t->setAssignedDomain(dom);
}
LEAVE( "DBHierIndex::setObjectDomain() - dom=" << dom << ", pos=" << pos << ", myOId=" << myOId );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setObjectDomain(" << dom << ", " << pos << ") " << myOId);
}
void
DBHierIndex::setObject(const KeyObject& theKey, unsigned int pos)
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setObject(" << theKey << ", " << pos << ") " << myOId);
ENTER( "DBHierIndex::setObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
myKeyObjects[pos] = theKey;
setModified();
if (!isLeaf())
{
DBHierIndexId(theKey.getObject())->setParent(this);
}
LEAVE( "DBHierIndex::setObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setObject(" << theKey << ", " << pos << ") " << myOId);
}
r_Minterval
DBHierIndex::getCoveredDomain() const
{
RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getCoveredDomain() const " << myOId << " " << myDomain);
TALK( "DBHierIndex::getCoveredDomain( " << myOId << ") -> " << myDomain );
return myDomain;
}
r_Dimension
DBHierIndex::getDimension() const
{
RMDBGONCE(7, RMDebug::module_indexif, "DBDDObjIx", "getDimension() const " << myOId << " " << myDomain.dimension());
TALK( "DBHierIndex::getDimension( " << myOId << ") -> " << myDomain.dimension() );
return myDomain.dimension();
}
r_Bytes
DBHierIndex::getTotalStorageSize() const
{
RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "getTotalStorageSize() " << myOId);
ENTER( "DBHierIndex::getTotalStorageSize() - myOId=" << myOId );
r_Bytes sz = 0;
for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
{
sz = sz + ((DBObject*)ObjectBroker::getObjectByOId(i->getObject().getOId()))->getTotalStorageSize();
}
LEAVE( "DBHierIndex::getTotalStorageSize( " << myOId << " ) for " << myKeyObjects.size() << " objects -> sz=" << sz );
RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "getTotalStorageSize() " << myOId << " " << sz);
return sz;
}
bool
DBHierIndex::isValid() const
{
ENTER( "DBHierIndex::isValid()" );
bool valid = true;
//may not be unsigned int (r_Area) because of error check
int area = 0;
if (!isLeaf())
{
area = myDomain.cell_count();
DBHierIndexId tempIx;
TALK( "inspecting " << myKeyObjects.size() << " objects in key object vector." );
for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
{
if (myDomain.covers((*i).getDomain()))
{
//ok
area = area - (*i).getDomain().cell_count();
}
else {
if (myDomain == (*i).getDomain())
{
//ok
area = area - (*i).getDomain().cell_count();
tempIx = DBHierIndexId((*i).getObject());
if (!tempIx->isValid())
{
valid = false;
break;
}
}
else {
RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " key does not cover domain: myDomain " << myDomain << " key " << *i);
valid = false;
break;
}
}
}
if (valid)
{
if (area < 0)
{
RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " there are double entries");
valid = false;
}
}
}
else {
area = myDomain.cell_count();
valid = true;
for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
{
if (myDomain.intersects_with((*i).getDomain()))
{
//ok
area = area - (*i).getDomain().create_intersection(myDomain).cell_count();
}
else {
RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " key does not intersect domain: myDomain " << myDomain << " key " << *i);
valid = false;
break;
}
}
if (!valid)
{
if (area < 0)
{
RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " there are double entries");
valid = false;
}
}
}
ENTER( "DBHierIndex::isValid() -> valid=" << valid );
return valid;
}
void
DBHierIndex::printStatus(unsigned int level, std::ostream& stream) const
{
ENTER( "DBHierIndex::printStatus() - level=" << level );
DBObjectId t;
char* indent = new char[level*2 +1];
for (unsigned int j = 0; j < level*2 ; j++)
indent[j] = ' ';
indent[level*2] = '\0';
stream << indent << "DBHierIndex ";
if (isRoot())
stream << "is Root ";
else
stream << "Parent " << parent << " ";
if (isLeaf())
stream << "Leaf ";
else
stream << "Node ";
DBObject::printStatus(level, stream);
stream << " size " << myKeyObjects.size() << " domain " << myDomain << std::endl;
int count = 0;
TALK( "inspecting " << myKeyObjects.size() << " objects in key object vector." );
for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
{
stream << indent << " entry #" << count << " is " << *i << std::endl;
if (!isLeaf())
{
t = DBObjectId((*i).getObject());
if (t.is_null())
stream << indent << " entry is null";
else
t->printStatus(level + 1, stream);
}
stream << std::endl;
count++;
}
delete[] indent;
LEAVE( "DBHierIndex::printStatus()" );
}
unsigned int
DBHierIndex::getSize() const
{
RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getSize() " << myOId << " " << myKeyObjects.size());
TALK( "DBHierIndex::getSize() - myOId=" << myOId << ", size=" << myKeyObjects.size() );
return myKeyObjects.size();
}
bool
DBHierIndex::isUnderFull() const
{
//redistribute in srptindexlogic has to be checked first before any other return value may be assigned
TALK( "DBHierIndex::isUnderFull() -> false" );
return false;
}
bool
DBHierIndex::isOverFull() const
{
ENTER( "DBHierIndex::isOverFull()" );
bool retval = false;
if (getSize() >= maxSize)
retval = true;
RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "isOverFull() " << myOId << " maxSize " << maxSize << " size " << getSize() << " retval " << retval)
ENTER( "DBHierIndex::isOverFull() -> " << retval );
return retval;
}
unsigned int
DBHierIndex::getOptimalSize(r_Dimension dim)
{
ENTER( "DBHierIndex::getOptimalSize() - dim=" << dim );
unsigned int retval = 0;
//BLOCKSIZE
unsigned int blocksize = 0;
unsigned int useablespace = 0;
//dimension * (upperbound + upperfixed + lowerbound + lowerfixed) + entryid + entryoidtype
unsigned int oneentry = dim * (sizeof(r_Range) * 2 + sizeof(char) * 2) + sizeof(OId::OIdCounter) + sizeof(char);
#ifdef BASEDB_ORACLE
blocksize = 2048;
//BLOCKSIZE - (BLOCK OVERHEAD + ROW OVERHEAD + 1 * largerow + number(15,0) + short)
useablespace = blocksize - (130 + 3 + 1 * 3 + 12 + 2);
#else
#ifdef BASEDB_DB2
blocksize = 4096;
//from the manual
useablespace = 3990;
#else
#ifdef BASEDB_INFORMIX
blocksize = 4096;
//from the manual
useablespace = 3990;
#else
#ifdef BASEDB_PGSQL
blocksize = 8192; // default only!!!;
useablespace = 7000; // no indication for any less space available, but to be sure we go a little lower -- PB 2005-jan-10
#else
#error "BASEDB not defined! please check for BASEDB_XXX define in Makefile.inc!"
#endif // pgsql
#endif // informix
#endif // db2
#endif // oracle
//remove mydomain size
useablespace = useablespace - dim * (sizeof(r_Range) * 2 + sizeof(char) * 2);
//minimum size is 8-lucky guess(good for 1,2,3,4 dimensions)
retval = std::max((unsigned int)8, useablespace / oneentry);
if (StorageLayout::DefaultIndexSize != 0)
retval = StorageLayout::DefaultIndexSize;
LEAVE( "DBHierIndex::getOptimalSize() - maxSize=" << retval );
RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getOptimalSize(" << dim << ") maxSize " << retval)
return retval;
}
unsigned int
DBHierIndex::getOptimalSize() const
{
TALK( "DBHierIndex::getOptimalSize() -> " << maxSize );
return maxSize;
}
r_Minterval
DBHierIndex::getAssignedDomain() const
{
TALK( "DBHierIndex::getAssignedDomain() -> " << myDomain );
return myDomain;
}
void
DBHierIndex::setAssignedDomain(const r_Minterval& newDomain)
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setAssignedDomain(" << newDomain << ") " << myOId);
ENTER( "DBHierIndex::setAssignedDomain() - newDomain=" << newDomain << ", myOId=" << myOId );
myDomain = newDomain;
setModified();
LEAVE( "DBHierIndex::setAssignedDomain()" );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setAssignedDomain(" << newDomain << ") " << myOId);
}
void
DBHierIndex::extendCoveredDomain(const r_Minterval& newTilesExtents) throw (r_Edim_mismatch, r_Eno_interval)
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "extendCoveredDomain(" << newTilesExtents << ") " << myOId);
ENTER( "DBHierIndex::extendCoveredDomain() - newTilesExtents=" << newTilesExtents << ", myOId=" << myOId );
myDomain.closure_with(newTilesExtents);
setModified();
LEAVE( "DBHierIndex::extendCoveredDomain()" );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "extendCoveredDomain(" << newTilesExtents << ") " << myOId);
}
void
DBHierIndex::setParent(const HierIndexDS* newPa)
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setParent(" << OId(newPa->getIdentifier()) << ") " << myOId);
ENTER( "DBHierIndex::setParent() - newPa=" << newPa << ", myOId=" << myOId );
if ((OId::OIdPrimitive)parent != newPa->getIdentifier())
{
parent = newPa->getIdentifier();
setModified();
}
LEAVE( "DBHierIndex::setParent()" );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setParent(" << OId(newPa->getIdentifier()) << ") " << myOId);
}
HierIndexDS*
DBHierIndex::getParent() const
{
RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getParent() const " << myOId << " " << parent << " " << parent);
ENTER( "DBHierIndex::getParent() - myOId=" << myOId << ", parent=" << parent );
DBHierIndexId t(parent);
LEAVE( "DBHierIndex::getParent() - t=" << t );
return (HierIndexDS*)t;
}
bool
DBHierIndex::isRoot() const
{
RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "isRoot() const " << myOId << " " << (int)(parent.getType() == OId::INVALID));
TALK( "DBHierIndex::isRoot() -> " << (parent.getType() == OId::INVALID) );
return (parent.getType() == OId::INVALID);
}
bool
DBHierIndex::isLeaf() const
{
RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "isLeaf() const " << myOId << " " << (int)(!_isNode));
TALK( "DBHierIndex::isLeaf() -> " << !_isNode );
return !_isNode;
}
void
DBHierIndex::setIsNode(bool isNodea)
{
RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "setIsNode(" << isNodea << ") " << myOId << " was " << _isNode);
TALK( "DBHierIndex::setIsNode() - isNodea=" << isNodea );
_isNode = isNodea;
}
void
DBHierIndex::freeDS()
{
TALK( "DBHierIndex::freeDS()" );
setPersistent(false);
}
bool
DBHierIndex::isSameAs(const IndexDS* other) const
{
ENTER( "DBHierIndex::isSameAs() - other=" << other );
bool result = false;
if (other->isPersistent())
if (myOId == other->getIdentifier())
result = true;
LEAVE( "DBHierIndex::isSameAs() -> " << result );
return result;
}
double
DBHierIndex::getOccupancy() const
{
cout << "DBHierIndex::getOccupancy() const NOT IMPLEMENTED" << std::endl;
TALK( "DBHierIndex::getOccupancy() NOT IMPLEMENTED" );
return 0;
}
const KeyObject&
DBHierIndex::getObject(unsigned int pos) const
{
RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getObject(" << pos << ") " << myOId << " " << myKeyObjects[pos]);
TALK( "DBHierIndex::getObject() - pos=" << pos << ", myOId=" << myOId << " -> " << myKeyObjects[pos] );
return myKeyObjects[pos];
}
void
DBHierIndex::getObjects(KeyObjectVector& objs) const
{
RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "getObjects() " << myOId);
ENTER( "DBHierIndex::getObjects() - myOId=" << myOId );
for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
{
objs.push_back(*keyIt);
}
LEAVE( "DBHierIndex::getObjects() - size=" << objs.size() );
RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "getObjects() " << myOId << " vec.size " << objs.size());
}
r_Minterval
DBHierIndex::getObjectDomain(unsigned int pos) const
{
RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getObjectDomain(" << pos << ") " << myOId << " " << myKeyObjects[pos]);
TALK( "DBHierIndex::getObjectDomain() - pos=" << pos << ", myOId=" << myOId << " -> " << myKeyObjects[pos] );
return myKeyObjects[pos].getDomain();
}
unsigned int
DBHierIndex::getHeight() const
{
TALK( "DBHierIndex::getHeight() -> " << getHeightToLeaf() );
return getHeightToLeaf();
}
unsigned int
DBHierIndex::getHeightOfTree() const
{
ENTER( "DBHierIndex::getHeightOfTree() - myOId=" << myOId );
unsigned int retval = getHeightToLeaf() + getHeightToRoot();
LEAVE( "DBHierIndex::getHeightOfTree() -> " << retval );
RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightOfTree() const " << myOId << " " << retval);
return retval;
}
unsigned int
DBHierIndex::getHeightToRoot() const
{
ENTER( "DBHierIndex::getHeightToRoot() - myOId=" << myOId );
unsigned int retval = 0;
if (isRoot())
retval = 0;
else {
DBHierIndexId t(parent);
const DBHierIndex* tp = (DBHierIndex*)t.ptr();
retval = tp->getHeightToRoot() + 1;
}
LEAVE( "DBHierIndex::getHeightToRoot() -> " << retval );
RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightToRoot() const " << myOId << " " << retval);
return retval;
}
unsigned int
DBHierIndex::getHeightToLeaf() const
{
ENTER( "DBHierIndex::getHeightToLeaf() - myOId=" << myOId );
unsigned int retval = 0;
if (isLeaf())
retval = 0;
else {
DBHierIndexId t(parent);
const DBHierIndex* tp = (DBHierIndex*)t.ptr();
retval = tp->getHeightToLeaf() + 1;
}
LEAVE( "DBHierIndex::getHeightToLeaf() -> " << retval );
RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightToLeaf() const " << myOId << " " << retval);
return retval;
}
unsigned int
DBHierIndex::getTotalLeafCount() const
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotalLeafCount() const " << myOId);
ENTER( "DBHierIndex::getTotalLeafCount() - myOId=" << myOId );
unsigned int retval = 0;
if (!isLeaf())
{
//i am not a leaf
if (DBHierIndexId(myKeyObjects.begin()->getObject())->isLeaf())
{
//i contain only leafs, so i return the number of entries i contain
retval = getSize();
}
else {
//i contain only nodes, so i ask my children how many leafs there are
for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
{
DBHierIndexId accessedIx((*keyIt).getObject());
retval = retval + accessedIx->getTotalLeafCount();
}
}
}
else {
retval = 1;
}
LEAVE( "DBHierIndex::getTotalLeafCount() -> " << retval );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotalLeafCount() const " << myOId << " " << retval);
return retval;
}
unsigned int
DBHierIndex::getTotalNodeCount() const
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotalNodeCount() const " << myOId);
ENTER( "DBHierIndex::getTotalNodeCount() - myOId=" << myOId );
unsigned int retval = 0;
if (!isLeaf())
{
//i am not a leaf
if (DBHierIndexId(myKeyObjects.begin()->getObject())->isLeaf())
{
//i contain only nodes
//i add the nodes i contain
retval = getSize();
//i add the nodes my children contain
for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
{
DBHierIndexId accessedIx((*keyIt).getObject());
retval = retval + accessedIx->getTotalNodeCount();
}
}
}
//else : a leaf does not contain nodes
LEAVE( "DBHierIndex::getTotalNodeCount() -> " << retval );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotalNodeCount() const " << myOId << " " << retval);
return retval;
}
unsigned int
DBHierIndex::getTotalEntryCount() const
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotoalEntryCount() const " << myOId);
ENTER( "DBHierIndex::getTotalEntryCount() - myOId=" << myOId );
unsigned int retval = 0;
if (isLeaf())
{
//i contain only entries
//i return the number of entries i contain
retval = getSize();
}
else {
//i contain only nodes, no entries
//i ask my children how many entries they contain
for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
{
DBHierIndexId accessedIx((*keyIt).getObject());
retval = retval + accessedIx->getTotalEntryCount();
}
}
LEAVE( "DBHierIndex::getTotalEntryCount() -> " << retval );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotoalEntryCount() const " << myOId << " " << retval);
return retval;
}
void
DBHierIndex::destroy()
{
TALK( "DBObject::destroy()" );
DBObject::destroy();
}
DBHierIndex::~DBHierIndex()
{
RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "~DBHierIndex() " << myOId);
ENTER( "DBHierIndex::~DBHierIndex() - myOId=" << myOId );
validate();
currentDbRows = 0;
parent = OId(0);
myKeyObjects.clear();
myDomain = (InlineMinterval) NULL;
maxSize = 0;
_isNode = true;
LEAVE( "DBHierIndex::~DBHierIndex()" );
RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "~DBHierIndex() " << myOId);
}
/*
Encoding:
name :
type_oid.raw
value :
common
1 byte version
1 byte endianness
2 bytes type
4 bytes oid
1 byte flags
2 byte reserved
special
4 bytes size
2 bytes dimension
8 bytes parent oid
1 byte subtype
x bytes database layout
*/
BinaryRepresentation
DBHierIndex::getBinaryRepresentation() const throw (r_Error)
{
ENTER( "DBHierIndex::getBinaryRepresentation()" );
BinaryRepresentation brp;
brp.binaryName = getBinaryName();
brp.binaryData = NULL;
brp.binaryLength = 0;
short dimension2 = myDomain.dimension();
size_t size2 = myKeyObjects.size();
short subtype = _isNode;
double parentid2 = 0;
if (parent.getType() == OId::INVALID)
parentid2 = 0;
else
parentid2 = parent;
//INSERTINTO
//number of bytes for bounds for "size" entries and mydomain
r_Bytes boundssize = sizeof(r_Range) * (size2 + 1) * dimension2;
//number of bytes for fixes for "size" entries and mydomain
r_Bytes fixessize = sizeof(char) * (size2 + 1) * dimension2;
//number of bytes for ids of entries
r_Bytes idssize = sizeof(OId::OIdCounter) * size2;
//number of bytes for types of entries
r_Bytes typessize = sizeof(char) * size2;
//number of bytes for the dynamic data
r_Bytes completesize = boundssize * 2 + fixessize * 2 + idssize + typessize;
char* completebuffer = new char[completesize];
r_Range* upperboundsbuf = new r_Range[boundssize];
r_Range* lowerboundsbuf = new r_Range[boundssize];
char* upperfixedbuf = new char[fixessize];
char* lowerfixedbuf = new char[fixessize];
OId::OIdCounter* entryidsbuf = new OId::OIdCounter[idssize];
char* entrytypesbuf = new char[typessize];
RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete " << completesize << " bounds " << boundssize << " fixes " << fixessize << " ids " << idssize << " types " << typessize);
//counter which keeps track of the bytes that have been written to the db
r_Bytes byteswritten = 0;
//counter which keeps track of the bytes that have to be written to the db
r_Bytes bytestowrite = 0;
myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " stored as " << InlineMinterval(dimension2, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
//populate the buffers with data
KeyObjectVector::const_iterator it = myKeyObjects.begin();
InlineMinterval indom;
for (unsigned int i = 0; i < size2; i++, it++)
{
indom = (*it).getDomain();
indom.insertInDb(&(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2]));
entryidsbuf[i] = (*it).getObject().getOId().getCounter();
entrytypesbuf[i] = (char)(*it).getObject().getOId().getType();
RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension2, &(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2])));
}
//write the buffers in the complete buffer
//this indirection is neccessary because of memory alignement of longs...
memcpy(completebuffer, lowerboundsbuf, boundssize);
delete [] lowerboundsbuf;
memcpy(&completebuffer[boundssize], upperboundsbuf, boundssize);
delete [] upperboundsbuf;
memcpy(&completebuffer[boundssize * 2], lowerfixedbuf, fixessize);
delete [] lowerfixedbuf;
memcpy(&completebuffer[boundssize * 2 + fixessize], upperfixedbuf, fixessize);
delete [] upperfixedbuf;
memcpy(&completebuffer[boundssize * 2 + fixessize * 2], entryidsbuf, idssize);
delete [] entryidsbuf;
memcpy(&completebuffer[boundssize * 2 + fixessize * 2 + idssize], entrytypesbuf, typessize);
delete [] entrytypesbuf;
/*
5 bytes tag
1 byte version
1 byte endianness
8 bytes oid
*/
//version + endianness + oid + size + dimension + parentoid + subtype
brp.binaryLength = 7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char) + completesize;
brp.binaryData = new char[brp.binaryLength];
memcpy(brp.binaryData, BinaryRepresentation::fileTag, 5);
memset(&brp.binaryData[5], 1, 1);
if (r_Endian::get_endianness() == r_Endian::r_Endian_Little)
{
memset(&brp.binaryData[6], 1, 1);
}
else {
memset(&brp.binaryData[6], 0, 1);
}
double tempd = myOId;
memcpy(&brp.binaryData[7], &tempd, sizeof(double));
/*
special
4 bytes size
2 bytes dimension
8 bytes parent oid
1 byte subtype
x bytes database layout
*/
int tempi = size2;
memcpy(&brp.binaryData[7 + sizeof(double)], &tempi, sizeof(int));
short temps = dimension2;
memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int)], &temps, sizeof(short));
memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short)], &parentid2, sizeof(double));
char tempc = subtype;
memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double)], &tempc, sizeof(char));
memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char)], completebuffer, completesize);
delete [] completebuffer;
LEAVE( "DBHierIndex::getBinaryRepresentation()" );
return brp;
}
void
DBHierIndex::setBinaryRepresentation(const BinaryRepresentation& brp) throw (r_Error)
{
ENTER( "DBHierIndex::setBinaryRepresentation()" );
if (memcmp(brp.binaryData, BinaryRepresentation::fileTag, 5) != 0)
{
RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") not a correct data set " << brp.binaryData << endl;
throw r_Error();
}
if (brp.binaryData[5] != 1)
{
RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") not unknown export version " << (int)brp.binaryData[5] << endl;
throw r_Error();
}
if (brp.binaryData[6] != (r_Endian::get_endianness() == r_Endian::r_Endian_Little))
{
RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") endianess conversion not supported" << endl;
throw r_Error();
}
size_t size1;
short dimension1;
double parentid1;
int tempi;
short temps;
char tempc;
double tempd;
memcpy((char*)&tempd, &brp.binaryData[7], sizeof(double));
myOId = tempd;
char* temp = getBinaryName();
if (strcmp(temp, brp.binaryName) != 0)
{
RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") my name should be " << temp << endl;
delete [] temp;
throw r_Error();
}
delete [] temp;
temp = NULL;
memcpy(&tempi, &brp.binaryData[7 + sizeof(double)], sizeof(int));
size1 = tempi;
memcpy(&temps, &brp.binaryData[7 + sizeof(double) + sizeof(int)], sizeof(short));
dimension1 = temps;
memcpy(&parentid1, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short)], sizeof(double));
memcpy(&tempc, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double)], sizeof(char));
_isNode = tempc;
if (parentid1)
parent = OId(parentid1);
else
parent = OId(0, OId::INVALID);
//number of bytes for bounds for "size" entries and mydomain
r_Bytes boundssize = sizeof(r_Range) * (size1 + 1) * dimension1;
//number of bytes for fixes for "size" entries and mydomain
r_Bytes fixessize = sizeof(char) * (size1 + 1) * dimension1;
//number of bytes for ids of entries
r_Bytes idssize = sizeof(OId::OIdCounter) * size1;
//number of bytes for types of entries
r_Bytes typessize = sizeof(char) * size1;
//number of bytes for the dynamic data
r_Bytes completesize = boundssize * 2 + fixessize * 2 + idssize + typessize;
RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "size " << size1 << " dimension " << dimension1 << " fixes " << fixessize << " ids " << idssize << " types " << typessize);
TALK( "DBHierIndex::setBinaryRepresentation(): size=" << size1 << ", dimension=" << dimension1 << ", fixes=" << fixessize << ", ids=" << idssize << ", types=" << typessize );
char* completebuffer = new char[completesize];
r_Range* upperboundsbuf = new r_Range[boundssize];
r_Range* lowerboundsbuf = new r_Range[boundssize];
char* upperfixedbuf = new char[fixessize];
char* lowerfixedbuf = new char[fixessize];
OId::OIdCounter* entryidsbuf = new OId::OIdCounter[idssize];
char* entrytypesbuf = new char[typessize];
memcpy(completebuffer, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char)], completesize);
//all dynamic data is in completebuffer
//put that stuff in the correct buffers
memcpy(lowerboundsbuf, completebuffer, boundssize);
memcpy(upperboundsbuf, &completebuffer[boundssize], boundssize);
memcpy(lowerfixedbuf, &completebuffer[boundssize * 2], fixessize);
memcpy(upperfixedbuf, &completebuffer[boundssize * 2 + fixessize], fixessize);
memcpy(entryidsbuf, &completebuffer[boundssize * 2 + fixessize * 2], idssize);
memcpy(entrytypesbuf, &completebuffer[boundssize * 2 + fixessize * 2 + idssize], typessize);
//all dynamic data is in its buffer
delete [] completebuffer;
completebuffer = NULL;
int i = 0;
//rebuild the attributes from the buffers
myDomain = InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[i*dimension1]));
RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " constructed from " << InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
KeyObject theKey = KeyObject(DBObjectId(), myDomain);
for (i = 0; i < size1; i++)
{
theKey.setDomain(InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1])));
theKey.setObject(OId(entryidsbuf[i], (OId::OIdType)entrytypesbuf[i]));
myKeyObjects.push_back(theKey);
RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1])));
}
delete [] upperboundsbuf;
delete [] lowerboundsbuf;
delete [] upperfixedbuf;
delete [] lowerfixedbuf;
delete [] entryidsbuf;
delete [] entrytypesbuf;
_isInDatabase = true;
_isPersistent = true;
_isModified = true;
currentDbRows = 1;
LEAVE( "DBHierIndex::setBinaryRepresentation()" );
}