summaryrefslogtreecommitdiffstats
path: root/indexmgr
diff options
context:
space:
mode:
authorConstantin Jucovschi <cj@ubuntu.localdomain>2009-04-24 07:20:22 -0400
committerConstantin Jucovschi <cj@ubuntu.localdomain>2009-04-24 07:20:22 -0400
commit8f27e65bddd7d4b8515ce620fb485fdd78fcdf89 (patch)
treebd328a4dd4f92d32202241b5e3a7f36177792c5f /indexmgr
downloadrasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.gz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.xz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.zip
Initial commitv8.0
Diffstat (limited to 'indexmgr')
-rw-r--r--indexmgr/Makefile.am38
-rw-r--r--indexmgr/hierindexds.cc23
-rw-r--r--indexmgr/hierindexds.hh118
-rw-r--r--indexmgr/indexds.cc24
-rw-r--r--indexmgr/indexds.hh176
-rw-r--r--indexmgr/keyobject.cc135
-rw-r--r--indexmgr/keyobject.hh134
-rw-r--r--indexmgr/mddobjix.cc529
-rw-r--r--indexmgr/mddobjix.hh274
-rw-r--r--indexmgr/persmddobjix.cc2
-rw-r--r--indexmgr/persmddobjix.hh1
-rw-r--r--indexmgr/sdirindexlogic.cc333
-rw-r--r--indexmgr/sdirindexlogic.hh169
-rw-r--r--indexmgr/srcindexlogic.cc288
-rw-r--r--indexmgr/srcindexlogic.hh132
-rw-r--r--indexmgr/srptindexlogic.cc1147
-rw-r--r--indexmgr/srptindexlogic.hh244
-rw-r--r--indexmgr/test/Makefile103
-rw-r--r--indexmgr/test/test_abc.cc373
-rw-r--r--indexmgr/test/test_clusterix.cc338
-rw-r--r--indexmgr/test/test_dirix.cc357
-rw-r--r--indexmgr/test/test_expix.cc488
-rw-r--r--indexmgr/test/test_hierix.cc388
-rw-r--r--indexmgr/test/test_ix.cc517
-rw-r--r--indexmgr/test/test_ix1.cc853
-rw-r--r--indexmgr/transdirix.cc269
-rw-r--r--indexmgr/transdirix.hh141
27 files changed, 7594 insertions, 0 deletions
diff --git a/indexmgr/Makefile.am b/indexmgr/Makefile.am
new file mode 100644
index 0000000..01eac08
--- /dev/null
+++ b/indexmgr/Makefile.am
@@ -0,0 +1,38 @@
+# -*-Makefile-*- (for Emacs)
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# indexmgr
+#
+#
+# COMMENTS:
+#
+##################################################################
+
+noinst_LIBRARIES=libindexmgr.a
+libindexmgr_a_SOURCES= mddobjix.cc transdirix.cc keyobject.cc srptindexlogic.cc \
+ sdirindexlogic.cc indexds.cc hierindexds.cc srcindexlogic.cc \
+ mddobjix.hh transdirix.hh keyobject.hh srptindexlogic.hh \
+ sdirindexlogic.hh indexds.hh hierindexds.hh srcindexlogic.hh
+
+CLEANFILES=core
diff --git a/indexmgr/hierindexds.cc b/indexmgr/hierindexds.cc
new file mode 100644
index 0000000..9ccc2ce
--- /dev/null
+++ b/indexmgr/hierindexds.cc
@@ -0,0 +1,23 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "relindexif/hierindex.hh"
diff --git a/indexmgr/hierindexds.hh b/indexmgr/hierindexds.hh
new file mode 100644
index 0000000..c4aedb6
--- /dev/null
+++ b/indexmgr/hierindexds.hh
@@ -0,0 +1,118 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: hierindexds.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: HierIndexDS
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _HIERINDEXDS_HH_
+#define _HIERINDEXDS_HH_
+
+#include "indexmgr/indexds.hh"
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+ Interface class for Data Structure classes of Hierarchical Indexes.
+ Classes which wish to use the RPTreeIndexLogic must implement this
+ class.
+*/
+
+class HierIndexDS : public IndexDS
+ {
+ public:
+ HierIndexDS():IndexDS() {}
+
+ HierIndexDS(const OId& id):IndexDS(id) {}
+
+ virtual double getOccupancy() const = 0;
+ /*@Doc:
+ Return the relative occupancy of this index.
+ For flat indexes return 0.
+ Not implemented.
+ */
+
+ virtual HierIndexDS* getParent() const = 0;
+ /*@Doc:
+ Returns a newly constructed HierIndexDS pointer to this
+ object`s parent.
+ */
+
+ virtual void setParent(const HierIndexDS* newPa) = 0;
+ /*@Doc:
+ Sets the parent node of this object to newPa.
+ */
+
+ virtual void setIsNode(bool beNode) = 0;
+ /*@Doc:
+ When set to false, this index will behave as a leaf.
+ When set to true, this index will behave as a node.
+ */
+
+ virtual bool isLeaf() const = 0;
+ /*@Doc:
+ If true this index contains objects which are stored in the index.
+ If false this index contains index nodes.
+ */
+
+ virtual bool isRoot() const = 0;
+ /*@Doc:
+ If true this object is the root node.
+ */
+
+ virtual unsigned int getHeight() const = 0;
+ /*@Doc:
+ Returns the height of this subtree.
+ Returns the complete height when called by the root node.
+ */
+
+ virtual unsigned int getTotalEntryCount() const = 0;
+ /*@Doc:
+ Get number of entries in leafs of the subtree.
+ Returns the number of all entries in the tree
+ when called by the root node.
+ */
+
+ virtual unsigned int getTotalNodeCount() const = 0;
+ /*@Doc:
+ Get number of nodes in the tree.
+ Returns the number of all nodes in the tree
+ when called by the root node.
+ I do not count myself.
+ */
+
+ virtual unsigned int getTotalLeafCount() const = 0;
+ /*@Doc:
+ Get number of leafs in this subtree.
+ Returns the number of all leafes in the tree
+ when called by the root node.
+ I do count myself -> I am a leaf, I return 1.
+ */
+
+ };
+
+#endif
diff --git a/indexmgr/indexds.cc b/indexmgr/indexds.cc
new file mode 100644
index 0000000..04c3dd2
--- /dev/null
+++ b/indexmgr/indexds.cc
@@ -0,0 +1,24 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "indexds.hh"
+
diff --git a/indexmgr/indexds.hh b/indexmgr/indexds.hh
new file mode 100644
index 0000000..ede1583
--- /dev/null
+++ b/indexmgr/indexds.hh
@@ -0,0 +1,176 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: indexds.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: IndexDS
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _INDEXDS_HH_
+#define _INDEXDS_HH_
+
+#include "reladminif/dbobject.hh"
+#include "reladminif/lists.h"
+#include "reladminif/oidif.hh"
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+This is an interface class. It is abstract. It supplies the signature that
+is required to allow SDirIndexLogic to manage this object.
+
+*/
+
+class IndexDS : public DBObject
+ {
+ public:
+ IndexDS():DBObject() {}
+
+ IndexDS(const OId& id):DBObject(id) {}
+
+ virtual r_Minterval getCoveredDomain() const = 0;
+ /*@Doc:
+ returns the domain which is covered by the entries of this index.
+ when some one has time:
+ this should not be persistent
+ this is not the same as assigned domain
+ this should be updated automatically when removing and adding entries, and is
+ */
+
+ virtual r_Minterval getAssignedDomain() const = 0;
+ /*@Doc:
+ returns the domain this index is responsible for (assigned domain).
+ when some one has time:
+ this is persistent and should be
+ this should not be the same as covered domain, but is
+ this should not be updated when removing entries, but is because of above
+ */
+
+ virtual r_Minterval getObjectDomain(unsigned int pos) const = 0;
+ /*@Doc:
+ Returns the (assigned) domain for the object in position {\ttpos}.
+ The object domain is always a assigned domain, because we do not read the domain from the entries (blobtiles do not store one).
+ At some point this of course makes storing the assigned domain obsolete (because it is stored at the parent, in case of the root it is the covered domain which can be computed from the entries)
+ */
+
+ virtual r_Dimension getDimension() const = 0;
+ /*@Doc:
+ Returns the dimensionality of this index.
+ */
+
+ virtual unsigned int getSize() const = 0;
+ /*@Doc:
+ Only the number of elements in this index node is returned.
+ */
+
+ virtual bool isValid() const = 0;
+ /*@Doc:
+ true when domains of entries of nodes are completely covered
+ by the assigned domains of the nodes and assigned domains of
+ leafs intersect with each of their entries domains. The assigned domains may not intersect.
+ false otherwise.
+ */
+
+ virtual bool isUnderFull() const = 0;
+ /*@Doc:
+ Returns true when the index does not have the minimal number of entries (it is a candidate for merging).
+ Otherwise false.
+ */
+
+ virtual bool isOverFull() const = 0;
+ /*@Doc:
+ Same as above but vice versa.
+ */
+
+ virtual bool isSameAs(const IndexDS* pix) const = 0;
+ /*@Doc:
+ Compares two index data structures:
+ When both are persistent, their oids are compared.
+ When both are transient there memory address is compared.
+ Else they are not equal.
+ */
+
+ virtual bool removeObject(unsigned int pos) = 0;
+ /*@Doc:
+ Removes an object from this index. It returns true if the object was successfully removed.
+ */
+
+ virtual bool removeObject(const KeyObject& theKey) = 0;
+ /*@Doc:
+ Removes an object from this index. It returns true if the object was successfully removed.
+ */
+
+ virtual void insertObject(const KeyObject& theKey, unsigned int pos) = 0;
+ /*@Doc:
+ Inserts the object in theKey at the sppecified position.
+ Position 0 means at the front.
+ */
+
+ virtual void setAssignedDomain(const r_Minterval& domain) = 0;
+ /*@Doc:
+ Sets the assigned domain.
+ */
+
+ virtual void setObject(const KeyObject& theKey, unsigned int pos) = 0;
+ /*@Doc:
+ Sets the entry and domain at position pos.
+ */
+
+ virtual void setObjectDomain(const r_Minterval& dom, unsigned int pos) = 0;
+ /*@Doc:
+ Sets the assigned domain of the object at position pos to dom.
+ */
+
+ virtual const KeyObject& getObject(unsigned int pos) const = 0;
+ /*@Doc:
+ The requested object will be placed in result.
+ */
+
+ virtual void getObjects(KeyObjectVector& objs) const = 0;
+ /*@Doc:
+ Push all entries into the vector
+ */
+
+ virtual unsigned int getOptimalSize() const = 0;
+ /*@Doc:
+ Computes the optimal number of entries for this index.
+ Should be moved to a place where StorageLayout is accessible.
+ */
+
+ virtual void freeDS() = 0;
+ /*@Doc:
+ Marks the persistent database index data structure for
+ deletion all entries contained in it will be deleted
+ from the database along with it.
+ */
+
+ virtual OId::OIdPrimitive getIdentifier() const = 0;
+
+ virtual IndexDS* getNewInstance() const = 0;
+ };
+
+#endif
diff --git a/indexmgr/keyobject.cc b/indexmgr/keyobject.cc
new file mode 100644
index 0000000..e1d46ab
--- /dev/null
+++ b/indexmgr/keyobject.cc
@@ -0,0 +1,135 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "keyobject.hh"
+#include "tilemgr/tile.hh"
+
+ostream& operator<<(ostream& in, const KeyObject& d)
+ {
+ if (d.isPersCarrier())
+ {
+ in << "Carrier{" << d.getDomain() << ", " << d.getObject().getOId() << "}";
+ }
+ else {
+ in << "Carrier{" << d.getDomain() << ", TransTile}";
+ }
+ return in;
+ }
+
+KeyObject::KeyObject()
+ : transobject(NULL)
+ {
+ }
+
+KeyObject::KeyObject(const KeyObject& old)
+ : persobject(old.persobject),
+ domain(old.domain),
+ transobject(old.transobject)
+ {
+ }
+
+KeyObject::KeyObject(const Tile* tile)
+ : persobject(),
+ domain(tile->getDomain()),
+ transobject(NULL)
+ {
+ if (tile->isPersistent())
+ {
+ persobject = (const DBObjectId&)((Tile*)tile)->getDBTile();
+ }
+ else {
+ transobject = (Tile*)tile;
+ }
+ }
+
+KeyObject::KeyObject(const DBObjectId& obj, const r_Minterval& dom)
+ : persobject(obj),
+ domain(dom),
+ transobject(NULL)
+ {
+ }
+
+KeyObject::~KeyObject()
+ {
+ transobject = NULL;
+ }
+
+void
+KeyObject::setDomain(const r_Minterval& dom)
+ {
+ domain = dom;
+ }
+
+void
+KeyObject::setTransObject(const Tile* tile)
+ {
+ domain = tile->getDomain();
+ transobject = (Tile*)tile;
+ }
+
+void
+KeyObject::setObject(const DBObjectId& obj)
+ {
+ persobject = obj;
+ }
+
+bool
+KeyObject::isInitialised() const
+ {
+ if (transobject)
+ return true;
+ if (persobject.isInitialised())
+ return true;
+ return false;
+ }
+
+bool
+KeyObject::isPersCarrier() const
+ {
+ return (transobject == NULL);
+ }
+
+Tile*
+KeyObject::getTransObject() const
+ {
+ return transobject;
+ }
+
+const DBObjectId&
+KeyObject::getObject() const
+ {
+ return persobject;
+ }
+
+r_Minterval
+KeyObject::getDomain() const
+ {
+ return domain;
+ }
+/*
+const r_Minterval&
+KeyObject::getDomain() const
+ {
+ return domain;
+A }
+*/
diff --git a/indexmgr/keyobject.hh b/indexmgr/keyobject.hh
new file mode 100644
index 0000000..51bf89c
--- /dev/null
+++ b/indexmgr/keyobject.hh
@@ -0,0 +1,134 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _KEYOBJECT_HH_
+#define _KEYOBJECT_HH_
+
+class Tile;
+class KeyObject;
+
+#include "reladminif/dbobject.hh"
+#include "raslib/minterval.hh"
+#include "reladminif/dbref.hh"
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+This class is a carrier structure which carries objects and their domains
+through the different levels of the index.
+*/
+class KeyObject
+ {
+ public:
+ KeyObject();
+
+ KeyObject(const KeyObject& old);
+ /*@Doc:
+ Copy constructor. Copies the tile pointer.
+ */
+
+ KeyObject(const Tile* p);
+ /*@Doc:
+ Construccts a new KeyObject. The type (persistent/transinet)
+ is deremined based on the Tile. The domain also.
+ This constructor is sometimes misused by the compiler in statements like KeyObject p = 0.
+ This will cause a crash because the domain is read from the tile which is NULL : )
+ */
+
+ KeyObject(const DBObjectId& obj, const r_Minterval& dom);
+ /*@Doc:
+ Constructs a new KeyObject for a persistent object.
+ */
+
+ const DBObjectId& getObject() const;
+ /*@Doc:
+ Returns a smartpointer to the persistent object attribute.
+ If this is a transient object carrier the returned smart-
+ pointer is invalid.
+ */
+
+ Tile* getTransObject() const;
+ /*@Doc:
+ Returns the transient object. If this KeyObject carries
+ a persistent object a NULL is returned.
+ */
+
+ r_Minterval getDomain() const;
+ /*@Doc:
+ Returns the domain which is associated with the objects that
+ is carried.
+ */
+
+ ~KeyObject();
+ /*@Doc:
+ Does not delete the TransTile!!
+ */
+
+ bool isInitialised() const;
+ /*@Doc:
+ Returns true if trans object is initialised or the dbref is initialised.
+ */
+
+ bool isPersCarrier() const;
+ /*@Doc:
+ Returns true if the transobject attribute is NULL.
+ */
+
+ void setDomain(const r_Minterval& dom);
+ /*@Doc:
+ Alters the domain the KeyObject carries.
+ */
+
+ void setTransObject(const Tile* tile);
+ /*@Doc:
+ makes the KeyObject a transient carrier and copies the pointer.
+ */
+
+ void setObject(const DBObjectId& obj);
+ /*@Doc:
+ makes the KeyObject a persistent carrier and copies object.
+ */
+
+ protected:
+ DBObjectId persobject;
+ /*@Doc:
+ A smartpointer to the carried object if it is persistent.
+ */
+
+ r_Minterval domain;
+ /*@Doc:
+ The domain which the carried object belongs to.
+ */
+
+ Tile* transobject;
+ /*@Doc:
+ Attribute for storing a transtile. is NULL if a persistent
+ object is carried.
+ */
+ };
+
+/*@Doc:
+ Prints the status of KeyObject object.
+*/
+extern std::ostream& operator<<(std::ostream& in, const KeyObject& d);
+
+#endif
diff --git a/indexmgr/mddobjix.cc b/indexmgr/mddobjix.cc
new file mode 100644
index 0000000..6e85d97
--- /dev/null
+++ b/indexmgr/mddobjix.cc
@@ -0,0 +1,529 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: mddobjix.cc
+ *
+ * MODULE: indexmgr
+ * CLASS: MDDObjIx
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+static const char rcsid[] = "@(#)mddobjix, MDDObjIx: $Id: mddobjix.cc,v 1.30 2002/07/24 14:33:51 hoefner Exp $";
+
+#include <iostream>
+#include <math.h>
+
+#include "indexmgr/mddobjix.hh"
+#include "raslib/rmdebug.hh"
+#include "tilemgr/tile.hh"
+#include "indexmgr/srptindexlogic.hh"
+#include "indexmgr/sdirindexlogic.hh"
+#include "indexmgr/srcindexlogic.hh"
+#include "indexmgr/transdirix.hh"
+#include "relindexif/hierindex.hh"
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/dbrcindexds.hh"
+#include "keyobject.hh"
+#include "reladminif/lists.h"
+#include "relblobif/tileid.hh"
+
+void
+MDDObjIx::setNewLastAccess(const r_Minterval& newLastAccess, const std::vector<Tile*>* newLastTiles)
+ {
+ lastAccess = newLastAccess;
+ releasePersTiles();
+ lastAccessTiles = *newLastTiles;
+ }
+
+void
+MDDObjIx::setNewLastAccess(const Tile* newLastTile, bool clear)
+ {
+ if (clear)
+ {
+ releasePersTiles();
+ lastAccessTiles.erase(lastAccessTiles.begin(), lastAccessTiles.end());
+ }
+ if (newLastTile)
+ {
+ r_Minterval region = newLastTile->getDomain();
+ lastAccess = region;
+ lastAccessTiles.push_back((Tile*)newLastTile);
+ }
+ }
+
+bool
+MDDObjIx::removeTileFromLastAccesses(const Tile* tileToRemove)
+ {
+ bool found = false;
+ std::vector<Tile*>::iterator iter;
+ for (iter = lastAccessTiles.begin(); iter != lastAccessTiles.end() ; iter++)
+ {
+ if (*iter == tileToRemove)
+ {
+ found = true;
+ lastAccessTiles.erase(iter);
+ break;
+ }
+ }
+ if (found)
+ {
+ r_Minterval emptyInterval;
+ lastAccess = emptyInterval;
+ }
+ return found;
+ }
+
+std::vector< Tile* >*
+MDDObjIx::lastAccessIntersect(const r_Minterval& searchInter) const
+ {
+ std::vector< Tile* >* interResult = 0;
+ if ((lastAccess.dimension() != 0) && (lastAccess.covers(searchInter)))
+ {
+ RMDBGONCE(6, RMDebug::module_indexmgr, "MDDObjIx", "lastAccessIntersect Search in the cache ")
+ interResult = new std::vector< Tile* >();
+ interResult->reserve(10);
+ for (int i = 0; i < lastAccessTiles.size(); i++)
+ {
+ if (lastAccessTiles[i]->getDomain().intersects_with(searchInter))
+ interResult->push_back(lastAccessTiles[i]);
+ }
+ if (interResult->size() == 0)
+ {
+ delete interResult;
+ interResult = NULL;
+ }
+ }
+ return interResult;
+ }
+
+Tile*
+MDDObjIx::lastAccessPointQuery(const r_Point& searchPoint) const
+ {
+ Tile* result = 0;
+
+ if ((lastAccess.dimension() != 0) && (lastAccess.covers(searchPoint)))
+ {
+ for (int i = 0; !result && i < lastAccessTiles.size(); i++)
+ {
+ if (lastAccessTiles[i]->getDomain().covers(searchPoint))
+ {
+ result = lastAccessTiles[i];
+ }
+ }
+ }
+ return (result);
+ }
+
+void
+MDDObjIx::releasePersTiles()
+ {
+ RMDBGENTER(6, RMDebug::module_indexmgr, "MDDObjIx", "releasePersTiles()")
+ if (isPersistent())
+ {
+ Tile* t = NULL;
+ for(int i = 0; i < lastAccessTiles.size(); i++)
+ {
+ t = lastAccessTiles[i];
+ delete t;
+ lastAccessTiles[i] = NULL;
+ }
+ lastAccessTiles.clear();
+ }
+ RMDBGEXIT(6, RMDebug::module_indexmgr, "MDDObjIx", "releasePersTiles()")
+ }
+
+void
+MDDObjIx::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ stream << "MDDObjIx [ last access interval = " << lastAccess << " tile cache size = " << lastAccessTiles.size() << " index structure = ";
+ actualIx->printStatus(level, stream);
+ }
+
+DBObjectId
+MDDObjIx::getDBMDDObjIxId() const
+ {
+ return actualIx;
+ }
+
+r_Minterval
+MDDObjIx::getCurrentDomain() const
+ {
+ return actualIx->getCoveredDomain();
+ }
+
+r_Dimension
+MDDObjIx::getDimension() const
+ {
+ return actualIx->getDimension();
+ }
+
+#ifdef RMANBENCHMARK
+void
+MDDObjIx::initializeTimerPointers()
+ {
+ pointQueryTimer= new RMTimer("DirIx", "pointQuery time ");
+ intersectTimer = new RMTimer("DirIx", "intersect time ");
+ getTilesTimer = new RMTimer("DirIx", "getTiles time ");
+ }
+#endif
+
+MDDObjIx::MDDObjIx(const StorageLayout& sl, const r_Minterval& dim, const BaseType* bt)
+ : cellBaseType(bt),
+ myStorageLayout(sl),
+ actualIx(0),
+ _isPersistent(true)
+ {
+ RMDBGENTER(10, RMDebug::module_indexmgr, "MDDObjIx", "MDDObjIx(storage, " << dim << ", type)")
+ lastAccessTiles.reserve(10);
+ if (bt == NULL)
+ {
+ RMDBGMIDDLE(10, RMDebug::module_indexmgr, "MDDObjIx", "TransIndex")
+ _isPersistent = false;
+ }
+ initializeLogicStructure();
+ if (isPersistent())
+ {
+ r_Range temp;
+ switch(myStorageLayout.getIndexType())
+ {
+ case r_RPlus_Tree_Index:
+ actualIx = (HierIndexDS*)new DBHierIndex(dim.dimension(), false, true);
+ break;
+ case r_Reg_Computed_Index:
+ actualIx = new DBRCIndexDS(dim, SRCIndexLogic::computeNumberOfTiles(myStorageLayout, dim));
+ break;
+ case r_Tile_Container_Index:
+ actualIx = (HierIndexDS*)new DBTCIndex(dim.dimension(), false);
+ break;
+ case r_Directory_Index:
+ actualIx = (HierIndexDS*)new DBHierIndex(dim.dimension(), false, true);
+ break;
+ case r_Auto_Index:
+ default:
+ // should never get here. If Auto_Index, a specific index was
+ RMDBGONCE(0, RMDebug::module_indexmgr, "MDDObjIx", "initializeLogicStructure() Auto_Index or unknown index chosen");
+ throw r_Error(UNKNOWN_INDEX_TYPE);
+ break;
+ }
+ }
+ else {
+ //only dirindex supports transient indexes
+ actualIx = new TransDirIx(dim.dimension());
+ }
+#ifdef RMANBENCHMARK
+ initializeTimerPointers();
+#endif
+ RMDBGEXIT(10, RMDebug::module_indexmgr, "MDDObjIx", "MDDObjIx(storage, " << dim << ", type)")
+ }
+
+MDDObjIx::MDDObjIx(DBObjectId newDBIx, const StorageLayout& sl, const BaseType* bt)
+ : cellBaseType(bt),
+ myStorageLayout(sl),
+ actualIx(newDBIx),
+ _isPersistent(true)
+ {
+ initializeLogicStructure();
+ lastAccessTiles.reserve(10);
+#ifdef RMANBENCHMARK
+ initializeTimerPointers();
+#endif
+ }
+
+void
+MDDObjIx::initializeLogicStructure()
+ {
+ switch(myStorageLayout.getIndexType())
+ {
+ case r_RPlus_Tree_Index:
+ case r_Tile_Container_Index:
+ do_getObjs = SRPTIndexLogic::getObjects;
+ do_insertObj = SRPTIndexLogic::insertObject2;
+ do_pointQuery = SRPTIndexLogic::containPointQuery2;
+ do_removeObj = SRPTIndexLogic::removeObject;
+ do_intersect = SRPTIndexLogic::intersect2;
+ break;
+ case r_Reg_Computed_Index:
+ do_getObjs = SRCIndexLogic::getObjects;
+ do_insertObj = SRCIndexLogic::insertObject;
+ do_pointQuery = SRCIndexLogic::containPointQuery;
+ do_removeObj = SRCIndexLogic::removeObject;
+ do_intersect = SRCIndexLogic::intersect;
+ break;
+ case r_Directory_Index:
+ // chosen before this
+ do_getObjs = SDirIndexLogic::getObjects;
+ do_pointQuery = SDirIndexLogic::containPointQuery;
+ do_removeObj = SDirIndexLogic::removeObject;
+ do_intersect = SDirIndexLogic::intersect;
+ do_insertObj = SDirIndexLogic::insertObject;
+ break;
+ default:
+ case r_Auto_Index:
+ // should never get here. If Auto_Index, a specific index was
+ RMInit::logOut << "MDDObjIx::initializeLogicStructure() illegal index (" << myStorageLayout.getIndexType() << ") chosen!" << endl;
+ throw r_Error(ILLEGAL_INDEX_TYPE);
+ break;
+ }
+ }
+
+
+void
+MDDObjIx::insertTile(const Tile* newTile)
+ {
+ if (isPersistent())
+ {
+ ((Tile*)newTile)->setPersistent();
+ }
+ KeyObject t(newTile);
+ do_insertObj(actualIx, t, myStorageLayout);
+ setNewLastAccess(newTile, false);
+ }
+
+bool
+MDDObjIx::removeTile(const Tile* tileToRemove)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "MDDObjIx", "removeTile(Tile)")
+ bool found = false;
+ // removes from cache, if it's there
+ removeTileFromLastAccesses(tileToRemove);
+
+ // removes from the index itself
+ KeyObject t(tileToRemove);
+ found = do_removeObj(actualIx, t, myStorageLayout);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "MDDObjIx", "removeTile(Tile)")
+ return found;
+ }
+
+vector< Tile* >*
+MDDObjIx::intersect(const r_Minterval& searchInter) const
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "MDDObjIx", "intersect(" << searchInter << ")")
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 3) intersectTimer->start();
+#endif
+
+ vector< Tile* >* result = lastAccessIntersect(searchInter);
+ if (!result)
+ {
+ KeyObjectVector resultKeys;
+ do_intersect(actualIx, searchInter, resultKeys, myStorageLayout);
+ result = new vector< Tile* >();
+ if (!resultKeys.empty())
+ {
+ unsigned int resSize = resultKeys.size();
+ result->reserve(resSize);
+ Tile* t = NULL;
+ unsigned int i = 0;
+ if (isPersistent())
+ {
+//this checks if there are double tiles in the result
+ RMDBGIF(1, RMDebug::module_indexmgr, "MDDObjIx", \
+ DomainMap t; \
+ DomainMap::iterator it; \
+ for (i = 0; i < resSize; i++) \
+ { \
+ DomainPair p(resultKeys[i].getObject().getOId(), \
+ resultKeys[i].getDomain()); \
+ if ((it = t.find(p.first)) != t.end()) \
+ { \
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "MDDObjIx", \
+ "intersect(" << searchInter << \
+ ") received double tile: " << \
+ resultKeys[i]) \
+ for (int i = 0; i < resultKeys.size(); i++) \
+ { \
+ RMInit::dbgOut << resultKeys[i] << endl; \
+ } \
+ throw r_Error(TILE_MULTIPLE_TIMES_RETRIEVED); \
+ } \
+ t.insert(p); \
+ } \
+ );
+ for (i = 0; i < resSize; i++)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "MDDObjIx", "received entry " << resultKeys[i])
+ result->push_back(new Tile(resultKeys[i].getDomain(), cellBaseType, DBTileId(resultKeys[i].getObject())));
+ }
+ }
+ else {
+ for (i = 0; i < resSize; i++)
+ {
+ result->push_back(resultKeys[i].getTransObject());
+ }
+ }
+ ((MDDObjIx*) this)->setNewLastAccess(searchInter, result);
+ }
+ }
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 3) intersectTimer->stop();
+#endif
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "MDDObjIx", "intersect(" << searchInter << ") " << (void*)result)
+ return result;
+ }
+
+char*
+MDDObjIx::pointQuery(const r_Point& searchPoint)
+ {
+ char* result = 0;
+
+ Tile* resultTile = containPointQuery(searchPoint);
+
+ if(resultTile)
+ {
+ result = resultTile->getCell(searchPoint);
+ }
+ return result;
+ }
+
+const char*
+MDDObjIx::pointQuery(const r_Point& searchPoint) const
+ {
+ const char* result = 0;
+
+ Tile* resultTile = containPointQuery(searchPoint);
+
+ if(resultTile)
+ {
+ result = resultTile->getCell(searchPoint);
+ }
+ return result;
+ }
+
+Tile*
+MDDObjIx::containPointQuery(const r_Point& searchPoint) const
+ {
+
+ Tile* resultTile = 0;
+
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 4) pointQueryTimer->start();
+#endif
+ resultTile = lastAccessPointQuery(searchPoint);
+ if (!resultTile)
+ {
+ KeyObject resultKey;
+ do_pointQuery(actualIx, searchPoint, resultKey, myStorageLayout);
+ if (resultKey.isInitialised())
+ {
+ if (isPersistent())
+ {
+ resultTile = new Tile(resultKey.getDomain(), cellBaseType, DBTileId(resultKey.getObject()));
+ // for rcindex
+ ((DBObject*)resultKey.getObject().ptr())->setCached(false);
+ }
+ else {
+ resultTile = resultKey.getTransObject();
+ }
+ ((MDDObjIx*) this)->setNewLastAccess(resultTile);
+ }
+ }
+
+#ifdef RMANBENCHMARK
+ if (RManBenchmark >= 4) pointQueryTimer->stop();
+#endif
+ return resultTile;
+ }
+
+vector< Tile* >*
+MDDObjIx::getTiles() const
+ {
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 3) getTilesTimer->start();
+#endif
+ vector< Tile* >* result = NULL;
+ KeyObjectVector resultKeys;
+ do_getObjs(actualIx, resultKeys, myStorageLayout);
+ if (!resultKeys.empty())
+ {
+ result = new vector< Tile* >();
+ unsigned int resSize = resultKeys.size();
+ result->reserve(resSize);
+ Tile* t = 0;
+ if (isPersistent())
+ {
+//this checks if there are double tiles in the result
+ RMDBGIF(1, RMDebug::module_indexmgr, "MDDObjIx", \
+ DomainMap tmap; \
+ DomainMap::iterator it; \
+ for (int cnt = 0; cnt < resSize; cnt++) \
+ { \
+ DomainPair p(resultKeys[cnt].getObject().getOId(), \
+ resultKeys[cnt].getDomain()); \
+ if ((it = tmap.find(p.first)) != tmap.end()) \
+ { \
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "MDDObjIx", \
+ "getTiles() received double tile: " << \
+ resultKeys[cnt]) \
+ for (int cnt = 0; cnt < resultKeys.size(); cnt++) \
+ { \
+ RMInit::dbgOut << resultKeys[cnt] << endl; \
+ } \
+ throw r_Error(TILE_MULTIPLE_TIMES_RETRIEVED ); \
+ } \
+ tmap.insert(p); \
+ } \
+ );
+ for (int i = 0; i < resSize; i++)
+ {
+ result->push_back(new Tile(resultKeys[i].getDomain(), cellBaseType, DBTileId(resultKeys[i].getObject())));
+ }
+ }
+ else {
+ for (int i = 0; i < resultKeys.size(); i++)
+ {
+ result->push_back(resultKeys[i].getTransObject());
+ }
+ }
+ r_Minterval emptyInterval;
+ ((MDDObjIx*) this)->setNewLastAccess(emptyInterval, result);
+ }
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 3) getTilesTimer->stop();
+#endif
+ return result;
+ }
+
+
+bool
+MDDObjIx::isPersistent() const
+ {
+ return _isPersistent;
+ }
+
+MDDObjIx::~MDDObjIx()
+ {
+ releasePersTiles();
+ actualIx->destroy();
+ actualIx = 0;
+
+#ifdef RMANBENCHMARK
+ pointQueryTimer->setOutput(0);
+ if (pointQueryTimer) delete pointQueryTimer;
+ intersectTimer->setOutput(0);
+ if (intersectTimer) delete intersectTimer;
+ getTilesTimer->setOutput(0);
+ if (getTilesTimer) delete getTilesTimer;
+#endif
+ }
diff --git a/indexmgr/mddobjix.hh b/indexmgr/mddobjix.hh
new file mode 100644
index 0000000..0e7dd09
--- /dev/null
+++ b/indexmgr/mddobjix.hh
@@ -0,0 +1,274 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _MDDOBJIX_HH_
+#define _MDDOBJIX_HH_
+
+class PersTile;
+class BaseType;
+class Tile;
+class r_Point;
+#include "raslib/minterval.hh"
+#include "raslib/rmdebug.hh"
+#include "indexmgr/indexds.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "reladminif/lists.h"
+#include "relindexif/indexid.hh"
+#include <vector>
+
+
+/****************************************************************************
+ *
+ *
+ * INCLUDE: mddobjix.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: MDDObjIx
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ****************************************************************************/
+
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+Each MDD Object is composed of a set of tiles which are accessed through an index.
+The task of the index is to determine the tiles affected by a spatial operation and to allow fast access to them. It will also take care of memory management of the tiles.
+
+{\bfMDD Objects indexes: }
+
+MDD Objects indexes are multidimensional since they provide access to multidimensional rectangular tiles existing in multidimensional intervals. An MDDObjIx has to be able to deal with different dimensionalities.
+
+The index of an MDD object keeps the information about the current domain of the MDD object. During the lifetime of the object, it is possible that the definition (or current) domain of an object is not completely covered by the tiles already inserted.
+At each moment, the current domain of an object is the closure of the domains of all tiles. All tiles should be completely contained
+in the definition domain of an object.
+The definition domain may have open boundaries, but the current domain is always a closed interval.
+
+The lower classes in the indexmgr support storage of any kind of persistent object.
+This class has to be changed to reflect this aability.
+
+ In the future, functions have to be implemented which allow the user
+ to give indication about priorities for freeing tiles from main memory.
+
+*/
+
+//function pointer to the static function which inserts objects
+typedef bool (*IxLogic_insertObject) (IndexDS* theIx, const KeyObject& theObj, const StorageLayout& sl);
+
+//function pointer to the static function which removes objects
+typedef bool (*IxLogic_removeObject) (IndexDS* theIx, const KeyObject& theObj, const StorageLayout& sl);
+
+//function pointer to the static function which gets objects from the index
+typedef void (*IxLogic_intersect) (const IndexDS* theIx, const r_Minterval& searchInterval, KeyObjectVector& objs, const StorageLayout& sl);
+
+//function pointer to the static function which gets object at point
+typedef void (*IxLogic_containPointQuery) (const IndexDS* theIx, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl);
+
+//function pointer to the static function which inserts objects
+typedef void (*IxLogic_getObjects) (const IndexDS* theIx, KeyObjectVector& objs, const StorageLayout& sl);
+
+class MDDObjIx
+ {
+ public:
+
+ MDDObjIx(const StorageLayout& sl, const r_Minterval& dom, const BaseType* bt = 0);
+ /*@Doc:
+ When bt is NULL this index will behave as if it were a transient index.
+ */
+
+ MDDObjIx(DBObjectId newDBIx, const StorageLayout& sl, const BaseType* bt);
+ /*@Doc:
+ When bt is NULL this index will behave as if it were a transient index.
+ */
+
+ void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ ~MDDObjIx();
+
+ DBObjectId getDBMDDObjIxId() const;
+
+ r_Minterval getCurrentDomain() const;
+
+ r_Dimension getDimension() const;
+
+ void insertTile(const Tile* newTile);
+
+ bool removeTile(const Tile *);
+
+ std::vector<Tile *> * intersect(const r_Minterval &) const;
+
+ char* pointQuery(const r_Point& searchPoint);
+
+ const char* pointQuery(const r_Point& searchPoint) const;
+
+ Tile* containPointQuery(const r_Point& searchPoint) const;
+
+ std::vector< Tile* >* getTiles() const;
+
+ bool isPersistent() const;
+
+ void releasePersTiles();
+ /*@Doc:
+ This function has to be called by the destructors of persistent subclasses which use the cache, to make sure that the memory for the tiles in the cache is freed.
+ This will only have effect on persistent indexes.
+ Transient indexes keep their tiles in TransDirIx which deletes its tiles in the destructor.
+ */
+
+ protected:
+
+ void setNewLastAccess(const r_Minterval& newLastAccess, const std::vector<Tile*>* newLastTiles);
+
+ void setNewLastAccess(const Tile* newLastTile, bool te = true);
+ /*@Doc:
+ Add a new tile to the cache and reset the access domain
+ If clear:
+ clear the cache
+ release all tiles
+ */
+
+ std::vector< Tile* >* lastAccessIntersect(const r_Minterval& searchInter) const;
+
+ Tile* lastAccessPointQuery(const r_Point& searchPoint) const;
+
+ bool removeTileFromLastAccesses(const Tile* tileToRemove);
+ /*@Doc:
+ Does NOT free tileToRemove allocated memory. Only removes this pointer from lastAccesses list if it finds it there.
+ Returns true if found.
+ Subclasses which use the cache must call this function before removing a tile from the index, or else the tile may remain in main memory.
+ */
+
+ r_Minterval lastAccess;
+ /*@Doc:
+ Either empty interval, if not to search in the cache, or an interval
+ corresponding to the search done the last time. The algorithms which
+ search this cache for an intersection take this into account.
+ It works simultaneously as a flag and as the specification for the last
+ access, if valid.
+ Last searched region.
+ */
+
+ std::vector< Tile* > lastAccessTiles;
+ /*@Doc:
+ Internal cache of {\tt Tile}s accessed the last time.
+ Contents change everytime there is an insert, an intersect, a getTiles
+ or a poin query, in the following way:
+ - insert: cache invalid, last Access is put to empty interval,
+ lastAccessTiles contains the inserted tiles. This is needed
+ if we want the index to automatically manage the memory
+ allocated for persistent tiles or else the just inserted
+ tiles are immediately invalid for the user after insertion
+ in the object. The lastAccess can not be put to the area
+ because it's impossible to determine the area corresponding
+ to inserted tiles (there may be empty areas and so on, it
+ would be rather complex to calculate these things).
+ - intersect/pointquery: cache and lastAccessTiles get the new result.
+ The old access and tiles are thrown away.
+ - getTiles: it would be very inefficient to search here for smaller
+ regions, so lastAccess is made empty and lastAccessTiles
+ contains the tiles accessed (because of PersTiles and
+ automatic management of their memory, they have to be
+ kept by the MDDObjIx).
+ For this reason, tiles passed by PersMDDObj are only valid until the
+ next intersect/pointQuery/insert/getTiles operation.
+ Alternative implementation for getTiles - always put in the cache
+ correctly.
+ Make a check about the search interval and what is in the cache (for
+ example, if cell_count < 90% cache cell count , access index).
+ Such a check should also be done in lastAccessPointQuery(): if the
+ cache has more than 10 elements, it is not worth searching in it for
+ a point.
+ */
+
+ const BaseType* cellBaseType;
+ /*@Doc:
+ This is needed because the PersTile constructor expects a BaseType.
+ It Should be considered to move the creation of PersTiles into the
+ MDDObj class.
+ */
+
+
+ IndexDS* actualIx;
+ /*@Doc:
+ The real index structure
+ */
+
+ IxLogic_insertObject do_insertObj;
+ /*@Doc:
+ Function pointer to insert tile logic
+ */
+
+ IxLogic_removeObject do_removeObj;
+ /*@Doc:
+ Function pointer to remove tile logic
+ */
+
+ IxLogic_intersect do_intersect;
+ /*@Doc:
+ Function pointer to find tiles logic
+ */
+
+ IxLogic_containPointQuery do_pointQuery;
+ /*@Doc:
+ Function pointer to find tile logic
+ */
+
+ IxLogic_getObjects do_getObjs;
+ /*@Doc:
+ Function pointer to get all tiles logic
+ */
+
+ #ifdef RMANBENCHMARK
+
+ void initializeTimerPointers();
+ /*@Doc:
+ This code was commented out because it crashed
+ */
+
+ RMTimer *pointQueryTimer;
+ RMTimer *intersectTimer;
+ RMTimer *getTilesTimer;
+ #endif
+ void initializeLogicStructure();
+ /**
+ {\tt actualDBIx} and {\tt cellBaseType} must be already correctly set.
+ The function pointers are set according to the index type.
+ */
+
+ bool _isPersistent;
+ /*@Doc:
+ This class is used for both persistent and tranisent objects
+ To be able to distinguish whether it is persistent or transient
+ this attribute is used.
+ */
+
+ const StorageLayout& myStorageLayout;
+ /*@Doc:
+ Nifty object which holds information on how to store data in the database.
+ It tells you which index to use, hos large a index might become and so on.
+ */
+ };
+
+#endif
diff --git a/indexmgr/persmddobjix.cc b/indexmgr/persmddobjix.cc
new file mode 100644
index 0000000..02a8c2d
--- /dev/null
+++ b/indexmgr/persmddobjix.cc
@@ -0,0 +1,2 @@
+//moved to mddobjix
+
diff --git a/indexmgr/persmddobjix.hh b/indexmgr/persmddobjix.hh
new file mode 100644
index 0000000..b4e4c9b
--- /dev/null
+++ b/indexmgr/persmddobjix.hh
@@ -0,0 +1 @@
+//moved to mddobjix
diff --git a/indexmgr/sdirindexlogic.cc b/indexmgr/sdirindexlogic.cc
new file mode 100644
index 0000000..e63ba22
--- /dev/null
+++ b/indexmgr/sdirindexlogic.cc
@@ -0,0 +1,333 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: dirix.cc
+ *
+ * MODULE: indexmgr
+ * CLASS: SDirIndexLogic
+ *
+ * COMMENTS:
+ *
+*/
+static const char rcsiddirix[] = "@(#)dirix, SDirIndexLogic: $Id: sdirindexlogic.cc,v 1.10 2002/06/15 18:27:49 coman Exp $";
+
+#include <iostream>
+#include "raslib/rmdebug.hh"
+#include "indexmgr/sdirindexlogic.hh"
+#include "keyobject.hh"
+#include "indexds.hh"
+
+
+bool
+SDirIndexLogic::insertObject(IndexDS* ixDS, const KeyObject& newKeyObject, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "insertObject(" << newKeyObject << ")");
+ r_Minterval newKeyObjectDomain = newKeyObject.getDomain();
+
+ int pos = binarySearch(ixDS, newKeyObjectDomain, Lowest, 0, (int)ixDS->getSize()-1);
+ ixDS->insertObject(newKeyObject, pos + 1);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "insertObject(" << newKeyObject << ")");
+ //should check if insertion was succesfull
+ return true;
+ }
+
+int
+SDirIndexLogic::binarySearch( const IndexDS* ixDS,
+ const r_Minterval& newDomain,
+ OrderPoint o,
+ int first,
+ int last)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binarySearch(" << newDomain << ", " << (int)o << ", " << first <<", " << last << ")");
+ int retval = 0;
+ int middle = 0;
+ int compResult = 0;
+
+ if (first > last)
+ retval = last;
+ else {
+ middle = (last + first) /2;
+ compResult = compare(newDomain, ixDS->getObjectDomain(middle), o , o);
+ if (compResult < 0)
+ retval = binarySearch(ixDS, newDomain, o, first, middle - 1);
+ else
+ if (compResult > 0)
+ retval = binarySearch(ixDS, newDomain, o, middle + 1, last);
+ else
+ retval = middle;
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binarySearch(" << newDomain << ", " << (int)o << ", " << first <<", " << last << ") " << retval);
+ return retval;
+ }
+
+
+int
+SDirIndexLogic::binaryPointSearch( const IndexDS* ixDS,
+ const r_Point& pnt,
+ SDirIndexLogic::OrderPoint o,
+ int first,
+ int last)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryPointSearch(" << pnt << ", " << (int)o << ", " << first << ", " << last << ")");
+ int retval = 0;
+ int middle = 0;
+ int compResult = 0;
+ r_Minterval KeyObjectDomain;
+ r_Point pnt2;
+
+ if (first > last)
+ retval = -1;
+ else
+ {
+ middle = (last + first) /2;
+ KeyObjectDomain = ixDS->getObjectDomain(middle);
+ if (KeyObjectDomain.covers(pnt) == 1)
+ retval = middle;
+ else
+ {
+ switch(o)
+ {
+ case Highest:
+ pnt2 = KeyObjectDomain.get_high();
+ break;
+ case Lowest:
+ pnt2 = KeyObjectDomain.get_origin();
+ break;
+ case None:
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryPointSearch(...) o is None");
+ break;
+ }
+
+ compResult = pnt.compare_with(pnt2);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryPointSearch compResult " << compResult);
+
+ if (compResult > 0 && o == Highest)
+ retval = binaryPointSearch(ixDS, pnt, o, middle+1, last);
+ else
+ if (compResult < 0 && o == Lowest)
+ retval = binaryPointSearch(ixDS, pnt, o, first, middle -1);
+ else
+ {
+ compResult = binaryPointSearch(ixDS, pnt, o, middle +1, last);
+ if (compResult < 0)
+ retval = binaryPointSearch(ixDS, pnt, o, first, middle -1);
+ else
+ retval = compResult;
+ }
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryPointSearch(" << pnt << ", " << (int)o << ", " << first << ", " << last << ") " << retval);
+ return retval;
+ }
+
+
+int
+SDirIndexLogic::binaryRegionSearch( const IndexDS* ixDS,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ int first,
+ int last)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryRegionSearch(" << mint << ", " << area << ", vector, " << first << ", " << last << ")");
+ int retval = 0;
+ int middle = 0;
+ r_Minterval t;
+ int inc = 0;
+ int ix = 0;
+ r_Minterval objDomain;
+ int compResult = 0;
+ KeyObject newObj;
+ r_Minterval intersectedRegion;
+ // assumes order according to the lowest corner of the objects
+ if (first > last)
+ retval = -1;
+ else {
+ middle = (last + first) / 2;
+ t = ixDS->getObjectDomain(middle);
+ if (mint.get_high().compare_with(t.get_origin()) < 0)
+ {// R.hi < tile.lo no tiles after this one
+ retval = binaryRegionSearch(ixDS, mint, area, intersectedObjects, first, middle - 1);
+ }
+ else {
+ if (t.get_high().compare_with(mint.get_origin()) < 0)
+ {
+ retval = binaryRegionSearch(ixDS, mint, area, intersectedObjects, middle + 1, last);
+ if (area > 0)
+ retval = binaryRegionSearch(ixDS, mint, area, intersectedObjects, first, middle - 1);
+ }
+ else {
+ inc = 1;
+ ix = middle;
+ //starting to search forward, starting in the middle
+ while (true)
+ {
+ objDomain = ixDS->getObjectDomain(ix);
+ compResult = mint.get_high().compare_with(objDomain.get_origin());
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "position " << ix << " last " << last << " incrementor " << inc << " object domain " << objDomain << " compare " << compResult);
+ // object intersects region
+ if (objDomain.intersects_with(mint))
+ {
+ intersectedRegion = objDomain;
+ intersectedRegion.intersection_with(mint);
+ area = area - intersectedRegion.cell_count();
+ newObj = ixDS->getObject(ix);
+ intersectedObjects.push_back(newObj);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "added one entry, intersected region " << intersectedRegion << " area left " << area);
+ }
+ if (inc != -1 && (ix == last || compResult < 0))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "starting again at middle, but going backwards");
+ ix = middle;
+ inc = -1;
+ }
+ if (ix == first && inc == -1)//not needed:||first == last
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "breaking loop, arrived at start");
+ retval = ix;
+ break;
+ }
+ if (area <= 0)// || first == last || ix == first)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "breaking loop, area is found");
+ retval = ix;
+ break;
+ }
+ ix += inc;
+ }
+ }
+ }
+ }
+
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryRegionSearch(" << mint << ", " << area << ", vector, " << first << ", " << last << ") " << retval);
+ return retval;
+ }
+
+
+int
+SDirIndexLogic::compare(const r_Minterval& mint1,
+ const r_Minterval& mint2,
+ OrderPoint o1,
+ OrderPoint o2)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "compare(" << mint1 << ", " << mint2 << ", " << (int)o1 << ", " << (int)o2 << ")");
+ r_Point point1,point2;
+ switch(o1)
+ {
+ case Highest:
+ point1 = mint1.get_high();
+ break;
+ case Lowest:
+ point1 = mint1.get_origin();
+ break;
+ case None:
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "compare(...) o1 is None");
+ break;
+ }
+ switch(o2)
+ {
+ case Highest:
+ point2 = mint2.get_high();
+ break;
+ case Lowest:
+ point2 = mint2.get_origin();
+ break;
+ case None:
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "compare(...) o2 is None");
+ break;
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "compare(" << mint1 << ", " << mint2 << ", " << (int)o1 << ", " << (int)o2 << ") " << point1.compare_with(point2));
+ return point1.compare_with(point2);
+ }
+
+void
+SDirIndexLogic::intersect(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& intersectedObjs, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersect(" << searchInter << ")");
+ r_Area area = 0;
+ int result = 0;
+ r_Minterval intersectArea(searchInter.dimension());
+ r_Minterval currDom(ixDS->getCoveredDomain());
+ // avoid exceptions from r_Minterval
+ if (!searchInter.intersects_with(currDom))
+ {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersect(" << searchInter << ") search interval does not intersect wit current domain " << currDom);
+ }
+ else {
+ // Optimization: no need to search the whole area.
+ // only the area which is intersected by the current domain.
+ intersectArea.intersection_of(searchInter, currDom);
+ area = intersectArea.cell_count();
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "Area = " << area);
+ result = binaryRegionSearch(ixDS, intersectArea, area, intersectedObjs, 0, (int) ixDS->getSize() - 1);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersect(" << searchInter << ") vectorsize: " << intersectedObjs.size());
+ }
+ }
+
+void
+SDirIndexLogic::intersectUnOpt(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& intersectedObjs)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersectUnOpt(" << searchInter << ")");
+ for(int i=0; i< ixDS->getSize(); i++)
+ {
+ r_Minterval objInterval = ixDS->getObjectDomain(i);
+ if (searchInter.intersects_with(objInterval))
+ {
+ KeyObject obj = ixDS->getObject(i);
+ intersectedObjs.push_back(obj);
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersectUnOpt(" << searchInter << ") vectorsize: " << intersectedObjs.size());
+ }
+
+void
+SDirIndexLogic::containPointQuery(const IndexDS* ixDS, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "containPointQuery(" << searchPoint << ")");
+ int ix = binaryPointSearch(ixDS, searchPoint, Lowest, 0, (int) ixDS->getSize() - 1);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "result from binaryPointSearch ix " << ix);
+
+ if (ix >= 0)
+ {
+ result = ixDS->getObject(ix);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "containPointQuery(" << searchPoint << ") " << result);
+ }
+ else {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "containPointQuery(" << searchPoint << ") nothing found ");
+ }
+ }
+
+void
+SDirIndexLogic::getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl)
+ {
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "getObjects()");
+ ixDS->getObjects(objs);
+ }
+
+bool
+SDirIndexLogic::removeObject(IndexDS* ixDS, const KeyObject& objToRemove, const StorageLayout& sl)
+ {
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "removeObject(" << objToRemove << ")");
+ return ixDS->removeObject(objToRemove);
+ }
+
diff --git a/indexmgr/sdirindexlogic.hh b/indexmgr/sdirindexlogic.hh
new file mode 100644
index 0000000..f94084c
--- /dev/null
+++ b/indexmgr/sdirindexlogic.hh
@@ -0,0 +1,169 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _DIRIX_HH_
+#define _DIRIX_HH_
+
+#include "reladminif/lists.h"
+class r_Point;
+class StorageLayout;
+
+/***********************
+ *
+ * INCLUDE: dirix.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: SDirIndexLogic
+ *
+ *
+ * COMMENTS:
+ *
+ ***********/
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+ The SDirIndexLogic class implements a Directory of Interval Objects Index.
+
+ Objects inserted in the index must be disjunctive, since optimizations
+ are made which assume nonoverlapping interval objects.
+
+ It can be used as index on tiles of MDD objects.
+ A directory index consists solely of the current domain and
+ a list of entries, one for each interval object (for instance, a tile).
+ Interval objects must not overlap, since {\tt SDirIndexLogic} optimizes access
+ based on the assumption that entries don't overlap. Entries are
+ sorted by the lower vertice.
+ Each entry contains the interval domain and a reference to the object
+ itself.
+
+ SDirIndexLogic implements the higher level index functionality and uses the
+ functionality of {\tt IndexDS} to do the operations.
+
+ This way, {\tt SDirIndexLogic} can be used for both persistent or
+ main memory indexes, tiles index or intermediate nodes of a multidimensional
+ index, etc, by defining appropriate {\tt IndexDS} classes. Examples are
+ {\tt TransDirIx} and {\tt DBHierIndex}, for transient and persistent
+ indexes, respectively.A
+
+ The logic classes are stack based for performance and memory reasons -> everything is static.
+*/
+
+class SDirIndexLogic
+ {
+ public:
+
+ static bool insertObject(IndexDS* theIx, const KeyObject& newObject, const StorageLayout& sl);
+ /*@Doc:
+ Inserts a new object in the index.
+ */
+
+ static bool removeObject(IndexDS* theIx, const KeyObject& tileToRemove, const StorageLayout& sl);
+ /*@Doc:
+ Removes the tile from the object.
+ */
+
+ static void intersect(const IndexDS* theIx, const r_Minterval& searchInter, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Search the index for a search region.
+ Determines all the tiles in the index which intersect a given
+ search interval (given by {\tt searchInter}).
+ The memory space allocated by this function for the contents
+ of the keyobjects in the returned vector (only) must be released
+ afterwards by the caller.
+ */
+
+ static void intersectUnOpt(const IndexDS* theIx, const r_Minterval& searchInter, KeyObjectVector& objs);
+ /*@Doc:
+ Search the index for a search region.
+ Old unoptimized version of intersect(). Just scans all the entries,
+ tests each one for intersection, returning all that intersect.
+ This method is actually used for removing of tiles (a tile can be stored in multiple nodes).
+ */
+
+ static void containPointQuery(const IndexDS* theIx, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl);
+ /*@Doc:
+ Passes a pointer to the searched item.
+ Memory is for the KeyObject is not to be released by the caller.
+ */
+
+ static void getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Returns all the tiles belonging to the object.
+ */
+
+ enum OrderPoint
+ {
+ Highest = 1,
+ Lowest = 2,
+ None = 0
+ };
+ /*@Doc:
+ */
+
+ static int compare( const r_Minterval& mint1,
+ const r_Minterval& mint2,
+ OrderPoint o1 = Lowest,
+ OrderPoint o2 = Lowest);
+ /*@Doc:
+ Compares two intervals based on two points from each one.
+ Returns : -1 if mint1.point(o1) < mint2.point(o2);
+ 0 iff mint1.point(o1) == mint2.point(o2) and
+ 1 iff mint1.point(o1) > mint2.point(o2); where
+ mint.point(o) is the lowest corner point of mint if o == Lowest,
+ mint.point(o) is the highest corner point of mint if o == Highest.
+ */
+
+ static int binarySearch( const IndexDS* theIx,
+ const r_Minterval& newDomain,
+ OrderPoint o,
+ int first,
+ int last);
+ /*@Doc:
+ Returns position of searched item or position before the one where
+ it should be inserted to keep the order of the list (-1 means it should be
+ inserted at the beginning of the list).
+ */
+
+ static int binaryPointSearch( const IndexDS* theIx,
+ const r_Point& pnt,
+ OrderPoint o,
+ int first,
+ int last);
+ /*@Doc:
+ Returns position of tile having the point, -1 if point not there.
+ */
+
+ static int binaryRegionSearch( const IndexDS* theIx,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ int first,
+ int last);
+ /*@Doc:
+ Assumes ordering according to the lowest corner of the tiles!!!
+ */
+
+ };
+
+#endif
diff --git a/indexmgr/srcindexlogic.cc b/indexmgr/srcindexlogic.cc
new file mode 100644
index 0000000..b2e6d4b
--- /dev/null
+++ b/indexmgr/srcindexlogic.cc
@@ -0,0 +1,288 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * MODULE: indexmgr
+ * CLASS: SRCIndexLogic
+ *
+ * COMMENTS:
+ *
+*/
+
+static const char rcsiddirix[] = "@(#)dirix, SRCIndexLogic: $Id: srcindexlogic.cc,v 1.8 2002/09/19 11:38:25 hoefner Exp $";
+
+#include <iostream>
+#include <math.h>
+#include "raslib/rmdebug.hh"
+#include "raslib/odmgtypes.hh"
+#include "indexmgr/srcindexlogic.hh"
+#include "keyobject.hh"
+#include "indexds.hh"
+#include "relindexif/dbrcindexds.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "relblobif/tileid.hh"
+#include "relblobif/blobtile.hh"
+#include "raslib/mitera.hh"
+
+unsigned int
+SRCIndexLogic::computeNumberOfTiles(const StorageLayout& sl, const r_Minterval& mddDomain)
+ {
+/*
+ cout << "mddDomain " << mddDomain << endl;
+ cout << "mddDomain extent " << mddDomain.get_extent() << endl;
+ cout << "tileConfig " << sl.getTileConfiguration() << endl;
+ cout << "tileConfig extent " << sl.getTileConfiguration().get_extent() << endl;
+ cout << "normalized " << temp << endl;
+ cout << "cell count " << temp.cell_count() << endl;
+*/
+ return computeNormalizedDomain(mddDomain.get_extent(), sl.getTileConfiguration().get_extent()).cell_count();
+ }
+
+r_Minterval
+SRCIndexLogic::computeNormalizedDomain(const r_Point& mddDomainExtent, const r_Point& tileConfigExtent)
+ {
+ r_Dimension theDim = mddDomainExtent.dimension();
+ r_Minterval normalizedDomain(theDim);
+ r_Range normalized = 0;
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ normalized = (r_Range)(mddDomainExtent[dim]/tileConfigExtent[dim]) - 1;
+ //cout << "mdd domain extent [" << dim << "] " << mddDomainExtent[dim] << endl;
+ //cout << "tile config extent [" << dim << "] " << tileConfigExtent[dim] << endl;
+ //cout << "division " << mddDomainExtent[dim]/tileConfigExtent[dim] << endl;
+ //cout << "normalized " << normalized << endl;
+ //remove this if we support rc index with border tiles
+ if ((normalized + 1)* tileConfigExtent[dim] != mddDomainExtent[dim])
+ {
+ //cout << "got you" << endl;
+ RMInit::logOut << "SRCIndexLogic::computeNormalizedDomain() the mdd domain does not fit the tile configuration" << endl;
+ throw r_Error(TILECONFIGMARRAYINCOMPATIBLE);
+ }
+ normalizedDomain[dim] = r_Sinterval(0, normalized);
+ }
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeNormalizedDomain(" << mddDomainExtent << ", " << tileConfigExtent << ") " << normalizedDomain);
+ return normalizedDomain;
+ }
+
+r_Point
+SRCIndexLogic::computeNormalizedPoint(const r_Point& toNormalize, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin)
+ {
+ r_Dimension theDim = mddDomainOrigin.dimension();
+ r_Point normalizedPoint(theDim);
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ normalizedPoint[dim] = (r_Range)((toNormalize[dim] - mddDomainOrigin[dim])/tileConfigExtent[dim]);
+ }
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeNormalizedPoint(" << toNormalize << ", " << tileConfigExtent << ", " << mddDomainOrigin << ") " << normalizedPoint);
+ return normalizedPoint;
+ }
+
+r_Minterval
+SRCIndexLogic::computeDomain(const r_Point& toConvert, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin)
+ {
+ r_Dimension theDim = mddDomainOrigin.dimension();
+ r_Minterval result(theDim);
+ r_Range high = 0;
+ r_Range low = 0;
+ r_Range offset = 0;
+ r_Range toConvTemp = 0;
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ toConvTemp = toConvert[dim];
+ offset = fmod((r_Double)(toConvTemp - mddDomainOrigin[dim]), tileConfigExtent[dim]);
+ low = toConvTemp - offset;
+ //there has to be a check if we support border tiles.
+ high = toConvTemp - offset + tileConfigExtent[dim];
+ result[dim] = r_Sinterval(low, high);
+ }
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeDomain(" << toConvert << ", " << tileConfigExtent << ", " << mddDomainOrigin << ") " << result);
+ return result;
+ }
+
+OId
+SRCIndexLogic::computeOId(const r_Minterval& mddDomain, const r_Point& tileConfigExtent, OId::OIdCounter baseCounter, OId::OIdType type, const r_Point& tileOrigin)
+ {
+ OId::OIdCounter counter;
+ counter = computeNormalizedDomain(mddDomain.get_extent(), tileConfigExtent).cell_offset(computeNormalizedPoint(tileOrigin, tileConfigExtent, mddDomain.get_origin())) + baseCounter;
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeOId(" << mddDomain << ", " << tileConfigExtent << ", " << baseCounter << ", " << tileOrigin << ") " << OId(counter, type));
+ return OId(counter, type);
+ }
+
+bool
+SRCIndexLogic::insertObject(IndexDS* ixDS, const KeyObject& newKeyObject, const StorageLayout& sl)
+ {
+ //this method should check if the tile is actually in the tiling
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRCIndexLogic", "insertObject(" << newKeyObject << ")");
+
+ RMInit::logOut << "SRCIndexLogic::insertObject(" << ixDS->getIdentifier() << ", " << newKeyObject << ", sl) insert operation not allowed" << endl;
+ throw r_Error(INSERTINTORCINDEX);
+ //if src is able to extend:
+ r_Minterval newKeyObjectDomain = newKeyObject.getDomain();
+ r_Minterval tileConfig = sl.getTileConfiguration();
+ r_Minterval mddDomain = ixDS->getCoveredDomain();
+ OId newBlobOId(computeOId(mddDomain, tileConfig.get_extent(), ((DBRCIndexDS*)ixDS)->getBaseCounter(), ((DBRCIndexDS*)ixDS)->getBaseOIdType(), newKeyObjectDomain.get_origin()));
+ DBTileId tile = newKeyObject.getObject();
+ BLOBTile* t = new BLOBTile(tile->getSize(), tile->getCells(), tile->getDataFormat(), newBlobOId);
+ // is done in the constructor
+ //t->setPersistent(true);
+ tile->setPersistent(false);
+
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRCIndexLogic", "insertObject(" << newKeyObject << ")");
+ //should check if insertion was succesfull
+ return true;
+ }
+
+/*
+r_Minterval
+SRCIndexLogic::computeDomain(const r_Point& toConvert, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin)
+ {
+ r_Dimension theDim = mddDomainOrigin.dimension();
+ r_Minterval result(theDim);
+ r_Range high = 0;
+ r_Range low = 0;
+ r_Range offset = 0;
+ r_Range toConvTemp = 0;
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ toConvTemp = toConvert[dim];
+ offset = fmod((toConvTemp - mddDomainOrigin[dim]), tileConfigExtent[dim]);
+ low = toConvTemp - offset;
+ high = toConvTemp - offset + tileConfigExtent[dim];
+ result[dim] = r_Sinterval(low, high);
+ }
+ return result;
+ }
+*/
+
+r_Minterval
+SRCIndexLogic::computeTiledDomain(const r_Minterval& completeDomain, const r_Point& tileConfigExtent, const r_Minterval& widenMe)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeTiledDomain(" << completeDomain << ", " << tileConfigExtent << ", " << widenMe << ")");
+ r_Minterval searchDomain(completeDomain.create_intersection(widenMe));
+ r_Dimension theDim = searchDomain.dimension();
+ r_Minterval retval(theDim);
+ r_Range high = 0;
+ r_Range low = 0;
+ r_Range offsetlow = 0;
+ r_Range offsethigh = 0;
+ r_Range mddOrigin = 0;
+ r_Range tileExtent = 0;
+ r_Sinterval currSi;
+ r_Point mddDomainOrigin = completeDomain.get_origin();
+ RMDBGMIDDLE(5, RMDebug::module_indexmgr, "SRCIndexLogic", "search domain " << searchDomain << " mdd origin " << mddDomainOrigin)
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {// make retval fit the tiling layout
+ currSi = searchDomain[dim];
+ low = currSi.low();
+ high = currSi.high();
+ mddOrigin = mddDomainOrigin[dim];
+ tileExtent = tileConfigExtent[dim];
+ offsetlow = (low - mddOrigin)%tileExtent;
+ offsethigh = (high - mddOrigin)%tileExtent;
+ //this has to be revised if we support border tiles
+ retval[dim] = r_Sinterval(low - offsetlow, high - offsethigh + tileExtent - 1);
+ RMDBGMIDDLE(6, RMDebug::module_indexmgr, "SRCIndexLogic", "mdd interval " << currSi << " offset low " << offsetlow << " offset high " << offsethigh << " tile extent " << tileExtent)
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeTiledDomain(" << completeDomain << ", " << tileConfigExtent << ", " << widenMe << ") " << retval);
+ return retval;
+ }
+
+void
+SRCIndexLogic::intersect(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& intersectedObjs, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRCIndexLogic", "intersect(" << searchInter << ")");
+ r_Minterval mddDomain = ixDS->getCoveredDomain();
+ if (searchInter.intersects_with(mddDomain))
+ {
+ r_Minterval tileConfig = sl.getTileConfiguration();
+ r_Point tileConfigExtent = tileConfig.get_extent();
+ OId::OIdCounter baseCounter = ((DBRCIndexDS*)ixDS)->getBaseCounter();
+ OId::OIdType type = ((DBRCIndexDS*)ixDS)->getBaseOIdType();
+ r_Dimension dim = mddDomain.dimension();
+ r_Point searchPoint(dim);
+ r_Minterval searchDomain = computeTiledDomain(mddDomain, tileConfigExtent, searchInter);
+ r_MiterArea iter(&tileConfig, &searchDomain);
+ r_Minterval iterArea(dim);
+
+ while (!iter.isDone())
+ {//iterate through the partitions in the search domain
+ iterArea = iter.nextArea();
+ r_Point orig = iterArea.get_origin();
+ OId t = computeOId(mddDomain, tileConfigExtent, baseCounter, type, orig);
+ DBObjectId theObject(t);
+ //the domain of the object has to be adapted to the border tiles
+ if (!theObject.is_null())
+ {
+ theObject->setCached(true);
+ }
+ else {
+ theObject = new BLOBTile(t, sl.getTileSize(), sl.getDataFormat(orig));
+ theObject->setCached(true);
+ }
+ intersectedObjs.push_back(KeyObject(theObject, iterArea));
+ }
+ }
+ }
+
+void
+SRCIndexLogic::containPointQuery(const IndexDS* ixDS, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRCIndexLogic", "containPointQuery(" << searchPoint << ")");
+ r_Minterval mddDomain = ixDS->getCoveredDomain();
+ if (mddDomain.covers(searchPoint))
+ {
+ r_Minterval tileConfig = sl.getTileConfiguration();
+ r_Point tileConfigExtent = tileConfig.get_extent();
+ OId t = computeOId(mddDomain, tileConfigExtent, ((DBRCIndexDS*)ixDS)->getBaseCounter(), ((DBRCIndexDS*)ixDS)->getBaseOIdType(), searchPoint);
+ DBObjectId theObject(t);
+ if (!theObject.is_null())
+ {
+ theObject->setCached(true);
+ }
+ else {
+ theObject = new BLOBTile(t, sl.getTileSize(), sl.getDataFormat(searchPoint));
+ }
+ result.setDomain(computeDomain(searchPoint, tileConfigExtent, mddDomain.get_origin()));
+ result.setObject(theObject.getOId());
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRCIndexLogic", "containPointQuery(" << searchPoint << ") " << result);
+ }
+
+void
+SRCIndexLogic::getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl)
+ {
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "getObjects()");
+ intersect(ixDS, ixDS->getCoveredDomain(), objs, sl);
+ }
+
+bool
+SRCIndexLogic::removeObject(IndexDS* ixDS, const KeyObject& objToRemove, const StorageLayout& sl)
+ {
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "removeObject(" << objToRemove << ")");
+ return true;
+ }
+
diff --git a/indexmgr/srcindexlogic.hh b/indexmgr/srcindexlogic.hh
new file mode 100644
index 0000000..92b0869
--- /dev/null
+++ b/indexmgr/srcindexlogic.hh
@@ -0,0 +1,132 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * MODULE: indexmgr
+ * CLASS: SRCIndexLogic
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _SRCINDEXLOGIC_HH_
+#define _SRCINDEXLOGIC_HH_
+
+#include "reladminif/lists.h"
+#include "raslib/minterval.hh"
+#include "reladminif/oidif.hh"
+
+class r_Point;
+class StorageLayout;
+class SRCIndexLogic;
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+The regular computed index uses DBRCIndexDS and StorageLayout to store its persistent data.
+The point is:
+ The tiles all have the same layout.
+ The domain of the mdd is fixed.
+With those preliminaries it is possible to speed up the index considerably.
+DBRCIndexDS stores the domain of the mdd object, the first OIdCounter and the OIdType of the entries.
+The storage layout stores the tile configuration.
+
+An algorithm computes the oid of a tile using the complete domain and the tile configuration.
+
+The number of allocated oids has to be stored in the DBRCIndexDS because the DBRCIndexDS has to delete
+all tiles belonging to it without information on the tile configuration (an hence cannot compute its
+size).
+
+*/
+
+class SRCIndexLogic
+ {
+ public:
+
+ static unsigned int computeNumberOfTiles(const StorageLayout& sl, const r_Minterval& mddDomain);
+ /*@Doc:
+ Compute the number of tiles that will have to be allocated by the index. This is based on the tile config from storagelayout and the domain covered by the mdd.
+ */
+
+ static bool insertObject(IndexDS* theIx, const KeyObject& newObject, const StorageLayout& sl);
+ /*@Doc:
+ Inserts a new object in the index. Creates a new tile which has the oid that belongs to that domain. The original tile is deleted from database.
+ */
+
+ static bool removeObject(IndexDS* theIx, const KeyObject& tileToRemove, const StorageLayout& sl);
+ /*@Doc:
+ Removes the tile from the object.
+ */
+
+ static void intersect(const IndexDS* theIx, const r_Minterval& searchInter, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Search the index for a search region.
+ Determines all the tiles in the index which intersect a given
+ search interval (given by {\tt searchInter}).
+ The memory space allocated by this function for the contents
+ of the keyobjects in the returned vector (only) must be released
+ afterwards by the caller.
+ */
+
+ static void containPointQuery(const IndexDS* theIx, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl);
+ /*@Doc:
+ Passes a pointer to the searched item.
+ Memory is for the KeyObject is not to be released by the caller.
+ */
+
+ static void getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Returns all the tiles belonging to the object.
+ */
+
+ protected:
+
+ static r_Minterval computeNormalizedDomain(const r_Point& mddDomainExtent, const r_Point& tileConfigExtent);
+ /*@Doc:
+ compute the normalized matrix from the extent of the domain and the extent of the tile config.
+ */
+
+ static r_Point computeNormalizedPoint(const r_Point& toNormalize, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin);
+ /*@Doc:
+ compute the normalized point from the point, the extent of the tile config and the origin of the mdd domain.
+ this point is then used to calculate the number of the tile in the normailzed matrix.
+ */
+
+ static r_Minterval computeDomain(const r_Point& toConvert, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin);
+ /*@Doc:
+ compute the tile domain based on the point inside that domain, the tile config extent and the origin of the mdd.
+ */
+
+ static OId computeOId(const r_Minterval& mddDomain, const r_Point& tileConfigExtent, OId::OIdCounter baseCounter, OId::OIdType type, const r_Point& tileOrigin);
+ /*@Doc:
+ compute the oid of an entry based on the domain of the mdd, the extent of the tile config, the starting oid adress, the type of oid and the origin of the tile domain.
+ */
+
+ static r_Minterval computeTiledDomain(const r_Minterval& completeDomain, const r_Point& tileConfigExtent, const r_Minterval& widenMe);
+ /*@Doc:
+ compute the completely tiled domain, which is the intersection of the complete domain and the domain to be tiled (widenMe), based on the tile config.
+ Example: user requests tiles in domain [3:5]. the tile config is [1], the complete domain is [2:7]. the result will be [2:5] because [3:3] belongs to the tile [2:3].
+ */
+
+ };
+
+#endif
diff --git a/indexmgr/srptindexlogic.cc b/indexmgr/srptindexlogic.cc
new file mode 100644
index 0000000..8ddc26b
--- /dev/null
+++ b/indexmgr/srptindexlogic.cc
@@ -0,0 +1,1147 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "indexmgr/srptindexlogic.hh"
+#include "raslib/rmdebug.hh"
+#include "tilemgr/tile.hh"
+#include "raslib/point.hh"
+#include "indexmgr/sdirindexlogic.hh"
+#include <math.h>
+#include "indexmgr/keyobject.hh"
+#include "relindexif/hierindex.hh"
+#include "reladminif/dbref.hh"
+#include "relindexif/indexid.hh"
+
+const float ff = 0.5;
+
+//removes all entries from a index and inserts them into a vector
+void
+clear(KeyObjectVector& keyvec, HierIndexDS* node)
+ {
+ RMDBGENTER(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "clear(keyvec, " << OId(node->getIdentifier()) << ")");
+ unsigned int i = 0;
+ unsigned int nodeSize = node->getSize();
+
+ keyvec.reserve(nodeSize);
+ while (!keyvec.empty())
+ {
+ keyvec.erase(keyvec.begin());
+ }
+ for(i = 0; i < nodeSize; i++)
+ {
+ keyvec.push_back(node->getObject(0));
+ node->removeObject((unsigned int)0);
+ }
+ RMDBGEXIT(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "clear(keyvec, " << OId(node->getIdentifier()) << ")");
+ }
+
+/*this may be usefull when getting rid of the extendFaces method
+unsigned int
+findNearestNode(IndexDS* whereToLook, const r_Minterval& theEntryDomain)
+ {
+ r_Minterval sum(theEntryDomain.dimension());
+//this code is not used -> no pror
+ r_Area smallestArea = (r_Area)0xFFFFFFFF;
+ unsigned int smallestAreaAt = 0;
+ unsigned long currentArea = 0;
+ unsigned int i = 0;
+ unsigned int numElems = whereToLook->getSize();
+
+ for (i = 0; i < numElems; i++)
+ {
+ currentArea = sum.closure_of(whereToLook->getObjectDomain(i), theEntryDomain).cell_count();
+ if (currentArea <= smallestArea)
+ {
+ smallestArea = currentArea;
+ smallestAreaAt = i;
+ }
+ }
+ return smallestAreaAt;
+ }
+*/
+
+bool
+SRPTIndexLogic::insertObject2(IndexDS* ixDS, const KeyObject& newKeyObject, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "insertObject2(" << OId(ixDS->getIdentifier()) << ", " << newKeyObject << ")")
+ IndexPVector leafNodes2Split;
+ r_Minterval newKeyObjectDom;
+ r_Minterval cd;
+ bool extend = false;
+ bool* facesToExtendLo = NULL;
+ bool* facesToExtendHi = NULL;
+ r_Dimension i = 0;
+ r_Dimension dim = 0;
+ unsigned int overflowed = 0;
+
+ if (ixDS->getSize() == 0)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "Index is empty. only set domain");
+ ixDS->setAssignedDomain(newKeyObject.getDomain());
+ }
+ else {
+ // initialize facesToExtend
+ newKeyObjectDom = newKeyObject.getDomain();
+ cd = ixDS->getCoveredDomain();
+ dim = cd.dimension();
+ extend = false;
+ facesToExtendLo = new bool[dim];
+ facesToExtendHi = new bool[dim];
+ for(i = 0; i < dim; i++)
+ {
+ if (newKeyObjectDom[i].low() < cd[i].low())
+ {
+ facesToExtendLo[i] = true;
+ extend = true;
+ }
+ else
+ facesToExtendLo[i] = false;
+
+ if (newKeyObjectDom[i].high() > cd[i].high())
+ {
+ facesToExtendHi[i] = true;
+ extend = true;
+ }
+ else
+ facesToExtendHi[i] = false;
+ }
+
+ // Implementation note:
+ // the extension of faces could be integrated with the insertObject()
+ // function and result in a more efficient but more complex implementation
+ // (a nonrecursive extendFaces() woul be needed and insertObject()
+ // changed to have additional parameters oldCurrDom, facesToExtendLo,
+ // facesToExtendHi).
+ // The simple solution was chosen, where the whole tree is first updated
+ // for the new borders and then the insertion is made.
+ // Another solution would be the implementation of the external borders as
+ // infinite. Each node would have to have both a current domain and a domain.
+
+ if (extend)
+ {
+ SRPTIndexLogic::extendFaces((HierIndexDS*)ixDS, newKeyObjectDom, cd, facesToExtendLo, facesToExtendHi);
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "no need to extend faces");
+ }
+ delete[] facesToExtendLo;
+ facesToExtendLo = NULL;
+ delete[] facesToExtendHi;
+ facesToExtendHi = NULL;
+ }
+
+ // call recursive insertObject()
+ overflowed = SRPTIndexLogic::insertObject(newKeyObject, (HierIndexDS*)ixDS, leafNodes2Split, sl);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "number of leaf overflows " << leafNodes2Split.size())
+
+ if (!leafNodes2Split.empty())
+ SRPTIndexLogic::splitNodes((HierIndexDS*)ixDS, leafNodes2Split, sl);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "insertObject2(" << OId(ixDS->getIdentifier()) << ", " << newKeyObject << ")")
+ //there should be a check here : )
+ return true;
+ }
+
+void
+SRPTIndexLogic::intersect2(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& intersectedObjs, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect2(" << OId(ixDS->getIdentifier()) << ", " << searchInter << ")")
+ r_Minterval dom = ixDS->getCoveredDomain();
+ r_Area area = 0;
+
+ // avoid exceptions from r_Minterval
+ if (searchInter.intersects_with(dom))
+ {
+ //this is neccessary because intersectNoDuplicats would think there were other index nodes that cover this area.
+ r_Minterval searchDom = searchInter.create_intersection(dom);
+ //needed this parent domain, or else indexes with one level only don't work
+ area = searchDom.cell_count();
+ SRPTIndexLogic::intersect(searchDom, dom, intersectedObjs, (const HierIndexDS*)ixDS, area);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect2(" << OId(ixDS->getIdentifier()) << "*, " << searchInter << ") found #" << intersectedObjs.size() << " matches");
+ }
+ else {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect2(" << OId(ixDS->getIdentifier()) << "* dom " << dom << ", " << searchInter << ") don't intersect");
+ }
+ }
+
+void
+SRPTIndexLogic::containPointQuery2(const IndexDS* ixDS, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl)
+ {
+ SRPTIndexLogic::containPointQuery(searchPoint, (const HierIndexDS*)ixDS, result, sl);
+ }
+
+void
+SRPTIndexLogic::getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl)
+ {
+ // can be optimized !!!
+ intersect2((const HierIndexDS*)ixDS, ixDS->getCoveredDomain(), objs, sl);
+ }
+
+int
+SRPTIndexLogic::insertObject( const KeyObject& newKeyObject,
+ HierIndexDS* ix,
+ IndexPVector& leafNodes2Split,
+ const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "insertObject(" << newKeyObject << ", " << OId(ix->getIdentifier()) << ", leafNodes2Split.size " << leafNodes2Split.size() << ")")
+ int overflowed = 0;
+
+ if (ix->isLeaf())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "ix is Leaf")
+ //this is new
+ r_Minterval oldDom = ix->getCoveredDomain();
+ SDirIndexLogic::insertObject(ix, newKeyObject, sl);
+ ix->setAssignedDomain(oldDom);
+ // no node overflow, simply insert newEntry
+ if (ix->isOverFull())
+ {// node overflow: add node to list of nodes to split
+ overflowed = 1;
+ leafNodes2Split.push_back(ix);
+ }
+ else {
+ if (!ix->isRoot())
+ {
+ ix->destroy();
+ }
+ }
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "ix is Node")
+ KeyObjectVector intersectedNodes;
+ KeyObjectVector::iterator nodeIt;
+ SDirIndexLogic::intersect(ix, newKeyObject.getDomain(), intersectedNodes, sl);
+ while (!intersectedNodes.empty())
+ {
+ overflowed = overflowed + insertObject(newKeyObject, DBHierIndexId((*(intersectedNodes.begin())).getObject()).ptr(), leafNodes2Split, sl);
+ intersectedNodes.erase(intersectedNodes.begin());
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "insertObject(" << newKeyObject << ", ix, leafNodes2Split.size " << leafNodes2Split.size() << ") " << overflowed)
+ return overflowed;
+ }
+
+
+void
+SRPTIndexLogic::extendFaces( HierIndexDS* ix,
+ const r_Minterval& newKeyObjectDom,
+ const r_Minterval& oldCurrDom,
+ const bool* facesToExtendLo,
+ const bool* facesToExtendHi)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "extendFaces(" << OId(ix->getIdentifier()) << ", " << newKeyObjectDom << ", " << oldCurrDom << ", facesToExtendLo, facesToExtendHi)");
+ bool extendEntries = false;
+ unsigned int numberElems = 0;
+ r_Dimension dim = 0;
+ r_Dimension i = 0;
+ r_Dimension d = 0;
+ r_Minterval entryDom;
+ bool follow = false;
+ r_Minterval ixDom = oldCurrDom;//ix->getCoveredDomain();
+
+ if (ix->isLeaf())
+ {
+ if (!(ix->isRoot())) // nothing to do!!!
+ {//this entry's domain was set in the previous call of extendFaces
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", OId(ix->getIdentifier()) << " is Leaf and not Root - already updated");
+ ix->destroy();
+ ix = 0;
+ }
+ else {// ix is both leaf and root, one node only!! must update domain
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", OId(ix->getIdentifier()) << " is Leaf and Root - update domain");
+ ixDom.closure_with(newKeyObjectDom);
+ ix->setAssignedDomain(ixDom);
+ }
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", OId(ix->getIdentifier()) << " is Node");
+ dim = newKeyObjectDom.dimension();
+ for (i = 0; i < dim; i++)
+ {
+ if (facesToExtendLo[i] && (ixDom[i].low() == oldCurrDom[i].low()))
+ {
+ ixDom[i].set_low(newKeyObjectDom[i].low());
+ extendEntries = true;
+ }
+ if (facesToExtendHi[i] && (ixDom[i].high() == oldCurrDom[i].high()))
+ {
+ ixDom[i].set_high(newKeyObjectDom[i].high());
+ extendEntries = true;
+ }
+ }
+ if (extendEntries)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "must extend entries");
+ numberElems = ix->getSize();
+ for (i = 0; i < numberElems; i++)
+ {
+ follow = false;
+ entryDom = ix->getObjectDomain(i);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry #" << i << " has domain " << entryDom);
+ for(d = 0; d < dim; d++)
+ {
+ if (facesToExtendLo[d] && (entryDom[d].low() == oldCurrDom[d].low()))
+ {
+ entryDom[d].set_low(newKeyObjectDom[d].low());
+ follow = true;
+ }
+ if (facesToExtendHi[d] && (entryDom[d].high() == oldCurrDom[d].high()))
+ {
+ entryDom[d].set_high(newKeyObjectDom[d].high());
+ follow = true;
+ }
+ }
+ if (follow)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry #" << i << " must be extended to " << entryDom);
+ HierIndexDS* child = convert(ix->getObject(i));
+ extendFaces(child, newKeyObjectDom, oldCurrDom, facesToExtendLo, facesToExtendHi);
+ ix->setObjectDomain(entryDom, i);
+ }
+ }
+ }
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "new Domain of " << OId(ix->getIdentifier()) << " is " << ix->getCoveredDomain());
+ if (!ix->isRoot())
+ {
+ ix->destroy();
+ ix =0;
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "extendFaces(ixMayBeNull, " << newKeyObjectDom << ", " << oldCurrDom << ", facesToExtendLo, facesToExtendHi)");
+ }
+
+
+
+void
+SRPTIndexLogic::splitNodes(HierIndexDS* ixDS, IndexPVector& leafNodes2Split, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitNodes(" << OId(ixDS->getIdentifier()) << ", leafNodes2Split)")
+ HierIndexDS* parentIxDS = NULL;
+ HierIndexDS* leafNodeIxDS = NULL;
+ HierIndexDS* n1 = NULL;
+ HierIndexDS* n2 = NULL;
+ HierIndexDS* nln1 = NULL; // non leaf nodes
+ HierIndexDS* nln2 = NULL; // non leaf nodes
+ HierIndexDS* tempPar = NULL;
+ r_Dimension axis = 0;
+ r_Range value = 0;
+ int parentOverflowed = 0;
+ KeyObjectVector keyvec;
+ KeyObject nodekey1;
+ KeyObject nodekey2;
+ r_Minterval domain;
+ bool wasroot = false;
+ bool found = false;
+ r_Dimension dim = ixDS->getDimension();
+ unsigned int numElem = 0;
+ unsigned int cur = 0;
+
+ while (!leafNodes2Split.empty())
+ {
+ leafNodeIxDS = (HierIndexDS*)leafNodes2Split[0];
+ leafNodes2Split.erase(leafNodes2Split.begin());
+
+ wasroot = leafNodeIxDS->isRoot();
+ if (wasroot)
+ domain = leafNodeIxDS->getCoveredDomain();
+ else {
+ tempPar = leafNodeIxDS->getParent();
+ KeyObject tkey;
+ numElem = tempPar->getSize();
+ for (cur = 0; cur < numElem; cur++)
+ {
+ tkey = tempPar->getObject(cur);
+ if (((OId::OIdPrimitive)tkey.getObject().getOId()) == leafNodeIxDS->getIdentifier())
+ {
+ domain = tkey.getDomain();
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ RMInit::logOut << "SRPTIndexLogic::splitNodes() the leaf node to split was not found in its parent" << endl;
+ throw r_Error(INDEXNOTFOUNDINPARENT);
+ }
+ tempPar->destroy();
+ tempPar = NULL;
+ }
+
+ calculatePartition(axis, value, leafNodeIxDS);
+ clear(keyvec, leafNodeIxDS);
+ n1 = (HierIndexDS*)leafNodeIxDS->getNewInstance();
+ if (wasroot)
+ {
+ parentIxDS = leafNodeIxDS;
+ n2 = (HierIndexDS*)leafNodeIxDS->getNewInstance();
+ leafNodeIxDS->setIsNode(true);
+ leafNodeIxDS = NULL;
+ }
+ else {
+ parentIxDS = leafNodeIxDS->getParent();
+ n2 = leafNodeIxDS;
+ leafNodeIxDS = NULL;
+ }
+ splitLeaf(n1, n2, keyvec, axis, value, domain, sl);
+ nodekey1 = convert(n1);
+ nodekey2 = convert(n2);
+ if (!wasroot)
+ parentIxDS->removeObject(nodekey2);
+ SDirIndexLogic::insertObject(parentIxDS, nodekey1, sl);
+ SDirIndexLogic::insertObject(parentIxDS, nodekey2, sl);
+ parentOverflowed = parentIxDS->isOverFull();
+
+ n1->destroy();
+ n1 = NULL;
+ n2->destroy();
+ n2 = NULL;
+
+ while (parentOverflowed) // split up
+ {
+ wasroot = parentIxDS->isRoot();
+ domain = parentIxDS->getAssignedDomain();
+ calculatePartition(axis, value, parentIxDS);
+ clear(keyvec, parentIxDS);
+ nln1 = (HierIndexDS*)parentIxDS->getNewInstance();
+
+ if (wasroot)
+ {
+ nln2 = (HierIndexDS*)parentIxDS->getNewInstance();
+ }
+ else {
+ nln2 = parentIxDS;
+ parentIxDS = parentIxDS->getParent();
+ }
+ splitNonLeaf(nln1, nln2, keyvec, leafNodes2Split, axis, value, domain, sl);
+ nodekey1 = convert(nln1);
+ nodekey2 = convert(nln2);
+ if (!wasroot)
+ parentIxDS->removeObject(nodekey2);
+ SDirIndexLogic::insertObject(parentIxDS, nodekey1, sl);
+ SDirIndexLogic::insertObject(parentIxDS, nodekey2, sl);
+ parentOverflowed = parentIxDS->isOverFull();
+
+ nln1->destroy();
+ nln1 = NULL;
+ nln2->destroy();
+ nln2 = NULL;
+ }
+ if (parentIxDS && (parentIxDS != ixDS))
+ {
+ parentIxDS->destroy();
+ parentIxDS = NULL;
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitNodes(" << OId(ixDS->getIdentifier()) << ", leafNodes2Split)")
+ }
+
+void
+SRPTIndexLogic::splitLeaf( HierIndexDS* pd1,
+ HierIndexDS* pd2,
+ KeyObjectVector& keyvec,
+ r_Dimension axis,
+ r_Range value,
+ r_Minterval& domain,
+ const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitLeaf(" << OId(pd1->getIdentifier()) << ", " << OId(pd2->getIdentifier()) << ", keyvec, " << axis << ", " << value << ", " << domain << ")")
+ unsigned int i = 0;
+ unsigned int leafSize = keyvec.size();
+
+ r_Minterval cd(domain);
+ r_Minterval nd1 = cd;
+ r_Minterval nd2 = cd;
+
+ KeyObject obj;
+
+ nd1[axis].set_high(value - 1);
+ nd2[axis].set_low(value);
+ RMDBGMIDDLE(6, RMDebug::module_indexmgr, "SRPTIndexLogic", "old leaf domain " << cd << " partition 1 " << nd1 << " partition 2 " << nd2);
+ //populate two nodes
+ for(i = 0; i < leafSize; i++)
+ {
+ cd = keyvec[i].getDomain();
+ RMDBGMIDDLE(5, RMDebug::module_indexmgr, "SRPTIndexLogic", "ObjectDomain of Object #" << i << " is " << cd);
+ obj = keyvec[i];
+ if (nd1.intersects_with(cd))
+ {
+ SDirIndexLogic::insertObject(pd1, obj, sl);
+ }
+ if (nd2.intersects_with(cd))
+ {
+ SDirIndexLogic::insertObject(pd2, obj, sl);
+ }
+//sanity check
+RMDBGIF(0, RMDebug::module_indexmgr, "SRPTIndexLogic", \
+ if (!nd1.intersects_with(cd) && !nd2.intersects_with(cd)) \
+ { \
+ RMInit::logOut << "SRPTIndexLogic::splitLeaf() the entry does not intersect with any node: node 1 " << nd1 << " node 2 " << nd2 << " entry " << cd << endl; \
+ throw r_Error(TILE_NOT_INSERTED_INTO_INDEX); \
+ } )
+ }
+ pd1->setAssignedDomain(nd1);
+ pd2->setAssignedDomain(nd2);
+
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitLeaf(" << OId(pd1->getIdentifier()) << ", " << OId(pd2->getIdentifier()) << ", keyvec, " << axis << ", " << value << ", " << domain << ")")
+ }
+
+void
+SRPTIndexLogic::splitNonLeaf( HierIndexDS* pd1,
+ HierIndexDS* pd2,
+ KeyObjectVector& keyvec,
+ IndexPVector& leafNodes2Split,
+ r_Dimension axis,
+ r_Range value,
+ const r_Minterval& domain,
+ const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitNonLeaf(" << OId(pd1->getIdentifier()) << ", " << OId(pd2->getIdentifier()) << ", keyvec, leafNodes2Split, " << axis << ", " << value << ", " << domain << ")");
+ r_Dimension dim = domain.dimension();
+ r_Minterval cd(domain);
+ r_Minterval nd1(cd);
+ r_Minterval nd2(cd);
+ r_Minterval leafDomain(dim);
+ r_Minterval nodeDomain(dim);
+ KeyObjectVector listMinKO1;
+ KeyObjectVector listMinKO2;
+ KeyObjectVector keyvec2;
+ IndexPVector newLeafsToSplit;
+ HierIndexDS* entry = NULL;
+ HierIndexDS* n11 = NULL;
+ HierIndexDS* parentIxDS = NULL;
+ KeyObject tempKey;
+ KeyObject k11;
+ KeyObject k22;
+ unsigned int i = 0;
+ unsigned int a = 0;
+ unsigned int nodeSize = keyvec.size();
+ unsigned int leafSize = 0;
+
+ nd1[axis].set_high(value - 1);
+ nd2[axis].set_low(value);
+
+ //repopulate node and pd1
+ for(i = 0; i < nodeSize; i++)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "repopulating node (entry " << i << " of " << nodeSize << ")");
+ tempKey = keyvec[i];
+ entry = convert(tempKey);
+ // entry's domain
+ cd = keyvec[i].getDomain();
+ if (nd1.covers(cd))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry #" << i << " " << cd << " covers node 1 " << nd1);
+ // updates parent automatically
+ SDirIndexLogic::insertObject(pd1, tempKey, sl);
+ entry->destroy();
+ entry = 0;
+ }
+ else {
+ if (nd2.covers(cd))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry #" << i << " " << cd << " covers node 2 " << nd2);
+ // updates parent automatically
+ SDirIndexLogic::insertObject(pd2, tempKey, sl);
+ entry->destroy();
+ entry = NULL;
+ }
+ else {// intersects both -> split down
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry #" << i << " " << cd << " intersects both " << nd1 << " " << nd2);
+ n11 = NULL;
+ //k11 is not a pointer! it is an object
+ // k11 = 0;
+ if (entry->isLeaf())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry is leaf ")
+ n11 = (HierIndexDS*)entry->getNewInstance();
+ n11->setIsNode(false);
+ leafDomain = cd;
+ clear(keyvec2, entry);
+ splitLeaf(n11, entry, keyvec2, axis, value, leafDomain, sl);
+ //if this was one of the leaf nodes to split, remove it from the list
+ leafSize = leafNodes2Split.size();
+ newLeafsToSplit = vector< IndexDS* >();
+ for (a = 0; a < leafSize; a++)
+ {
+ if (leafNodes2Split[a]->isSameAs(entry))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "will not add entry " << a << " to leafNodes2Split.size " << leafSize)
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "will add entry " << a << " to leafNodes2Split.size " << leafSize)
+ newLeafsToSplit.push_back(leafNodes2Split[a]);
+ }
+ }
+ leafNodes2Split = newLeafsToSplit;
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "new LeafsToSplit size:" << leafNodes2Split.size())
+ }
+ else {// nonleaf node to be split
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry is nonleaf ")
+ n11 = (HierIndexDS*)entry->getNewInstance();
+ n11->setIsNode(true);
+ nodeDomain = cd;
+ parentIxDS = entry->getParent();
+ clear(keyvec2, entry);
+ splitNonLeaf(n11, entry, keyvec2, leafNodes2Split, axis, value, nodeDomain, sl);
+ k22 = convert(entry);
+ parentIxDS->removeObject(k22);
+ parentIxDS->destroy();
+ parentIxDS = NULL;
+ }
+ //n11 and entry are allocated
+ //n11 and entry are not inserted in a parent!
+ k11 = convert(n11);
+ if (n11->isUnderFull() || n11->isLeaf())
+ {//leaf or node with more than minfill entries
+ SDirIndexLogic::insertObject(pd1, k11, sl);
+ if (n11->isLeaf() && n11->isOverFull())
+ {//very improbable that this happens
+ //leaf with more than maxfill entries
+ leafNodes2Split.push_back(n11);
+ }
+ else {//node or leaf with ok entries
+ n11->destroy();
+ n11 = NULL;
+ }
+ }
+ else {//node with less than minfill entries
+ listMinKO1.push_back(k11);
+ //k11 is deleted in redistribute
+ n11->destroy();
+ n11 = NULL;
+ }
+ k22 = convert(entry);
+ if (entry->isUnderFull() || entry->isLeaf())
+ {
+ SDirIndexLogic::insertObject(pd2, k22, sl);
+ if (entry->isLeaf() && entry->isOverFull())
+ {// very improbable that this happens
+ leafNodes2Split.push_back(entry);
+ }
+ else {
+ entry->destroy();
+ entry = 0;
+ }
+ }
+ else {
+ listMinKO2.push_back(k22);
+ entry->destroy();
+ entry = 0;
+ //k22 is deleted in redistribute
+ //where is entry deleted
+ }
+ }
+ }
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "ended repopulating node (entry " << i << " of " << nodeSize << ")");
+ }
+ redistributeEntries(pd1, listMinKO1, sl);
+ redistributeEntries(pd2, listMinKO2, sl);
+ pd1->setAssignedDomain(nd1);
+ pd2->setAssignedDomain(nd2);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitNonLeaf(" << OId(pd1->getIdentifier()) << ", " << OId(pd2->getIdentifier()) << ", keyvec, leafNodes2Split, " << axis << ", " << value << ", " << domain << ")");
+ }
+
+void
+SRPTIndexLogic::redistributeEntries(IndexDS* node, KeyObjectVector& listMinKO, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "redistributeEntries(" << OId(node->getIdentifier()) << ", redistList.size " << listMinKO.size() << ")")
+ // not implemented. It could redistribute objects in case of too low fill factor
+ unsigned int size = listMinKO.size();
+ for(int i = 0; i < size; i++)
+ {
+ SDirIndexLogic::insertObject(node, listMinKO[i], sl);
+ }
+
+ listMinKO.clear();
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "redistributeEntries(" << OId(node->getIdentifier()) << ", redistList.size " << listMinKO.size() << ")")
+ }
+
+bool
+SRPTIndexLogic::removeObject(IndexDS* ixDS, const KeyObject& objToRemove, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << OId(ixDS->getIdentifier()) << ", " << objToRemove << ")")
+ bool found = false;
+ if (ixDS->getAssignedDomain().intersects_with(objToRemove.getDomain()))
+ {
+ if (((HierIndexDS*)ixDS)->isLeaf())
+ if (ixDS->removeObject(objToRemove))
+ {
+ found = true;
+ }
+ else {
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << ixDS->getAssignedDomain() << ", " << objToRemove.getDomain() << ") object was not found")
+ }
+ else {
+ KeyObjectVector candidates;
+ SDirIndexLogic::intersectUnOpt(ixDS, objToRemove.getDomain(), candidates);
+ for (KeyObjectVector::iterator it = candidates.begin(); it != candidates.end(); it++)
+ {
+ if (SRPTIndexLogic::removeObject((HierIndexDS*)DBHierIndexId((*it).getObject()), objToRemove, sl))
+ found = true;
+ else {
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << ixDS->getAssignedDomain() << ", " << objToRemove.getDomain() << ") did not remove an entry in a node")
+ }
+ }
+ }
+ }
+ else {
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << ixDS->getAssignedDomain() << ", " << objToRemove.getDomain() << ") did not intersect")
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << OId(ixDS->getIdentifier()) << ", const KeyObject*)")
+ return found;
+ }
+
+void
+SRPTIndexLogic::calculatePartition(r_Dimension& axis, r_Range& value, const HierIndexDS* node)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "calculatePartition(" << axis << ", " << value << ", " << OId(node->getIdentifier()) << ")");
+ float bestDist1 = 1;
+ float bestDist2 = 1;
+ double bestDistBal = 1;
+ r_Dimension dim = node->getDimension();
+ r_Dimension first = 0;//rand()%dim;
+ r_Dimension a = first;
+ unsigned int elemCount = node->getSize();
+ r_Range v = -1;
+ float dist1 = 0;
+ float dist2 = 0;
+ double distBal = 0;
+
+ while (true)
+ {
+ for (int i = 0; i < elemCount; i++)
+ {
+ v = node->getObjectDomain(i)[a].low();
+ calculateDistribution(a, v, dist1, dist2, node);
+
+ // balanced property of this split distribution: how close it
+ // is to 50%, 50% distribution. Worst case: 1.
+ distBal = fabs(dist1 - 0.5) + fabs(dist2 - 0.5);
+
+ if (distBal < bestDistBal)// less overlapping in number of entries;add other conditions !!!
+ {
+ bestDist1 = dist1;
+ bestDist2 = dist2;
+ bestDistBal = fabs(bestDist1 - 0.5) + fabs(bestDist2 - 0.5);
+ axis = a;
+ value = v;
+ }
+ }
+ a = (a+1) % dim;
+ if (a == first)
+ break;
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "calculatePartition(" << axis << ", " << value <<", " << OId(node->getIdentifier()) << ")")
+ }
+
+
+void
+SRPTIndexLogic::calculateDistribution( r_Dimension axis,
+ r_Range value,
+ float& dist1,
+ float& dist2,
+ const HierIndexDS* node)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "calculateDistribution(" << axis <<", " << value << ", Dist1, Dist2, " << OId(node->getIdentifier()) << ")")
+ dist1 = 0;
+ dist2 = 0;
+ unsigned int n = node->getSize();
+ r_Minterval dom;
+ for (unsigned int i = 0; i < n ; i++)
+ {
+ dom = node->getObjectDomain(i);
+ if (dom[axis].high() < value)
+ {// entry will fall in first part only
+ dist1 +=1;
+ RMDBGMIDDLE(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry goes into the first");
+ }
+ else {// entry will fall in first part only
+ if (dom[axis].low() >= value)
+ {
+ dist2 +=1;
+ RMDBGMIDDLE(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry goes into the second");
+ }
+ else {// entry will fall in both parts
+ dist1 +=1;
+ dist2 +=1;
+ RMDBGMIDDLE(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry goes into the first and second");
+ }
+ }
+ }
+ dist1 = dist1/n;
+ dist2 = dist2/n;
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "calculateDistribution(" << axis <<", " << value << ", " << dist1 << ", " << dist2 << ", " << OId(node->getIdentifier()) << ")")
+ }
+
+
+void
+SRPTIndexLogic::intersect( const r_Minterval& searchInter,
+ const r_Minterval& parentEntryDomain,
+ KeyObjectVector& intersectedObjs,
+ const HierIndexDS* ix,
+ r_Area& area)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect(SearchDom:" << searchInter << ", ParentDom:" << parentEntryDomain << ", intersectedObjects.size " << intersectedObjs.size() << ", " << OId(ix->getIdentifier()) << ", Area " << area << ") ")
+
+ r_Minterval intersectArea;
+ r_Minterval dom = ix->getCoveredDomain();
+ KeyObjectVector intersectedNodes;
+ HierIndexDS* tempIx = NULL;
+ r_Area nodeArea = 0;
+ r_Area oldArea = area;
+ unsigned int i = 0;
+ unsigned int nodeSize = ix->getSize();
+
+ if (ix->isLeaf())
+ {
+ //are there cells which belong into the result?
+ if (searchInter.intersects_with(dom))
+ {
+ intersectArea = searchInter.create_intersection(dom);
+ //may this leaf put cells into the result?
+ if (intersectArea.intersects_with(parentEntryDomain))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "searchDom " << searchInter << " indexDom " << dom << " intersection " << intersectArea << " area " << area);
+ binaryRegionSearch(ix, searchInter, area, intersectedObjs, 0, nodeSize - 1, dom);//parentEntryDomain);
+ }
+ }
+ }
+ else {// node is not a Leaf
+ if (searchInter.intersects_with(dom))
+ {
+ nodeArea = area;
+ binaryRegionSearch(ix, searchInter, nodeArea, intersectedNodes, 0, nodeSize - 1, dom);
+ for (i = 0; i < intersectedNodes.size(); i++)
+ {
+ if (area == 0)
+ {
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect AREA IS ALREADY FOUND")
+ }
+ if (nodeArea > oldArea)
+ {
+ RMInit::logOut << "SRPTIndexLogic::intersect() the index found more cells than allowed" << endl;
+ throw r_Error(INDEXEXHAUSTEDAREA);
+ }
+ r_Minterval objDom(intersectedNodes[i].getDomain());
+ tempIx = convert(intersectedNodes[i]);
+ intersect(searchInter, objDom, intersectedObjs, tempIx, area);
+ tempIx->destroy();
+ }
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect(SearchDom:" << searchInter << ", ParentDom:" << parentEntryDomain << ", intersectedObjects.size " << intersectedObjs.size() << ", " << OId(ix->getIdentifier()) << ", Area " << area << ")")
+ }
+
+bool
+SRPTIndexLogic::intersectNoDuplicates( const r_Minterval& searchInter,
+ const r_Minterval& entryDomain,
+ const r_Minterval& parentEntryDomain)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersectNoDuplicates(SearchDom:" << searchInter << ", EntryDom:" << entryDomain << ", ParentDom:" << parentEntryDomain << ")");
+
+ bool retval = true;
+ int testcase = 0;
+ r_Dimension i = 0;
+ r_Dimension dim = entryDomain.dimension();
+
+ // This condition allows an early detection of duplicates in the
+ // index structure for intersection operations.
+ // An entry of a leaf node is only added to the list of entries
+ // intersected by that node having it internally with respect to the
+ // parent (since no other node may have it then) or if it crosses
+ // the upper bounds of the parent node (it will be also crossed by
+ // another parent at the upper bounds and it is added to the list then).
+
+ // don't add the entry if it doesn't intersect the search area
+ // or if it intersects a lower bound of the parent's
+ // domain and that lower bound of the parent is higher than
+ // that of the search region
+ r_Range searchLo = 0;
+ r_Range entryLo = 0;
+
+
+ for (i = 0 ; i < dim; i++)
+ {
+ searchLo = searchInter[i].low();
+ entryLo = entryDomain[i].low();
+ // entry doesn't intersect search region
+ if (entryLo > searchInter[i].high())
+ {
+ retval = false;
+ break;
+ }
+ // entry doesn't intersect search region
+ if (entryDomain[i].high() < searchLo)
+ {
+ retval = false;
+ break;
+ }
+ // entry is also in another node where it intersects the higher bounds,
+ // it should be included then, not here
+ if (entryLo < parentEntryDomain[i].low() && searchLo < parentEntryDomain[i].low())
+ {
+ retval = false;
+ break;
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersectNoDuplicates(SearchDom:" << searchInter << ", EntryDom:" << entryDomain << ", ParentDom:" << parentEntryDomain << ")" << retval << " testcase " << testcase << " at dim " << i);
+ return retval;
+ }
+
+int
+SRPTIndexLogic::regionSearch( const HierIndexDS* ixNode,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ const r_Minterval& parentEntryDomain)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "regionSearch(" << OId(ixNode->getIdentifier()) << ", SearchDom " << mint << ", Area " << area << ", intersectedObjects.size " << intersectedObjects.size() << ", ParentDom " << parentEntryDomain << ")");
+
+ r_Minterval intersectedRegion;
+ unsigned int endAt = ixNode->getSize();
+ int retval = endAt;
+ KeyObject newObj;
+ r_Minterval objDomain;
+ unsigned int i = 0;
+ r_Area oldArea = area;
+
+/*there must be something like or the map version
+ DomainMap t;
+ DomainMap::iterator it;
+ for (i = 0; i < intersectedObjects->size(); i++)
+ {
+ DomainPair p((*intersectedObjects)[i]->getObject().getOId(), (*intersectedObjects)[i]->getDomain());
+ t.insert(p);
+ }
+*/
+
+ for (i = 0; i < endAt ; i++)
+ {
+ objDomain = ixNode->getObjectDomain(i);
+ // object intersects region
+ // problem with calculation of complete area when the entry is not added.
+
+/*there must be something like or the map version
+ if (objDomain.intersects_with(mint))
+ {
+ objDomain.intersection_with(mint);
+ area = area - objDomain.cell_count();
+ if (area <= 0)
+ {
+ retval = i;
+ break;
+ }
+ //insert intersectNoDuplicates here
+ }
+*/
+
+ if (intersectNoDuplicates(mint, objDomain, parentEntryDomain))
+ {
+
+/*there must be something like or the map version
+ if ((it = t.find(ixNode->getObject(i)->getObject().getOId())) == t.end())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "adding " << ixNode->getObject(i)->getObject().getOId() << " intersected region " << intersectedRegion << " area " << area);
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "not adding " << ixNode->getObject(i)->getObject().getOId() << " area " << area);
+ RMInit::logOut << "should never happen" << endl;
+ RMInit::logOut << "want to add " << ixNode->getObject(i)->getObject().getOId() << " at " << objDomain << endl;
+ for (it = t.begin(); it != t.end(); it++)
+ RMInit::logOut << OId((*it).first) << " at " << (*it).second << endl;
+ throw r_Error(TESTERROR);
+ }
+*/
+
+ objDomain.intersection_with(mint);
+ area = area - objDomain.cell_count();
+ newObj = ixNode->getObject(i);
+ intersectedObjects.push_back(newObj);
+ if (oldArea < area)
+ {
+ retval = i;
+ RMInit::logOut << "SRPTIndexLogic::regionSearch() the area was completely exhausted" << endl;
+ throw r_Error(INDEXEXHAUSTEDAREA);
+ break;
+ }
+ if (area == 0)
+ {
+ retval = i;
+ break;
+ }
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "not adding " << ixNode->getObject(i).getObject().getOId() << " dom " << objDomain << " does not intersect")
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "regionSearch(" << OId(ixNode->getIdentifier()) << ", SearchDom " << mint << ", Area " << area << ", intersectedObjects.size " << intersectedObjects.size() << ", ParentDom " << parentEntryDomain << ")" << retval);
+ return retval;
+ }
+
+
+int
+SRPTIndexLogic::binaryRegionSearch( const HierIndexDS* ixNode,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ int first,
+ int last,
+ const r_Minterval& parentEntryDomain)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "binaryRegionSearch(" << OId(ixNode->getIdentifier()) << ", SearchDom " << mint << ", Area " << area << ", intersectedObjs.size " << intersectedObjects.size() << ", From " << first << ", To " << last << ", ParentDom " << parentEntryDomain << ")");
+ // code copied from DirIx::binaryRegionSearch (11.11.98)
+ // and further adapted
+ // assumes order according to the lowest corner of the objects
+
+ int retval = 0;
+ int middle = 0;
+ int inc = 0;
+ int ix = 0;
+ int compResult = 0;
+ r_Minterval t;
+ r_Minterval objDomain;
+ r_Minterval intersectedRegion;
+ KeyObject newObj;
+ r_Area oldArea = area;
+
+ if (area == 0)
+ retval = -1;
+ else
+ if (first > last)
+ retval = -1;
+ else {
+ middle = (last + first)/2;
+
+ t = ixNode->getObjectDomain(middle);
+ if(mint.get_high().compare_with(t.get_origin()) < 0)
+ { // R.hi < tile.lo no tiles after this one
+ retval = binaryRegionSearch(ixNode, mint, area, intersectedObjects, first, middle - 1, parentEntryDomain);
+ }
+ else {
+ if(t.get_high().compare_with(mint.get_origin()) < 0)
+ {
+ retval = binaryRegionSearch(ixNode, mint, area, intersectedObjects, middle + 1, last, parentEntryDomain);
+ if (area > 0)
+ {
+ retval = binaryRegionSearch(ixNode, mint, area, intersectedObjects, first, middle - 1, parentEntryDomain);
+ }
+ }
+ else {
+ inc = 1;
+ for (ix = middle; ; ix += inc)
+ {
+ objDomain = ixNode->getObjectDomain(ix);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "cycle " << ix << " " << objDomain);
+ compResult = mint.get_high().compare_with(objDomain.get_origin());
+ // object intersects region
+ if (intersectNoDuplicates(mint, objDomain, parentEntryDomain))
+ {
+ intersectedRegion = objDomain;
+ intersectedRegion.intersection_with(mint).intersection_with(parentEntryDomain);
+ oldArea = area;
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "interesected region " << intersectedRegion << " intersection area " << intersectedRegion.cell_count() << " area before " << area)
+ area = area - intersectedRegion.cell_count();
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "area after " << area)
+ if (area > oldArea)
+ {
+ RMInit::logOut << "SRPTIndexLogic::binaryRegionSearch() index found more cells than allowed" << endl;
+ throw r_Error(INDEXEXHAUSTEDAREA);
+ }
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersectedRegion " << intersectedRegion << " area " << area)
+ newObj = ixNode->getObject(ix);
+ intersectedObjects.push_back(newObj);
+ if (area == 0)
+ {
+ retval = ix;
+ break;
+ }
+ }
+ if (inc != -1 && (ix == last || compResult < 0))
+ {
+ ix = middle;
+ inc = -1;
+ }
+ if (ix == first && inc == -1)
+ {
+ retval = ix;
+ break;
+ }
+ }
+ }
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "binaryRegionSearch(" << OId(ixNode->getIdentifier()) << ", SearchDom " << mint << ", Area " << area << ", intersectedObjs.size " << intersectedObjects.size() << ", From " << first << ", To " << last << ", ParentDom " << parentEntryDomain << ")" << retval);
+ return retval;
+ }
+
+void
+SRPTIndexLogic::containPointQuery( const r_Point& searchPoint,
+ const HierIndexDS* ix,
+ KeyObject& result,
+ const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "containPointQuery(" << searchPoint << ", Node " << ix << ", result)");
+ HierIndexDS* intersectedNode = NULL;
+ if (!ix)
+ {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "containPointQuery(" << searchPoint << ", Node, result) node is NULL");
+ }
+ else {
+ if (ix->isLeaf())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "index " << OId(ix->getIdentifier()) << " is leaf");
+ SDirIndexLogic::containPointQuery(ix, searchPoint, result, sl);
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "index " << OId(ix->getIdentifier()) << " is node");
+ KeyObject lowerNode;
+ SDirIndexLogic::containPointQuery(ix, searchPoint, lowerNode, sl);
+ containPointQuery(searchPoint, convert(lowerNode), result, sl);
+ }
+ if (result.isInitialised())
+ {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "containPointQuery(" << searchPoint << ", " << OId(ix->getIdentifier()) << ")" << result);
+ }
+ else {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "containPointQuery(" << searchPoint << ", " << OId(ix->getIdentifier()) << ") nothing found");
+ }
+ }
+ }
+
+HierIndexDS*
+SRPTIndexLogic::convert(const KeyObject& toConvert)
+ {
+ HierIndexDS* retval = NULL;
+ if (toConvert.isInitialised())
+ retval = (HierIndexDS*)DBHierIndexId(toConvert.getObject());
+ return retval;
+ }
+
+KeyObject
+SRPTIndexLogic::convert(HierIndexDS* toConvert)
+ {
+ if (toConvert)
+ return KeyObject(DBObjectId(toConvert->getIdentifier()), toConvert->getAssignedDomain());
+ KeyObject retval;
+ return retval;
+ }
+
diff --git a/indexmgr/srptindexlogic.hh b/indexmgr/srptindexlogic.hh
new file mode 100644
index 0000000..7ad0dc5
--- /dev/null
+++ b/indexmgr/srptindexlogic.hh
@@ -0,0 +1,244 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _SRPTINDEXLOGIC_HH_
+#define _SRPTINDEXLOGIC_HH_
+
+#include "indexmgr/hierindexds.hh"
+#include "reladminif/lists.h"
+class r_Point;
+class StorageLayout;
+
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+This class contains the logic for access, insertion and removal of objects
+into an index data structure. The logic is based on the R-Plus Tree. Objects
+inserted in this index don`t have to be regular. The leaf object`s domain
+must not overlap.
+
+The leaf objects are sorted into nodes which are split when needed. Nodes
+are split when the number of objects in them is equal to the maximum size
+specified by the underlying index data structure. This check should be done
+using the IndexDS::isOverFull() method.
+
+This class uses functionality supplied by SDirIndexLogic.
+
+This class was converted to pure static methods because it is fast to use stack.
+*/
+
+class SRPTIndexLogic
+ {
+ public:
+ static bool insertObject2(IndexDS* ixDS, const KeyObject& newObject, const StorageLayout& sl);
+ /*@Doc:
+ Inserts a new object in the index.
+ Must have a name different from the other insertObject because of the stupid compiler.
+ */
+
+ static bool removeObject(IndexDS* ixDS, const KeyObject& tileToRemove, const StorageLayout& sl);
+ /*@Doc:
+ Removes the object from the indexx.
+ */
+
+ static void intersect2(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Search the index for a search region.
+ Determines all the tiles in the index which intersect a given
+ search interval (given by {\tt searchInter}).
+ Must have a name different from other intersect because of compiler.
+ */
+
+ static void containPointQuery2(const IndexDS* ixDS, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl);
+ /*@Doc:
+ Passes a pointer to the searched item.
+ Must have different name from other containPointQuery because of compiler.
+ */
+
+ static void getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Returns all the tiles belonging to the object.
+ */
+
+ static int insertObject( const KeyObject& newObject,
+ HierIndexDS* ix,
+ IndexPVector& leafNodes2Split,
+ const StorageLayout& sl);
+ /*@Doc:
+ Inserts a new object in the index.
+ Recursive function which does the real job.
+ The return value is 1 if the current node was split, 0 otherwise. This is
+ used internally by the algorithm (?really - better not touch it?).
+ In {\tt leafNodes2Split}, the set of overflowed leaf nodes is returned.
+ It should be passed to {\tt splitNodes()}.
+ */
+
+
+ static void extendFaces(HierIndexDS* ix,
+ const r_Minterval& newKeyObjectDom,
+ const r_Minterval& oldCurrDom,
+ const bool* facesToExtendLo,
+ const bool* facesToExtendHi);
+ /*@Doc:
+ This method extends the domains of all index nodes which
+ intersect with the object that will be inserted.
+ This is neccessary because subsequently all nodes which
+ intersect with the object to be inserted are retrieved by
+ DirIndexLogic.
+ */
+
+ static void splitNodes( HierIndexDS* ixDS,
+ IndexPVector& leafNodes2Split,
+ const StorageLayout& sl);
+ /*@Doc:
+ Splits all nodes after insert
+ Full nodes are split all at once, to avoid repetition of splits.
+ Uses splitLeaf and splitNonLeaf to carry out the task.
+ */
+
+ static void splitLeaf( HierIndexDS* n1,
+ HierIndexDS* n2,
+ KeyObjectVector& keyvec,
+ r_Dimension axis,
+ r_Range value,
+ r_Minterval& domain,
+ const StorageLayout& sl);
+ /*@Doc:
+ Splits a leaf node
+ {\tt n1} has the entries which intersect (leafNodeDomain and x(axis) <= value),
+ {\tt n2 } the ones intersecting (leafNodeDomain and x(axis) > value).
+ The keyvec holds the tiles which will be inserted into the 2 new leafs.
+ The domain is the complete assigned domain of both leafs. It will be divided into 2 parts
+ based on axis and value. Then the tiles are assigned to the leaf that covers them - or both.
+ */
+
+ static void splitNonLeaf( HierIndexDS* n1,
+ HierIndexDS* n2,
+ KeyObjectVector& keyvec,
+ IndexPVector& leafNodes2Split,
+ r_Dimension axis,
+ r_Range value,
+ const r_Minterval& domain,
+ const StorageLayout& sl);
+ /*@Doc:
+ Splits a nonleaf node
+ Does semantically the same as splitLeaf. Syntactically it is quite different because it has to check
+ for over full nodes and treat them.
+ */
+
+ static void redistributeEntries(IndexDS* node,
+ KeyObjectVector& listMinKO,
+ const StorageLayout& sl);
+ /*@Doc:
+ stores the Keyobjects in the node. could do some more
+ fancy stuff in the future (like checking for under full and then redistribute those nodes).
+ */
+
+ static void calculatePartition( r_Dimension& axis,
+ r_Range& value,
+ const HierIndexDS* node);
+ /*@Doc:
+ Calculates the optimal partition for this node Partition is returned in {\tt axis}, {\tt value}.
+ This is the most problematic stuff because it depends on the order of insertion.
+ The index nodes are not optimally filled. But you know: we are the fastest anyway ; )
+ */
+
+ static void calculateDistribution( r_Dimension axis,
+ r_Range value,
+ float& dist1,
+ float& dist2,
+ const HierIndexDS* node);
+ /*@Doc:
+ Caluculates the distribution of entries for a given partition
+ Used by calculate partition.
+ Calculates resulting distribution of children of a node {\ttnode} if
+ it is split at axis = value. Distributions are returned in {\ttdist1}
+ (percentage of nodes intersecting x(axis) <= value) and {\ttdist2}
+ (percentage of nodes intersecting x(axis) > value).
+ */
+
+ static void intersect( const r_Minterval& searchInter,
+ const r_Minterval& parentDomain,
+ KeyObjectVector& intersectedObjs,
+ const HierIndexDS* ix,
+ r_Area& area);
+ /*@Doc:
+ This method helps you get the data out of the index again : )
+ searchInter will tell you for what to look.
+ parentDomain is used to determin if you should include a matching object or not.
+ you might not want to include a matching object because of duplicate entries in the index.
+ this choice is made by intersectNoDuplicates.
+ intersectedObjs holds the found entries.
+ the area is used to determine if we got everything.
+ */
+
+ static bool intersectNoDuplicates( const r_Minterval& searchInter,
+ const r_Minterval& entryDomain,
+ const r_Minterval& parentDomain);
+ /*@Doc:
+ Decides if the entry at hand should be included from this index or if it is in another
+ one and will be included from there.
+ */
+
+
+ static int binaryRegionSearch( const HierIndexDS* ixNode,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ int first,
+ int last,
+ const r_Minterval& parentEntryDom);
+ /*@Doc:
+ This will use a binary search algorithm to quickly find the nodes we want.
+ */
+
+ static int regionSearch(const HierIndexDS* ixNode,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ const r_Minterval& parentDomain);
+ /*@Doc:
+ This is a not binary search algorithm for doing the same as binaryRegionSearch.
+ */
+
+ static void containPointQuery(const r_Point& searchPoint, const HierIndexDS* ix, KeyObject& result, const StorageLayout& sl);
+ /*@Doc:
+ */
+
+ static HierIndexDS* convert(const KeyObject& toConvert);
+ /*@Doc:
+ Helper method for converting a keyobject to a hierindex object.
+ the parameter must be deleted by the caller.
+ the returned object must be deleted by the caller.
+ */
+
+ static KeyObject convert(HierIndexDS* toConvert);
+ /*@Doc:
+ Helper method for converting a hierindex to a keyobject.
+ the parameter must be deleted by the caller.
+ the returned object must be deleted by the caller.
+ */
+
+ };
+
+#endif
diff --git a/indexmgr/test/Makefile b/indexmgr/test/Makefile
new file mode 100644
index 0000000..5ae92c2
--- /dev/null
+++ b/indexmgr/test/Makefile
@@ -0,0 +1,103 @@
+# -*-Makefile-*-
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module indexmgr
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+SRCCXX= test_clusterix.cc test_expix.cc test_ix.cc \
+ test_abc.cc test_dirix.cc test_hierix.cc test_ix1.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+MISCCLEAN = core
+
+# some additional flags for compiling and linking
+CXXFLAGS := $(STLCXXFLAGS) $(CXXFLAGS)
+
+# includes in module directory
+LDFLAGS += -I$(RMANBASE)/indexif
+LDFLAGS := $(STLLDFLAGS) $(LDFLAGS) -L$(SUPPORT_BASE)/lib -lz
+
+
+########################### Targets ##############################
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+# test target for class Index (always make module!)
+.PHONY: test_index_target
+test_index_target: build_module test_dirix test_clusterix test_expix
+
+######################## Dependencies ############################
+
+# make module
+.PHONY: build_module
+build_module:
+ cd $(RMANBASE)/indexmgr; $(MAKE)
+
+# can not be used as a target (module library is not remade!)
+
+test_abc: test_abc.o
+ $(PURIFY) $(CXX) -o $@ $^ -lm
+
+test_dirix: test_dirix.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) $(BLOBIF) $(ADMINIF) $(MDDIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(QLPARSER)
+
+test_ix1: test_ix1.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) \
+ $(BLOBIF) $(ADMINIF) $(MDDIF) $(TOOLS) $(QLPARSER)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(QLPARSER)
+
+test_ix: test_ix.o $(RASLIB)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm
+
+test_hierix: test_hierix.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) $(BLOBIF) $(ADMINIF) $(MDDIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(QLPARSER)
+
+test_expix: test_expix.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) $(BLOBIF) $(ADMINIF) $(MDDIF) $(TOOLS) $(QLPARSER)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(INDEXMGR)
+
+test_clusterix: test_clusterix.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) $(BLOBIF) $(ADMINIF) $(MDDIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(INDEXIF) $(INDEXMGR)
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/indexmgr/test/test_abc.cc b/indexmgr/test/test_abc.cc
new file mode 100644
index 0000000..7c8160b
--- /dev/null
+++ b/indexmgr/test/test_abc.cc
@@ -0,0 +1,373 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: testabc.cc
+ *
+ * MODULE: test for A,B,C
+ *
+ * PURPOSE:
+ * Tests a hierarchy of classes where each one, after insertElement( )
+ * transforms itself into the superclass. Preparation for Hierarchy
+ * of indexes DirIx, RegDirIx, etc.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+// #include <vector.h>
+
+
+// extern char* myExecArgv0 = "";
+
+// #include "raslib/rminit.hh"
+//RMINITGLOBALS('C')
+
+class A
+{
+public:
+ A( );
+ A( A* a );
+ virtual void insertElement( A*& a );
+ virtual A* insertElementTransform( );
+ static void insertElementTransformStat( A*& );
+ virtual void printStatus( );
+ virtual ~A( );
+ int* DynAtt_A;
+ int StatAtt_A;
+protected:
+ void testProtectedA( );
+};
+
+A::A( )
+ :StatAtt_A(1)
+{
+ DynAtt_A = new int;
+ *DynAtt_A = 2;
+ cout <<"A Constructor"<< endl;
+}
+
+A::A( A* a)
+ :StatAtt_A( a->StatAtt_A ), DynAtt_A( a->DynAtt_A )
+{
+ a->DynAtt_A = 0;
+}
+
+void A::insertElement( A*& a )
+{
+ cout <<"A::insertElement( ) ";
+ printStatus( );
+ cout << endl;
+}
+
+A* A::insertElementTransform( )
+{
+ cout <<"A::insertElementTransform( ) ";
+ printStatus( );
+ cout << endl;
+ return this;
+}
+
+void A::insertElementTransformStat( A*& ix )
+{
+ cout <<"A::insertElementTransformStat( ) ";
+ ix->printStatus( );
+ cout << endl;
+}
+
+void A::printStatus( )
+{
+ cout <<"A: Dyn " << *DynAtt_A <<" Stat "<< StatAtt_A << endl;
+}
+
+A::~A()
+{
+ cout <<"A Destructor"<< endl;
+ if (DynAtt_A) delete DynAtt_A;
+}
+
+void A::testProtectedA( )
+{
+ cout <<"A::testProtectedA( )"<<endl;
+}
+
+class B: public A
+{
+public:
+ B( );
+ B( A* b );
+ virtual void insertElement( A*& a );
+ virtual A* insertElementTransform( );
+ static void insertElementTransformStat( A*& ix );
+ virtual void printStatus( );
+ virtual ~B( );
+ int* DynAtt_B;
+ int StatAtt_B;
+ void testProtectedB( );
+};
+
+B::B( )
+ :A( ),StatAtt_B(3)
+{
+ DynAtt_B = new int;
+ *DynAtt_B = 4;
+ cout <<"B Constructor"<< endl;
+}
+
+B::B( A* b )
+ :A(b),StatAtt_B(((B*)b)->StatAtt_B),DynAtt_B(((B*)b)->DynAtt_B)
+{
+ // use dynamic attributes of b, so that has to delete them
+ // from origin
+ ((B*)b)->DynAtt_B = 0;
+}
+
+void B::insertElement( A*& a )
+{
+ cout <<"B::insertElement( ) ";
+ printStatus( );
+ cout << endl;
+ A* c = new A( a );
+ delete a;
+ a = c;
+}
+
+A* B::insertElementTransform( )
+{
+ A* thisA = this;
+ cout <<"B::insertElementTransform( ) ";
+ printStatus( );
+
+ A* a = new A(thisA);
+ delete thisA;
+ return a;
+}
+
+void B::insertElementTransformStat( A*& ix )
+{
+ A* thisA = ix;
+ cout <<"B::insertElementTransformStat( ) ";
+ ix->printStatus( );
+
+ A* a = new A(thisA);
+ delete thisA;
+ ix = thisA;
+}
+
+void B::printStatus( )
+{
+ cout <<"B: Dyn " << *DynAtt_B <<" Stat "<< StatAtt_B << endl;
+}
+B::~B()
+{
+ cout <<"B Destructor"<< endl;
+ if (DynAtt_B) delete DynAtt_B;
+}
+
+void B::testProtectedB( )
+{
+ cout << "B::testProtectedB( ) calling A::testProtectedA( ) on itself: "<< endl;
+ A::testProtectedA( );
+ B objB;
+ cout << "B::testProtectedB( ) calling A::testProtectedA( ) on another obj B: "<< endl;
+ objB.testProtectedA( );
+ // A objA;
+ // cout << "B::testProtectedB( ) calling A::testProtectedA( ) on another obj A: "<< endl;
+ // objA.testProtectedA();
+}
+
+class C: public B
+{
+public:
+ C( int );
+ virtual void insertElement( A*& a );
+ virtual A* insertElementTransform( );
+ static void insertElementTransformStat( A*& ix );
+ virtual void printStatus( );
+ virtual ~C( );
+ int* DynAtt_C;
+ int StatAtt_C;
+};
+
+C::C(int)
+ :B(), StatAtt_C(5)
+{
+ DynAtt_C = new int;
+ *DynAtt_C = 6;
+ cout <<"C Constructor "<< endl;
+}
+void C::insertElement( A*& a )
+{
+ if( a != this )
+ cout << "Unexpected Usage of C::insertElement( ) "<< endl;
+ cout <<"C::insertElement( ) ";
+ printStatus( );
+
+ B* c = new B(a);
+ delete a;
+ a = c;
+}
+
+A* C::insertElementTransform( )
+{
+ A* thisA = this;
+ cout <<"C::insertElementTransform( ) ";
+ printStatus( );
+
+ B* b = new B(thisA);
+ delete thisA;
+ return b;
+
+}
+
+void C::insertElementTransformStat( A*& ix )
+{
+ A* thisA = ix;
+ cout <<"C::insertElementTransformStat( ) ";
+ ix->printStatus( );
+
+
+ B* b = new B(thisA);
+ ix = b;
+ delete thisA;
+
+}
+
+void C::printStatus( )
+{
+ cout <<"C: Dyn " << *DynAtt_C <<" Stat "<< StatAtt_C << endl;
+}
+
+C::~C( )
+{
+ cout <<"C Destructor"<< endl;
+ if (DynAtt_C) delete DynAtt_C;
+}
+
+/*************************************************************
+ * Function name.: int main( )
+ *
+ * Return value..: exit status
+ ************************************************************/
+int
+main( )
+{
+
+ cout << endl << " ---------------------------------------------- " << endl;
+ cout << endl << " Testing insertElementTransformStat( ) -------- " <<endl;
+
+ int i1t = 3;
+ cout << "Creating new C" << endl;
+ A *at = new C( i1t );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Inserting 2. element in B and getting A"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Inserting 3. element in A and getting A"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Inserting 4. element in A and getting A"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Destroying object"<< endl;
+ delete at;
+
+ cout << endl << " ---------------------------------------------- "<< endl;
+ at = new C( i1t );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Destroying object"<< endl;
+ delete at;
+
+ cout << endl << " ---------------------------------------------- " << endl;
+
+ exit( 0);
+/*
+ cout << endl << " ---------------------------------------------- " << endl;
+ cout << endl << " Testing insertElementTransform( ) ------------ " <<endl;
+
+ int i1t = 3;
+ cout << "Creating new C" << endl;
+ A *at = new C( i1t );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Inserting 2. element in B and getting A"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Inserting 3. element in A and getting A"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Inserting 4. element in A and getting A"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Destroying object"<< endl;
+ delete at;
+
+ cout << endl << " ---------------------------------------------- "<< endl;
+ at = new C( i1t );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Destroying object"<< endl;
+ delete at;
+
+ cout << endl << " ---------------------------------------------- " << endl;
+*/
+
+
+
+/*
+ B objB;
+ objB.testProtectedB( );
+ exit( 0 );
+
+ int i1 = 3;
+ cout << "Creating new C" << endl;
+ A *a = new C( i1 );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ a->insertElement( a );
+ cout << endl << "Inserting 2. element in B and getting A"<< endl;
+ a->insertElement( a );
+ cout << endl << "Inserting 3. element in A and getting A"<< endl;
+ a->insertElement( a );
+ cout << endl << "Inserting 4. element in A and getting A"<< endl;
+ a->insertElement( a );
+ cout << endl << "Destroying object"<< endl;
+ delete a;
+
+ cout << endl << " ---------------------------------------------- "<< endl;
+ a = new C( i1 );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ a->insertElement( a );
+ cout << endl << "Destroying object"<< endl;
+ delete a;
+
+ cout << endl << " ---------------------------------------------- "<< endl;
+ C a1( i1 );
+ a = new C( i1 );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ a1.insertElement( a );
+ cout << endl << "Inserting 2. element in C and getting B"<< endl;
+ a->insertElement( a );
+ cout << endl << "Destroying object"<< endl;
+ delete a;
+
+ exit( 0 );
+*/
+}
diff --git a/indexmgr/test/test_clusterix.cc b/indexmgr/test/test_clusterix.cc
new file mode 100644
index 0000000..92f4cf9
--- /dev/null
+++ b/indexmgr/test/test_clusterix.cc
@@ -0,0 +1,338 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_clusterix.cc
+ *
+ * MODULE: test for ClusterIx
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+
+#include "indexmgr/clusterix.hh"
+#include "dbclusterix.hh"
+#include "dbmddobjix.hh"
+#include "blobtile.hh"
+#include "basetype.hh"
+#include "ulongtype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/tile.hh"
+
+static char O2BenchDBName[] = "ClusterIxBase";
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+static void testConstructors();
+static void testSearch();
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting contents of database..." << endl;
+ ClearDB(database);
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ // database.open( O2BenchDBName ); // doesn't work with O2 V.5
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ database.create_persistent_root( "IndexContainer",
+ "d_List<d_Ref<DBClusterIx>>",
+ OL_CONSTANT);
+ ta.commit();
+
+ // create indexes and put them in IndexContainer
+ cout << "Create indices and put in IndexContainer..." << endl;
+ ta.begin();
+ testConstructors();
+ ta.commit();
+
+ // read index and print contents
+ cout << "Read indices and print contents..." << endl;
+ ta.begin();
+ testAccessing();
+ ta.commit();
+
+ // test search operation and print contents
+ cout << "Search a rectangular region and print contents..." << endl;
+ ta.begin();
+ testSearch();
+ ta.commit();
+
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+}
+
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructs Indices and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testConstructors()
+{
+ ClusterIx* indexObj2;
+ ULongType anyType;
+ char anyCell[4];
+
+ cout << "....testConstructors"<< endl;
+
+ // read root object
+ d_List<DBMDDObjIxId> indexList("IndexContainer");
+
+ // create Index Object
+ cout << " indexObj1" << endl;
+
+ cout << " tile 1 = nil, 10-12, 20-24 "<< endl;
+ r_Sinterval limits1Obj1(10l,12l);
+ r_Sinterval limits2Obj1(20l,24l);
+ r_Minterval dom(2);
+ dom << limits1Obj1 << limits2Obj1;
+ PersTile* tile1Obj1 = new PersTile( dom, &anyType, (const char*) anyCell);
+
+ cout << " tile 2 = nil, 0-400, 22-24 "<< endl;
+ dom[0].set_interval(0l,400l);
+ dom[1].set_interval(22l,24l);
+ PersTile* tile2Obj1 = new PersTile( dom, &anyType, (const char*) anyCell);
+
+ cout << " tile 3 = nil, 0-600, 10-1000 "<< endl;
+ dom[0].set_interval(0l,600l);
+ dom[1].set_interval(10l,1000l);
+ PersTile* tile3Obj1 = new PersTile( dom, &anyType, (const char*) anyCell);
+
+ vector<PersTile*> newTiles;
+ newTiles.push_back(tile1Obj1);
+ newTiles.push_back(tile2Obj1);
+ newTiles.push_back(tile3Obj1);
+
+ ClusterIx* indexObj1 = new ClusterIx(newTiles);
+ indexList.insert_element_last(indexObj1->getDBMDDObjIxId());
+
+ // create DBclusterix Object
+
+ cout << " indexObj2 "<< endl;
+ cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+ PersTile* tile1Obj2 = new PersTile( dom2, &anyType, (const char*) anyCell);
+ indexObj2 = new ClusterIx(tile1Obj2);
+
+ cout << " tile 2 = nil, 20-39, 60-79, 60-89 "<< endl;
+ dom2[0].set_interval(20l,39l);
+ dom2[1].set_interval(60l,79l);
+ dom2[2].set_interval(60l,89l);
+ PersTile* tile2Obj2 = new PersTile( dom2, &anyType, (const char*) anyCell);
+ indexObj2->insertTile(tile2Obj2);
+ indexList.insert_element_last(indexObj2->getDBMDDObjIxId());
+
+ delete indexObj1;
+ delete indexObj2;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DBClusterIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjIxId accessedIndex;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ cout<<endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testSearch()
+{
+
+ DBMDDObjIxId accessedIndex;
+ ULongType anyType;
+
+ cout << "....testSearch"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 0 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ vector< Tile* >* entriesList;
+
+ accessedIndex = indexIt.get_element();
+
+ if (i == 0 || i == 1)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+
+ cout << " -- " << i+1 << ". index object in list. Search for:";
+ switch (i) {
+ case 0: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = accessedIndex->intersect(searchInt1, &anyType);
+ break;
+ case 1: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = accessedIndex->intersect(searchInt2, &anyType);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ // O2 d_List d_Iterator< d_Ref<TilesIxEntry> > entryIt = entriesList->create_iterator();
+ // O2 d_List for ( ; entryIt.not_done() ; entryIt.advance() )
+ // O2 d_List entryIt.get_element()->printStatus();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ }
+
+ // release(entriesList->begin(), entriesList->end());
+ for( vector<Tile*>::iterator entIt = entriesList->begin();
+ entIt != entriesList->end();
+ entIt++ )
+ delete *entIt;
+
+ delete entriesList;
+
+ }
+
+}
+/*************************************************************
+ * Function......: clearDB( d_Database &DB )
+ *
+ * Arguments.....: none
+ * DB: reference to a d_Database-object to use
+ * Return value..: none
+ * Description...: delete the O2-base (in case it already
+ * existed) and recreates an empty base
+ ************************************************************/
+
+static void ClearDB( d_Database &DB )
+{
+ d_Transaction trans;
+ trans.begin();
+
+ cout << "Destroying " << O2BenchDBName << endl;
+
+ // destroy the database in case it already exists
+ DB.destroy( O2BenchDBName );
+
+ // and create a new one
+ cout << "Creating " << O2BenchDBName <<" on schema "
+ << O2BenchSchemaName << endl;
+ DB.create( O2BenchDBName, O2BenchSchemaName );
+
+ trans.commit();
+}
diff --git a/indexmgr/test/test_dirix.cc b/indexmgr/test/test_dirix.cc
new file mode 100644
index 0000000..801d974
--- /dev/null
+++ b/indexmgr/test/test_dirix.cc
@@ -0,0 +1,357 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_dirix.cc
+ *
+ * MODULE: test for DirIx
+ *
+ * PURPOSE:
+ * instantiates DBDirIx objects and reads them
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#define TEST_PROTECTED
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+
+#include "indexmgr/dirix.hh"
+#include "dbdirix.hh"
+#include "dbmddobjix.hh"
+#include "blobtile.hh"
+#include "basetype.hh"
+#include "ulongtype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/tile.hh"
+#include "indexmgr/persdirix.hh"
+#include "indexmgr/regdirix.hh"
+
+static char O2BenchDBName[] = "DirIxBase";
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+extern char* myExecArgv0 = "";
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+static void testConstructors();
+static void testSearch();
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting contents of database..." << endl;
+ ClearDB(database);
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ // database.open( O2BenchDBName ); // doesn't work with O2 V.5
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ /*
+ database.create_persistent_root( "IndexContainer",
+ "d_List<d_Ref<DBDirIx>>",
+ OL_CONSTANT);
+ */
+ ta.commit();
+
+
+ // create indexes and put them in IndexContainer
+ cout << "Create indices and put in IndexContainer..." << endl;
+ ta.begin();
+ testConstructors();
+ ta.commit();
+
+ // read index and print contents
+ cout << "Read indices and print contents..." << endl;
+ ta.begin();
+ testAccessing();
+ ta.commit();
+
+ // test search operation and print contents
+ cout << "Search a rectangular region and print contents..." << endl;
+ ta.begin();
+ testSearch();
+ ta.commit();
+
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+}
+
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructs Indices and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testConstructors()
+{
+ ULongType anyType;
+ char anyCell[4];
+
+ cout << "....testConstructors"<< endl;
+
+ // read root object
+ d_List<DBMDDObjIxId> indexList("IndexContainer");
+
+ // create Index Object
+ cout << " indexObj1" << endl;
+
+ r_Minterval dom( "[10:12,20:24]");
+ cout << " tile 1 = nil, "<< dom << endl;
+ PersTile* tile1Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ dom = r_Minterval( "[0:400,22:24]");
+ cout << " tile 2 = nil, "<< dom << endl;
+ PersTile* tile2Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ dom = r_Minterval( "[0:600,10:1000]");
+ cout << " tile 3 = nil, "<< dom << endl;
+ PersTile* tile3Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ vector<Tile*> newTiles;
+ newTiles.push_back(tile1Obj1);
+ newTiles.push_back(tile2Obj1);
+ newTiles.push_back(tile3Obj1);
+
+ PersDirIx* pd1 =
+ new PersDirIx( tile1Obj1->getDimension( ), ( const BaseType* ) &anyType );
+ RegDirIx<PersDirIx, Tile >* indexObj1 = new RegDirIx<PersDirIx, Tile >( pd1 );
+ MultiDimIx<Tile>::insertObjectsTransform( newTiles, indexObj1 );
+ // indexObj1->insertObjectsTransform( newTiles, indexObj1 );
+ indexList.insert_element_last(pd1->getDBMDDObjIxId());
+
+ // create DBDirIx Object
+
+ cout << " indexObj2 "<< endl;
+ r_Minterval dom2( "[0:19,20:59,30:59]");
+ cout << " tile 1 = nil, "<< dom2 << endl;
+ PersTile* tile1Obj2 =
+ new PersTile( dom2, ( const BaseType* ) &anyType, (const char*) anyCell);
+ PersDirIx* pd2 =
+ new PersDirIx( tile1Obj2->getDimension( ), ( const BaseType* ) &anyType );
+ RegDirIx<PersDirIx, Tile>* indexObj2 = new RegDirIx<PersDirIx, Tile>( pd2 );
+ indexObj2->insertObject( tile1Obj2 );
+
+ dom2 = r_Minterval( "[20:39,60:79,60:89]");
+ cout << " tile 2 = nil, "<< dom2 << endl;
+ PersTile* tile2Obj2 =
+ new PersTile( dom2, ( const BaseType* ) &anyType, (const char*) anyCell);
+ indexObj2->insertObject(tile2Obj2);
+ indexList.insert_element_last(pd2->getDBMDDObjIxId());
+
+ // PerDirIx doesn't free tiles
+ delete tile1Obj1;
+ delete tile2Obj1;
+ delete tile3Obj1;
+
+ delete tile1Obj2;
+ delete tile2Obj2;
+ delete indexObj1;
+ delete indexObj2;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DBDirIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjIxId accessedIndex;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ cout<<endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testSearch()
+{
+
+ DBMDDObjIxId accessedIndex;
+ ULongType anyType;
+
+ cout << "....testSearch"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 0 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ vector< Tile* >* entriesList;
+
+ accessedIndex = indexIt.get_element();
+
+ if (i == 0 || i == 1)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+
+ cout << " -- " << i+1 << ". index object in list. Search for:";
+ switch (i) {
+ case 0: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = ((d_Ref< DBDirIx>) accessedIndex)->intersect(searchInt1, &anyType);
+ break;
+ case 1: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = ((d_Ref<DBDirIx>)accessedIndex)->intersect(searchInt2, &anyType);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ // O2 d_List d_Iterator< d_Ref<TilesIxEntry> > entryIt = entriesList->create_iterator();
+ // O2 d_List for ( ; entryIt.not_done() ; entryIt.advance() )
+ // O2 d_List entryIt.get_element()->printStatus();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ }
+
+ // release(entriesList->begin(), entriesList->end());
+ for( vector<Tile*>::iterator entIt = entriesList->begin();
+ entIt != entriesList->end();
+ entIt++ )
+ delete *entIt;
+
+ delete entriesList;
+
+ }
+
+}
+/*************************************************************
+ * Function......: clearDB( d_Database &DB )
+ *
+ * Arguments.....: none
+ * DB: reference to a d_Database-object to use
+ * Return value..: none
+ * Description...: delete the O2-base (in case it already
+ * existed) and recreates an empty base
+ ************************************************************/
+
+static void ClearDB( d_Database &DB )
+{
+ d_Transaction trans;
+ trans.begin();
+
+ cout << "Destroying " << O2BenchDBName << endl;
+
+ // destroy the database in case it already exists
+ DB.destroy( O2BenchDBName );
+
+ // and create a new one
+ cout << "Creating " << O2BenchDBName <<" on schema "
+ << O2BenchSchemaName << endl;
+ DB.create( O2BenchDBName, O2BenchSchemaName );
+
+ trans.commit();
+}
diff --git a/indexmgr/test/test_expix.cc b/indexmgr/test/test_expix.cc
new file mode 100644
index 0000000..fc178a0
--- /dev/null
+++ b/indexmgr/test/test_expix.cc
@@ -0,0 +1,488 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_expix.cc
+ *
+ * MODULE: test for DirIx<T>
+ *
+ * PURPOSE:
+ * instantiates DirIx objects, inputs tiles and reads them, comparing
+ * performance for different indexes (for instance, DirIx<PersDirIx> vs.
+ * DirIx<TransDirIx>. Uses O2 directly.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+
+#include "indexmgr/transmddobjix.hh"
+#include "indexmgr/persmddobjix.hh"
+#include "indexmgr/dirix.hh"
+#include "indexmgr/transdirix.hh"
+#include "dbdirix.hh"
+#include "dbmddobjix.hh"
+#include "blobtile.hh"
+#include "basetype.hh"
+#include "ulongtype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/tile.hh"
+#include "tools/timer.hh"
+#include "indexmgr/persdirix.hh"
+
+static char O2BenchDBName[] = "DirIxBase";
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+extern char* myExecArgv0 = "";
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+
+static void testTransDirIx();
+static void testDirIx();
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting contents of database..." << endl;
+ ClearDB(database);
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ // database.open( O2BenchDBName ); // doesn't work with O2 V.5
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ // database.create_persistent_root( "IndexContainer",
+ // "d_List<d_Ref<DBDirIx>>",
+ // OL_CONSTANT);
+ ta.commit();
+
+ /*
+ cout << "Testing TransDirIx..." << endl;
+ ta.begin();
+ testTransDirIx( );
+ ta.commit();
+ */
+
+ cout << "Testing DirIx..." << endl;
+ ta.begin();
+ testDirIx( );
+ ta.commit();
+
+ cout << endl;
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+
+ return 0;
+}
+
+
+void
+testTransDirIx( )
+{
+
+ cout << "....testTransDirIx"<< endl;
+
+ TransDirIx* ti = new TransDirIx( 2 );
+ cout << "TransDirIx just created: "<< endl;
+ ti->printStatus( );
+
+ ULongType anyType;
+ char anyCell[4];
+
+ TransTile* ttArray[12];
+
+ for( long j = 0; j < 12 ; j++)
+ {
+ r_Minterval dom(2);
+ dom << r_Sinterval( j, j+ 5 ) << r_Sinterval( j , j+5 );
+ TransTile* tt = new TransTile( dom, (BaseType* ) &anyType, anyCell );
+ ttArray[j] = tt;
+ }
+
+ for( j = 0; j < 10 ; j++)
+ {
+ cout << "Insert Tile Last " << ttArray[j]->getDomain( ) << endl;
+ ti->insertObjectLast( ttArray[j] );
+ ti->printStatus( );
+ }
+
+ cout << "Insert Tile pos 5 " << ttArray[10]->getDomain( ) << endl;
+ ti->insertObject( ttArray[10], 5 );
+ ti->printStatus( );
+
+ cout << "Insert Tile First " << ttArray[11]->getDomain( ) << endl;
+ ti->insertObjectFirst( ttArray[11] );
+ ti->printStatus( );
+
+ delete ti;
+}
+
+void
+testDirIx( )
+{
+ cout << "....testDirIx"<< endl;
+
+ ULongType anyType;
+ char anyCell[4];
+
+ // TransDirIx* t = new TransDirIx( 2 );
+ // PersDirIx* t = new PersDirIx( 2, &anyType );
+
+ // char index[] = "MDDObjIx* DirIx<TransDIrIx>";
+ // char index[] = "MDDObjIx* DirIx<PersDirIx>";
+ // char index[] = "MDDObjIx* PersMDDObjIx ";
+ // char index[] = "TransMDDObjIx* DirIx<TransDirIx> ";
+ char index[] = "PersMDDObjIx* DirIx< > ";
+ // MDDObjIx* /* DirIx< TransDirIx >* */ di = new DirIx< TransDirIx >( t );
+ // DirIx< PersDirIx >* di = new DirIx< PersDirIx >( t );
+ MDDStorage ms1;
+ ms1.setIndexType( MDDStorage::DirTilesIx );
+ PersMDDObjIx* di = new PersMDDObjIx( 2, &anyType, &ms1 );
+ // TransMDDObjIx* di = new TransMDDObjIx( 2, 0 );
+
+ // char index1[] = "TransMDDObjIx* RegDirIx<TransDirIx>";
+ char index1[] = "PersMDDObjIx* RegDirIx< >";
+ // char index1[] = "TransMDDObjIx* ";
+ // TransMDDObjIx* di1 = new TransMDDObjIx( 2, 1 );
+ // DirIx< TransDirIx >* di1 = new DirIx< TransDirIx >( t );
+ MDDStorage ms;
+ ms.setIndexType( MDDStorage::RegDirIx );
+ PersMDDObjIx* di1 = new PersMDDObjIx( 2, &anyType, &ms );
+
+ cout << "Comparison of Index " << index << endl;
+ cout << "with Index1 " << index1 << endl;
+
+ // NumTiles should be a square from something:
+ unsigned const sqrtnumTiles = 32;
+ unsigned const NumTiles = sqrtnumTiles * sqrtnumTiles ;
+ unsigned const NumIntersections = 30;
+
+ // cout << "Index " << index << " just created: "<< endl;
+ // di->printStatus( );
+
+
+ cout <<"Random insertion of tiles into the indexe(s) ..." << endl;
+ Tile* ttArray[NumTiles]; Tile* tt1Array[NumTiles];
+ unsigned alreadyUsed[NumTiles];
+
+ long j = 0;
+
+ for( long k = 0; k < sqrtnumTiles ; k++ )
+ {
+ for( long l = 0; l < sqrtnumTiles ; l++)
+ {
+ r_Minterval dom(2);
+ // dom << r_Sinterval( k*5 , k*5+5-1 ) << r_Sinterval( l*5 , l*5+5-1 );
+ dom << r_Sinterval( k , k ) << r_Sinterval( l , l );
+
+ // Tile* tt = new TransTile( dom, (BaseType* ) &anyType, anyCell );
+ Tile* tt = new PersTile( dom, (const BaseType* ) &anyType, anyCell );
+ // Tile* tt1 = new TransTile( dom, (BaseType* ) &anyType, anyCell );
+ Tile* tt1 = new PersTile( dom, (const BaseType* ) &anyType, anyCell );
+
+ ttArray[j] = tt; tt1Array[j] = tt1;
+ alreadyUsed[j]=0;
+ j++;
+ }
+ }
+
+ cout <<" j "<< j << endl;
+
+ for( j = 0; j < NumTiles ; j++)
+ {
+ int ixToUse = rand( ) % NumTiles;
+ if ( alreadyUsed[ ixToUse ] )
+ {
+ // calculate another index;
+ ixToUse = 0;
+ for( int i = 0; !ixToUse && i < NumTiles; i++ )
+ {
+ if ( !alreadyUsed[i] ) ixToUse = i;
+ }
+ }
+ alreadyUsed[ ixToUse ] = 1;
+ cout << "Insert Tile ttArray[ " << ixToUse << " ] : ";
+ cout << ttArray[ixToUse]->getDomain( ) << endl;
+
+ // Index
+ di->insertTile( ttArray[ ixToUse ] );
+ // Index 1
+ di1->insertTile( tt1Array[ ixToUse ] );
+ // di->printStatus( );
+ }
+
+ cout << index << " contents: "<< endl;
+ di->printStatus( );
+
+ cout << index1 << " contents: "<< endl;
+ di1->printStatus( );
+ cout << endl;
+
+ r_Minterval cd = di->getCurrentDomain( );
+
+ r_Minterval badQuery1("[33:43,139:149]");
+ // not bad r_Minterval badQuery1("[65:75,32:42]");
+
+ r_Minterval badQuery2("[139:149,144:154]");
+
+ r_Minterval badQuery3("[43:53,81:91]");
+ // not bad r_Minterval badQuery3("[107:117,53:63]");
+
+ r_Minterval badQuery4("[37:47,151:161]");
+ // not bad r_Minterval badQuery4("[89:99,11:21]");
+
+ r_Minterval badQuery5("[71:81,113:123]"); // not bad
+
+ // test extreme cases: no intersection at all with the current domain
+ r_Minterval badQuery6("[161:162,113:113]");
+
+ // test extreme cases: no intersection at all with the current domain
+ r_Minterval badQuery7("[170:172,140:140]");
+
+ for( int i = 0; i < NumIntersections; i++ )
+ {
+ Timer time; Timer time1;
+ RMTimer* rtime = new RMTimer( "DirIx", "intersect" );
+ RMTimer* rtime1 = new RMTimer( "RegDirIx", "intersect" );
+ r_Minterval intRegion( 2 );
+ long l1 = cd.get_origin( )[0];
+ long l2 = cd.get_origin( )[1];
+ long h1 = cd.get_high( )[0];
+ long h2 = cd.get_high( )[1];
+ long length1 = h1 - l1 +1;
+ long length2 = h2 - l2 +1;
+ l1 = l1 + rand( ) % length1;
+ l2 = l2 + rand( ) % length2;
+ h1 = l1 + (rand( ) % (h1-l1+1) );
+ h2 = l2 + (rand( ) % (h2-l2+1) );
+ intRegion << r_Sinterval( l1,h1) << r_Sinterval( l2,h2);
+
+/*
+ if ( i == NumIntersections - 1 )
+ intRegion = badQuery1;
+ if ( i == NumIntersections - 2 )
+ intRegion = badQuery2;
+ if ( i == NumIntersections - 3 )
+ intRegion = badQuery3;
+ if ( i == NumIntersections - 4 )
+ intRegion = badQuery4;
+ if ( i == NumIntersections - 5 )
+ intRegion = badQuery5;
+*/
+ if ( i == NumIntersections - 6 )
+ intRegion = badQuery6;
+ if ( i == NumIntersections - 7 )
+ intRegion = badQuery7;
+
+
+ cout << "Intersect with "<< intRegion << endl;
+
+ // Index
+ time.start( ); rtime->start( );
+ vector< Tile* >* rqResult = di->intersect( intRegion );
+ rtime->stop( ); time.stop( );
+ if ( rqResult )
+ {
+ cout << index << endl << " No. of tiles, time , time/noTiles = "
+ << rqResult->size( ) << " , "<< time << " , ";
+ if ( rqResult->size( ) ) cout << time.ellapsed_sec( )/rqResult->size( ) << endl;
+ }
+ else
+ cout << "No tiles intersected "<< endl;
+ delete rtime;
+
+ // Index 1
+ time1.start( ); rtime1->start( );
+ vector< Tile* >* rqResult1 = di1->intersect( intRegion );
+ rtime1->stop( ); time1.stop( );
+ if ( rqResult1 )
+ {
+ cout << index1 << endl << " No. of tiles, time1, time1/noTiles = "
+ << rqResult1->size( ) << " , "<< time1 << " , ";
+ if ( rqResult1->size( ) ) cout << time1.ellapsed_sec( )/rqResult1->size( ) << endl;
+ }
+ else
+ cout << "No tiles intersected "<< endl;
+ delete rtime1;
+
+
+ // Index
+ cout << "Result " << index << endl;
+ if ( rqResult )
+ {
+ for( int j = 0; j < rqResult->size( ); j++)
+ cout << ( *rqResult )[j]->getDomain( ) << endl;
+ delete rqResult;
+ }
+
+ // Index1
+ cout << "Result " << index1 << endl;
+ if ( rqResult1 )
+ {
+ for( j = 0; j < rqResult1->size( ); j++)
+ cout << ( *rqResult1 )[j]->getDomain( ) << endl;
+ delete rqResult1;
+ }
+ cout << endl;
+ }
+
+ for( i = 0; i < NumIntersections; i++ )
+ {
+ Timer time; Timer time1;
+ r_Point pnt(2);
+ RMTimer* rtime = new RMTimer( "DirIx", "Point query" );
+ RMTimer* rtime1 = new RMTimer( "RegDirIx", "Point query" );
+ long l1 = cd.get_origin( )[0];
+ long l2 = cd.get_origin( )[1];
+ long length1 = cd.get_high( )[0] - l1;
+ long length2 = cd.get_high( )[1] - l2;
+ l1 = l1 + rand( ) % length1;
+ l2 = l2 + rand( ) % length2;
+ pnt << l1 << l2;
+
+ cout << "Point query with "<< pnt << endl;
+
+
+ // Index
+ time.start( ); rtime->start( );
+ Tile* rqResult = di->containPointQuery( pnt );
+ rtime->stop( ); time.stop( );
+ cout << index << " tile, time = "
+ << rqResult->getDomain( ) << " , "<< time << endl;
+ delete rtime;
+
+ // Index 1
+ time1.start( ); rtime1->start( );
+ Tile* rqResult1 = di1->containPointQuery( pnt );
+ rtime1->stop( ); time1.stop( );
+ cout << index1 << " tile, time1 = "
+ << rqResult1->getDomain( ) << " , "<< time1 << endl;
+ delete rtime1;
+
+ cout << endl;
+ }
+
+ delete di;
+ delete di1;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DBDirIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjIxId accessedIndex;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ cout<<endl;
+ }
+
+}
+
+
+/*************************************************************
+ * Function......: clearDB( d_Database &DB )
+ *
+ * Arguments.....: none
+ * DB: reference to a d_Database-object to use
+ * Return value..: none
+ * Description...: delete the O2-base (in case it already
+ * existed) and recreates an empty base
+ ************************************************************/
+
+static void ClearDB( d_Database &DB )
+{
+ d_Transaction trans;
+ trans.begin();
+
+ cout << "Destroying " << O2BenchDBName << endl;
+
+ // destroy the database in case it already exists
+ DB.destroy( O2BenchDBName );
+
+ // and create a new one
+ cout << "Creating " << O2BenchDBName <<" on schema "
+ << O2BenchSchemaName << endl;
+ DB.create( O2BenchDBName, O2BenchSchemaName );
+
+ trans.commit();
+}
diff --git a/indexmgr/test/test_hierix.cc b/indexmgr/test/test_hierix.cc
new file mode 100644
index 0000000..306d1bc
--- /dev/null
+++ b/indexmgr/test/test_hierix.cc
@@ -0,0 +1,388 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_hierix.cc
+ *
+ * MODULE: test for PersHierIx
+ *
+ * PURPOSE:
+ * instantiates DBDirIx objects and reads them
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#define TEST_PROTECTED
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+
+
+#include "dbhierix.hh"
+#include "dbdirix.hh"
+#include "dbmddobjix.hh"
+
+#include "blobtile.hh"
+#include "basetype.hh"
+#include "ulongtype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/tile.hh"
+#include "indexmgr/persdirix.hh"
+#include "indexmgr/regdirix.hh"
+#include "indexmgr/pershierix.hh"
+#include "indexmgr/dirix.hh"
+#include "indexmgr/rptreeix.hh"
+
+static char O2BenchDBName[] = "HierIxBase";
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+extern char* myExecArgv0 = "";
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+static void testConstructors();
+static void testSearch();
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting contents of database..." << endl;
+ ClearDB(database);
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ // database.open( O2BenchDBName ); // doesn't work with O2 V.5
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ database.create_persistent_root( "HierIndexContainer",
+ "d_List<d_Ref<DBDirIx>>",
+ OL_CONSTANT);
+ ta.commit();
+
+
+ // create indexes and put them in HierIndexContainer
+ cout << "Create indices and put in HierIndexContainer..." << endl;
+ ta.begin();
+ testConstructors();
+ ta.commit();
+
+ // read index and print contents
+ cout << "Read indices and print contents..." << endl;
+ ta.begin();
+ testAccessing();
+ ta.commit();
+
+ // test search operation and print contents
+ // cout << "Search a rectangular region and print contents..." << endl;
+ // ta.begin();
+ // testSearch();
+ //ta.commit();
+
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+}
+
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructs Indices and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testConstructors()
+{
+ ULongType anyType;
+ char anyCell[4];
+ RPlusTreeIx< Tile >* rtix;
+
+ cout << "....testConstructors"<< endl;
+
+ // read root object
+ d_List<DBMDDObjIxId> indexList("HierIndexContainer");
+
+
+ // create Index Object
+ cout << " indexObj1" << endl;
+
+ r_Minterval dom( "[10:12,20:24]");
+ cout << " tile 1 = nil, "<< dom << endl;
+ PersTile* tile1Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ dom = r_Minterval( "[0:400,22:24]");
+ cout << " tile 2 = nil, "<< dom << endl;
+ PersTile* tile2Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ dom = r_Minterval( "[0:600,10:1000]");
+ cout << " tile 3 = nil, "<< dom << endl;
+ PersTile* tile3Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ vector<Tile*> newTiles;
+ newTiles.push_back(tile1Obj1);
+ newTiles.push_back(tile2Obj1);
+ newTiles.push_back(tile3Obj1);
+
+ PersDirIx* pd1 =
+ new PersDirIx( tile1Obj1->getDimension( ), ( const BaseType* ) &anyType );
+ pd1->insertObject( tile1Obj1, 0 );
+ pd1->insertObject( tile2Obj1, 1 );
+ pd1->insertObject( tile3Obj1, 2 );
+
+ // pd1->insertObjects( newTiles );
+
+ indexList.insert_element_last(pd1->getDBMDDObjIxId());
+
+ // create DBDirIx Object
+
+ cout << " indexObj2 "<< endl;
+ // cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Minterval dom2( "[0:19,20:59,30:59]");
+ cout << " tile 1 = nil, "<< dom2 << endl;
+
+ PersTile* tile1Obj2 =
+ new PersTile( dom2, ( const BaseType* ) &anyType, (const char*) anyCell);
+ PersDirIx* pd2 =
+ new PersDirIx( tile1Obj2->getDimension( ), ( const BaseType* ) &anyType );
+ pd2->insertObject( tile1Obj2, 0 );
+ // RegDirIx<PersDirIx, Tile>* indexObj2 = new RegDirIx<PersDirIx, Tile>( pd2 );
+ // indexObj2->insertObject( tile1Obj2 );
+
+ // cout << " tile 2 = nil, 20-39, 60-79, 60-89 "<< endl;
+ dom2 = r_Minterval( "[20:39,60:79,60:89]");
+ cout << " tile 2 = nil, "<< dom2 << endl;
+
+ PersTile* tile2Obj2 =
+ new PersTile( dom2, ( const BaseType* ) &anyType, (const char*) anyCell);
+ pd2->insertObject( tile2Obj2, 1 );
+ // indexObj2->insertObject(tile2Obj2);
+ indexList.insert_element_last(pd2->getDBMDDObjIxId());
+
+
+ PersHierIx* hierIxObj =
+ new PersHierIx( pd1->getDimension( ),( const BaseType* ) &anyType );
+ rtix = new RPlusTreeIx< Tile >( hierIxObj );
+
+ DirIx< PersHierIx, PersIx >* hix = new DirIx< PersHierIx, PersIx >( hierIxObj );
+
+ // hierIxObj->insertObject( pd1, 0 );
+ // hierIxObj->insertObject( pd2, 1 );
+ r_Minterval domain( pd1->getDomain( ) );
+ // domain.closure_with( pd2->getDomain(
+ hix->insertObject( pd1 );
+ hix->insertObject( pd2 );
+ indexList.insert_element_last(hierIxObj->getDBMDDObjIxId());
+
+ // PerDirIx doesn't free tiles
+ delete tile1Obj1;
+ delete tile2Obj1;
+ delete tile3Obj1;
+
+ delete tile1Obj2;
+ delete tile2Obj2;
+ // delete pd1;
+ // delete pd2;
+ // delete hierIxObj;
+ delete hix;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DBDirIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjIxId accessedIndex;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ cout<<endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testSearch()
+{
+
+ DBMDDObjIxId accessedIndex;
+ ULongType anyType;
+
+ cout << "....testSearch"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 0 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ vector< Tile* >* entriesList;
+
+ accessedIndex = indexIt.get_element();
+
+ if (i == 0 || i == 1)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+
+ cout << " -- " << i+1 << ". index object in list. Search for:";
+ switch (i) {
+ case 0: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = ((d_Ref< DBDirIx>) accessedIndex)->intersect(searchInt1, &anyType);
+ break;
+ case 1: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = ((d_Ref<DBDirIx>)accessedIndex)->intersect(searchInt2, &anyType);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ // O2 d_List d_Iterator< d_Ref<TilesIxEntry> > entryIt = entriesList->create_iterator();
+ // O2 d_List for ( ; entryIt.not_done() ; entryIt.advance() )
+ // O2 d_List entryIt.get_element()->printStatus();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ }
+
+ // release(entriesList->begin(), entriesList->end());
+ for( vector<Tile*>::iterator entIt = entriesList->begin();
+ entIt != entriesList->end();
+ entIt++ )
+ delete *entIt;
+
+ delete entriesList;
+
+ }
+
+}
+/*************************************************************
+ * Function......: clearDB( d_Database &DB )
+ *
+ * Arguments.....: none
+ * DB: reference to a d_Database-object to use
+ * Return value..: none
+ * Description...: delete the O2-base (in case it already
+ * existed) and recreates an empty base
+ ************************************************************/
+
+static void ClearDB( d_Database &DB )
+{
+ d_Transaction trans;
+ trans.begin();
+
+ cout << "Destroying " << O2BenchDBName << endl;
+
+ // destroy the database in case it already exists
+ DB.destroy( O2BenchDBName );
+
+ // and create a new one
+ cout << "Creating " << O2BenchDBName <<" on schema "
+ << O2BenchSchemaName << endl;
+ DB.create( O2BenchDBName, O2BenchSchemaName );
+
+ trans.commit();
+}
diff --git a/indexmgr/test/test_ix.cc b/indexmgr/test/test_ix.cc
new file mode 100644
index 0000000..424140c
--- /dev/null
+++ b/indexmgr/test/test_ix.cc
@@ -0,0 +1,517 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_ix.cc
+ *
+ * MODULE: test for RasDaMan tiles indexes
+ *
+ * PURPOSE:
+ * Compares RPTreeIx's to DirIx's
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/rmdebug.hh"
+
+
+#include <math.h>
+
+extern char* myExecArgv0 = "";
+
+unsigned maximumFill = 10;
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+
+void calculateGrid( const r_Minterval& baseTile,
+ const r_Minterval& gridDesc,
+ long& numberParts,
+ vector<r_Minterval>*& grid ); //r_Minterval*& grid );
+
+
+float calculateAlignFactor( const vector<r_Minterval>& partition);
+
+int isDisjunctive( const vector<r_Minterval>& parts );
+
+void createTilesDomains( ofstream& outRndPopFile,
+ ofstream& outRndBMFile,
+ ofstream& outPopFile,
+ ofstream& outBMFile,
+ float alignFactor,
+ vector< r_Minterval >*& tgIntsVec,
+ int numberTiles,
+ unsigned dim );
+int randomInsertion = 1;
+int seqInsertion = 1;
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+
+ if( argc < 4 ) {
+ cout << "Usage: test_ix <dim> <numberTiles> <alignFactor> [-r|-s]" << endl;
+ cout << " -s only sequential insertion " << endl;
+ cout << " -r only random insertion " << endl;
+ cout << " default - both sequential and random " << endl;
+ return -1;
+ }
+
+ unsigned dim;
+ unsigned numberTiles;
+ float af;
+ dim = atoi( argv[1]);
+ numberTiles = atoi( argv[2]);
+ af = atof( argv[3] );
+ if ( dim < 2 || dim > 8 )
+ {
+ cout << " Error : dimensionality outside supported limits !" << endl;
+ return -1;
+ }
+ if ( numberTiles > 100000 || numberTiles < 50 )
+ {
+ cout << " Error : number of tiles outside supported limits !" << endl;
+ return -1;
+ }
+ if ( af < 0.05 || af > 1 )
+ {
+ cout << " Error : alignment fator outside supported limits !" << endl;
+ return -1;
+ }
+
+ if ( argc == 5 && strcmp(argv[4], "-r") == 0 )
+ {
+ seqInsertion = 0;
+ }
+ else if ( argc == 5 && strcmp(argv[4], "-s") == 0 )
+ {
+ randomInsertion = 0;
+ }
+
+
+ cout << "Dimensionality " << dim << endl;
+ cout << "Number of Tiles " << numberTiles << endl;
+ cout << "Alignment factor " << af << endl;
+ cout << "RandomInsertion ";
+
+ if ( randomInsertion )
+ cout << "RandomInsertion " << endl;
+ if ( seqInsertion )
+ cout << "SequentialInsertion " << endl;
+
+ vector< r_Minterval >* tgIntsVec;
+
+
+ char namePopFile[100];
+ char nameRndPopFile[100];
+ char nameBMFile[100];
+ char nameRndBMFile[100];
+ int afint = af*100;
+
+ sprintf( nameRndPopFile, "ix%dd%dn%dafrndpop.txt", dim, numberTiles, afint);
+ sprintf( nameRndBMFile, "ix%dd%dn%dafrnd.bm", dim, numberTiles, afint);
+ sprintf( namePopFile, "ix%dd%dn%dafpop.txt", dim, numberTiles, afint);
+ sprintf( nameBMFile, "ix%dd%dn%daf.bm", dim, numberTiles, afint);
+
+ ofstream ixStreamPopResults( namePopFile );
+ ofstream ixStreamRndPopResults( nameRndPopFile );
+ ofstream ixStreamBMResults( nameBMFile );
+ ofstream ixStreamRndBMResults( nameRndBMFile );
+ if ( randomInsertion )
+ {
+ cout << "nameRndPopFile " << nameRndPopFile << endl;
+ cout << "nameRndBMFile " << nameRndBMFile << endl;
+ // system("/usr/bin/date
+ if ( !ixStreamRndPopResults || !ixStreamRndBMResults )
+ {
+ cout <<"Error: one file could not be openened" << endl;
+ return -1;
+ }
+ }
+ if ( seqInsertion )
+ {
+ cout << "namePopFile " << namePopFile << endl;
+ cout << "nameBMFile " << nameBMFile << endl;
+ // system("/usr/bin/date
+ if ( !ixStreamPopResults || !ixStreamBMResults )
+ {
+ cout <<"Error: one file could not be openened" << endl;
+ return -1;
+ }
+ }
+
+
+ cout << "Dim " << dim << endl;
+ cout << "NTiles wanted " << numberTiles << endl;
+ cout << "AlignFactor wanted " << af << endl;
+
+
+ createTilesDomains( ixStreamRndPopResults, ixStreamRndBMResults,
+ ixStreamPopResults, ixStreamBMResults, af, tgIntsVec,
+ numberTiles, dim );
+ numberTiles = tgIntsVec->size( ); // integer arithmetic error
+
+
+ ixStreamPopResults.close( );
+ ixStreamBMResults.close( );
+ ixStreamRndPopResults.close( );
+ ixStreamRndBMResults.close( );
+
+ return 0;
+}
+
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+calculateGrid( const r_Minterval& baseTile,
+ const r_Minterval& gridDesc,
+ long& numberParts,
+ vector< r_Minterval>*& grid ) // grid r_Minterval*& grid)
+{
+ cout << "calculateGrid( " << baseTile << ", "<< gridDesc << ") "<< endl;
+ numberParts = gridDesc.cell_count( );
+ grid = new vector<r_Minterval>(numberParts); //new r_Minterval[numberParts];
+ r_Point ix( baseTile.dimension( ));
+ r_Point ext = baseTile.get_extent( );
+ for ( int i= 0; i < numberParts ; i++ )
+ {
+ ix = gridDesc.cell_point( i )* ext;
+ (*grid)[i] = baseTile.create_translation( ix );
+ // grid[i] = r_Minterval( baseTile.create_translation( ix ) );
+ }
+
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+createTilesDomains( ofstream& outRndPopFile, // file for test_populate
+ ofstream& outRndBMFile, // file for benchmark
+ ofstream& outPopFile, // file for test_populate
+ ofstream& outBMFile, // file for benchmark
+ float alignFactor,
+ vector< r_Minterval >*& tgIntsVec,
+ int numberTiles,
+ unsigned dim )
+{
+
+ if( alignFactor > 1 || alignFactor == 0 )
+ {
+ cout <<"Error: invalid alignment factor." << endl;
+ exit(0);
+ }
+
+ cout << "Alignment factor wanted " << alignFactor << endl;
+ cout << "Number of tiles, dim " << numberTiles << ", "<< dim << endl;
+
+ // number of partitions of the total grid
+ double ntgdouble = numberTiles/alignFactor;
+ // cout <<"Number of tiles in total grid (double)== " << ntgdouble << endl;
+ long ntg = ntgdouble;
+ cout <<"Number of tiles in total grid (long)== " << ntg << endl;
+
+ // r_Minterval* tgInts;
+
+ float f = float (1/ float(dim) );
+ long n = pow( ntg, f);
+ cout <<"Number of tiles in d-1 first directions (n) == " << n << endl;
+ r_Minterval tile(dim);
+ const unsigned tileLength = 3;
+ r_Minterval totalGrid( dim );
+ for (int i = 0; i < dim -1; i++ )
+ {
+ tile[i].set_interval( r_Range( 0 ), tileLength-1 );
+ totalGrid[i].set_interval( r_Range( 0 ), n-1 );
+ }
+ long n1 = pow(n,dim-1);
+ n1 = ntg/n1;
+ cout << "Number of tiles in direction d (n1) == " << n1 << endl;
+ tile[dim-1].set_interval( r_Range( 0 ), tileLength-1 );
+ totalGrid[dim-1].set_interval( r_Range( 0 ), n1-1 );
+
+ long ntg1;
+ calculateGrid( tile, totalGrid, ntg1, tgIntsVec );
+
+ if ( ntg1 < numberTiles )
+ {
+ cout <<"Error: number of partitions in total grid less than numberTiles";
+ cout <<"Exiting the program (integer arithmetic)"<< endl;
+ // exit(0);
+ }
+
+ if ( ntg1 != ntg )
+ {
+ cout << "Warning: number of partitions in total grid is not as expected " << endl;
+ cout << "Alignment factor won't be as expected (integer arithmetic)"<< endl;
+ }
+
+ cout << endl;
+
+ //tgIntsVec = new vector< r_Minterval >( tgInts, tgInts+ntg1 );
+
+ // delete tgInts; // ????
+
+ cout << "Number of tiles in total grid " << ntg1 << endl;
+ /*
+ for( i =0; i < tgIntsVec->size( ); i++ )
+ cout << "Interval "<< i << (*tgIntsVec)[i] <<endl;
+ */
+ int numberMerges = ntg1-numberTiles;
+ int cont = 1;
+ for ( i = 0; i < numberMerges && cont ; )
+ {
+ int found = 0;
+ int r = rand( ) % (tgIntsVec->size( ) );
+ // merge randomly
+ int notFinished = 1;
+
+ int contr = 1;
+ for( int ri = 0; contr && cont ; ri++)
+ {
+ notFinished = 1;
+ int init = rand( ) % tgIntsVec->size( );
+ for( int j = init; notFinished ; )
+ {
+ // cout <<"i,j"<< i <<","<< j<<endl;
+ if( (*tgIntsVec)[j].is_mergeable( (*tgIntsVec)[r]) )
+ {
+
+ if ( i % 100 == 0 )
+ cout << numberMerges-i << ". Merging j,r "<< j <<","<< r << " "
+ << (*tgIntsVec)[j] << ", " << (*tgIntsVec)[r] << " resulting ";
+ /*
+ cout << numberMerges-i << ". Merging j,r "<< j <<","<< r << " "
+ << (*tgIntsVec)[j] << ", " << (*tgIntsVec)[r] << " resulting ";
+ */
+
+ (*tgIntsVec)[j] = (*tgIntsVec)[j].closure_with( (*tgIntsVec)[r] );
+ tgIntsVec->erase( tgIntsVec->begin( ) + r );
+
+ if ( i % 100 == 0 )
+ {
+ if ( r < j )
+ cout << (*tgIntsVec)[j-1] <<endl;
+ else
+ cout << (*tgIntsVec)[j] <<endl;
+ }
+
+ i++;
+ notFinished = 0;
+ found = 1;
+ }
+ j = (j+1) % tgIntsVec->size( );
+ if ( j == init )
+ notFinished = 0;
+ }
+ // cout << " r == " << r << ", j == " << j << " , notFinished == " << notFinished << endl;
+ // cout << " ri == " << ri << " , tgIntsVec->size( ) " << tgIntsVec->size( ) << endl;
+ r = (r+1) % tgIntsVec->size( );
+ if ( found )
+ contr = 0; // already found
+ else
+ {
+ if ( ri >= tgIntsVec->size( ) )
+ cont = 0; // no more merges possible
+ else
+ r = (r+1) % tgIntsVec->size( );
+ }
+ }
+ }
+
+ cout << "======================================================="<< endl;
+ cout << "Results : "<< endl;
+ cout << " Alignement Factor wanted :" << alignFactor << endl;
+ cout << " Number of Resulting Tiles " << tgIntsVec->size( ) << endl;
+
+ cout << " Resulting Tiles " << endl;
+
+ unsigned ntilesObta = tgIntsVec->size( );
+ cout << "NTiles obtained " << ntilesObta << endl;
+
+ float faObta = float ( tgIntsVec->size( ))/ntg1;
+ cout <<" Alignment factor obtained "<< faObta << endl;
+
+ /*
+ * Benchmark file format:
+ * Dim \t ntiles \t af \t random \t h \t occ
+ */
+ if ( seqInsertion )
+ {
+ outBMFile << dim << "\t";
+ outBMFile << ntilesObta << "\t";
+ outBMFile << faObta << "\t";
+ outBMFile << "0\t";
+ }
+ if ( randomInsertion )
+ {
+ outRndBMFile << dim << "\t";
+ outRndBMFile << ntilesObta << "\t";
+ outRndBMFile << faObta << "\t";
+ outRndBMFile <<"1\t";
+ }
+
+ // Visual_Tiling_2D visTil( dom, "TilesImage");
+
+ /*
+ * Pop file format:
+ * Database: BmarkIxBase
+ *
+ * MDDColl: Ix2D_1000N_5AF_Set; Char2DSet
+ *
+ * MDDObj: [ 0:*, 0:*] ; Char2D
+ *
+ * HowToStore:
+ * IndexType: R+TreeIx
+ */
+ char collRndName[100];
+ char collName[100];
+ char collTypeName[100];
+ char mddTypeName[100];
+ int faInt = faObta*100;
+ if ( randomInsertion )
+ sprintf( collRndName, "Ix%dD_%dN_%dAF_RND_Set", dim, ntilesObta, faInt);
+ if ( seqInsertion )
+ sprintf( collName, "Ix%dD_%dN_%dAF_Set", dim, ntilesObta, faInt);
+ r_Minterval dom( dim );
+ for ( int d = 0; d < dim; d++ )
+ dom[d].set_interval((r_Range)0,'*');
+
+ sprintf( collTypeName, "Char%dDSet", dim);
+ sprintf( mddTypeName, "Char%dD", dim );
+
+ if ( seqInsertion )
+ {
+ outPopFile << "Database: BmarkIxBase " << endl << endl;
+ outPopFile << "MDDColl: " << collName << "; " << collTypeName << endl<< endl;
+ outPopFile << "MDDObj: " << dom << " ; " << mddTypeName << endl;
+ outPopFile << "HowToStore:" << endl;
+ outPopFile << "IndexType: R+TreeIx " << endl << endl;
+ }
+ if ( randomInsertion )
+ {
+ outRndPopFile << "Database: BmarkIxBase " << endl << endl;
+ outRndPopFile << "MDDColl: " << collRndName << "; " << collTypeName << endl<< endl;
+ outRndPopFile << "MDDObj: " << dom << " ; " << mddTypeName << endl;
+ outRndPopFile << "HowToStore:" << endl;
+ outRndPopFile << "IndexType: R+TreeIx " << endl << endl;
+ }
+ if ( seqInsertion )
+ {
+ for( i = 0; i < tgIntsVec->size( ); i++ )
+ {
+ outPopFile <<"Tile : "<< " "<< (*tgIntsVec)[i] << "; 0x0000" << endl;
+ }
+ }
+ if ( randomInsertion )
+ {
+ unsigned vecSz = tgIntsVec->size( );
+ vector< r_Minterval >* tgIntsVec2;
+ tgIntsVec2 = new vector<r_Minterval>(vecSz);
+ unsigned tix = i;
+ for( i = 0; i < vecSz; i++ )
+ {
+ tix = rand( ) % tgIntsVec->size( );
+ outRndPopFile <<"Tile : "<< " "<< (*tgIntsVec)[tix] << "; 0x0000" << endl;
+ (*tgIntsVec2)[i] = (*tgIntsVec)[tix];
+ tgIntsVec->erase( tgIntsVec->begin( ) + tix );
+ }
+ vector< r_Minterval >* tmpIntsVec;
+ tmpIntsVec = tgIntsVec;
+ tgIntsVec = tgIntsVec2;
+ delete tmpIntsVec;
+ }
+
+ /* For debugging purposes:
+ if( !isDisjunctive( *tgIntsVec ))
+ {
+ cout <<"Error: Nondisjunctive partition, exiting program "<< endl;
+ exit( 0);
+ }
+ else cout <<" Disjunctive partition OK " << endl;
+ */
+
+ if( tgIntsVec->size( ) != numberTiles )
+ {
+ cout <<"Error: tgIntsVec->size( ) != numberTiles "<< endl;
+ // exit( 0);
+ }
+ // calculateAlignFactor( tgIntsVec );
+
+}
+
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+float
+calculateAlignFactor( const vector<r_Minterval>& part )
+{
+ float fa;
+ // for ( int i = 0; i < part.size( ); i++ ) ;
+
+ return fa;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+int isDisjunctive( const vector<r_Minterval>& parts )
+{
+ for( int i = 0; i < parts.size( ); i++ )
+ {
+ r_Minterval inter = parts[i];
+ for( int j = i+1; j < parts.size( ); j++ )
+ {
+ if( inter.intersects_with( parts[j] ))
+ return 0;
+ }
+ }
+ return 1;
+}
+
diff --git a/indexmgr/test/test_ix1.cc b/indexmgr/test/test_ix1.cc
new file mode 100644
index 0000000..73c5323
--- /dev/null
+++ b/indexmgr/test/test_ix1.cc
@@ -0,0 +1,853 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_ix.cc
+ *
+ * MODULE: test for RasDaMan tiles indexes
+ *
+ * PURPOSE:
+ * Compares RPTreeIx's to DirIx's
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+#include <o2.h> // O2 Engine
+#include <o2_error.h> // O2 error from O2 Engine
+
+#include "dbmddobjix.hh"
+#include "basetype.hh"
+#include "chartype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "tools/timer.hh"
+#include "indexmgr/persdirix.hh"
+#include "indexmgr/pershierix.hh"
+#include "indexmgr/rptreeix.hh"
+#include "indexmgr/dirix.hh"
+#include "raslib/rmdebug.hh"
+
+
+#include <math.h>
+
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchDBName[] = "TestIxBase";
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+extern char* myExecArgv0 = "";
+
+unsigned maximumFill = 10;
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+
+// indexType 1 : R+ tree, 2: DirIx
+static void testPopulateIx( int indexType,
+ const vector< r_Minterval >& tilesDoms );
+
+// static void createTilesArr( Tile** tiles, float alignFactor, int numberTiles );
+
+
+void testCompareIxs( );
+
+void calculateGrid( const r_Minterval& baseTile,
+ const r_Minterval& gridDesc,
+ long& numberParts,
+ vector<r_Minterval>*& grid ); //r_Minterval*& grid );
+
+static void testCompareIxs( char* index, char* index1,
+ MultiDimIx<Tile>* ix, MultiDimIx<Tile>* ix1,
+ r_Minterval* searchInts, int numInts);
+
+float calculateAlignFactor( const vector<r_Minterval>& partition);
+
+int isDisjunctive( const vector<r_Minterval>& parts );
+
+void createTilesDomains( ofstream& outPopFile,
+ ofstream& outBMFile,
+ float alignFactor,
+ vector< r_Minterval >*& tgIntsVec,
+ int numberTiles,
+ unsigned dim );
+int randomInsertion;
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ if( argc < 4 ) {
+ cout << "Usage: test_ix <dim> <numberTiles> <alignFactor> [-r]" << endl;
+ return -1;
+ }
+
+ unsigned dim;
+ unsigned numberTiles;
+ float af;
+ dim = atoi( argv[1]);
+ numberTiles = atoi( argv[2]);
+ af = atof( argv[3] );
+ if ( dim < 2 || dim > 8 )
+ {
+ cout << " Error : dimensionality outside supported limits !" << endl;
+ return -1;
+ }
+ if ( numberTiles > 100000 || numberTiles < 50 )
+ {
+ cout << " Error : number of tiles outside supported limits !" << endl;
+ return -1;
+ }
+ if ( af < 0.05 || af > 1 )
+ {
+ cout << " Error : alignment fator outside supported limits !" << endl;
+ return -1;
+ }
+
+ if ( argc == 5 && strcmp(argv[4], "-r") == 0 )
+ randomInsertion = 1;
+ else
+ randomInsertion = 0;
+
+
+ cout << "Dimensionality " << dim << endl;
+ cout << "Number of Tiles " << numberTiles << endl;
+ cout << "Alignment factor " << af << endl;
+ cout << "RandomInsertion ";
+ if ( randomInsertion )
+ cout << " yes " << endl;
+ else
+ cout << " no " << endl;
+
+ /*
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ try{
+ database.open( O2BenchDBName ); // doesn't work with O2 V.5
+ }
+ catch( ...)
+ {
+ cout << "Could not open database. Exiting "<< endl;
+ session.end();
+ return -1;
+ }
+
+
+ // create root collection
+ cout << "Checking root collection..." << endl;
+ ta.begin();
+ Handle collHandle = 0;
+ collHandle = o2_get_root((char*)"HierIndexContainer");
+
+ if (!collHandle)
+ {
+ cout << "Collection doesn't exist yet, creating collection ... "<< endl;
+ // if root name isn't used yet, create new root name for MDD collection
+ // I don't know if this is needed. It works without it.
+ o2_unref_handle( collHandle );
+ database.create_persistent_root( "HierIndexContainer",
+ "d_List<d_Ref<DBMDDObjIx>>",
+ OL_CONSTANT);
+ }
+ else
+ {
+ cout << "Collection exists already, does nothing. "<< endl;
+ // if it exists already, doesn't do anything
+ // I don't know if this is needed. It works without it.
+ o2_unref_handle(collHandle);
+ }
+ */
+ /*
+ int exists = 1;
+ try{
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+ }
+ catch( ...)
+ {
+ cout << "Persistent root does't exist" << endl;
+ exists =0;
+ }
+ if ( !exists )
+ database.create_persistent_root( "HierIndexContainer",
+ "d_List<d_Ref<DBMDDObjIx>>",
+ OL_CONSTANT);
+ */
+ // ta.commit();
+
+
+ vector< r_Minterval >* tgIntsVec;
+
+
+ char namePopFile[100];
+ char nameBMFile[100];
+ int afint = af*100;
+ if ( randomInsertion )
+ {
+ sprintf( namePopFile, "ix%dd%dn%dafrndpop.txt", dim, numberTiles, afint);
+ sprintf( nameBMFile, "ix%dd%dn%dafrnd.bm", dim, numberTiles, afint);
+ }
+ else
+ {
+ sprintf( namePopFile, "ix%dd%dn%dafpop.txt", dim, numberTiles, afint);
+ sprintf( nameBMFile, "ix%dd%dn%daf.bm", dim, numberTiles, afint);
+ }
+ cout << "namePopFile " << namePopFile << endl;
+ cout << "nameBMFile " << nameBMFile << endl;
+
+ ofstream ixStreamPopResults(namePopFile);
+ ofstream ixStreamBMResults(nameBMFile);
+
+ // system("/usr/bin/date
+ if ( !ixStreamPopResults || !ixStreamBMResults )
+ {
+ cout <<"Error: one file could not be openened" << endl;
+ return -1;
+ }
+
+ cout << "Dim " << dim << endl;
+ cout << "NTiles wanted " << numberTiles << endl;
+ cout << "AlignFactor wanted " << af << endl;
+
+
+ // numberTiles = 80 * i;
+ createTilesDomains( ixStreamPopResults, ixStreamBMResults, af, tgIntsVec, numberTiles, dim );
+ numberTiles = tgIntsVec->size( ); // integer arithmetic error
+
+ /*
+ cout << "Populating Index 1..." << endl;
+ ta.begin( );
+ testPopulateIx( 1, *tgIntsVec );
+ ta.commit( );
+
+ cout << "Populating Index 2..." << endl;
+ ta.begin( );
+ testPopulateIx( 2, *tgIntsVec );
+ ta.commit( );
+
+ delete tgIntsVec;
+
+ cout <<"Testing two indexes ..."<< endl;
+ ta.begin( );
+ testCompareIxs( );
+ ta.commit( );
+
+ cout << endl;
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+ */
+
+ ixStreamPopResults.close( );
+ ixStreamBMResults.close( );
+
+ return 0;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+testPopulateIx( int indexType, const vector< r_Minterval >& tilesDomains )
+{
+ CharType anyType;
+ char* anyCells;
+ const int numberTiles = tilesDomains.size( );
+ const int dim = tilesDomains[1].dimension( );
+
+
+ cout << "....testPopulateIx"<< endl;
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+
+ PersDirIx* ix = new PersDirIx( dim, &anyType );
+
+ MultiDimIx< Tile >* rix;
+
+ cout << "Ix of type ";
+ switch( indexType )
+ {
+ case 1:
+ cout << "RPlusTree ";
+ rix = new RPlusTreeIx<Tile>( ix, maximumFill );
+ break;
+ case 2:
+ cout << "DirIx ";
+ rix = new DirIx< PersDirIx, Tile >( ix );
+ break;
+ // to be extended
+ default:
+ cout <<"Error "<<endl;
+ exit( 2 );
+ }
+
+ cout << "just created: "<< endl;
+ rix->printStatus( );
+
+ Tile* tiles[100000];
+
+ for( int i = 0; i < tilesDomains.size( ); i++ )
+ {
+ anyCells = (char*)mymalloc(tilesDomains[i].cell_count() * anyType.getSize());
+ tiles[i] =
+ new PersTile( tilesDomains[i], (const BaseType*) &anyType, anyCells);
+ }
+
+
+ cout << endl;
+ for( i = 0; i < numberTiles ; i++ )
+ {
+ cout << endl << "Insert new tile " << i << " " << tiles[i]->getDomain( )<< endl;
+
+ rix->insertObject( tiles[i] );
+
+ // rix->printStatus( );
+ // cout << endl;
+ }
+ cout << endl << "Finished, index contents: " << endl;
+ rix->printStatus( );
+ cout << endl;
+ indexList.insert_element_last( ( (PersIx*) (rix->getIxDS( )) )->getDBMDDObjIxId( ) );
+ for( i = 0; i < numberTiles ; i++ )
+ delete tiles[i];
+ delete rix;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+calculateGrid( const r_Minterval& baseTile,
+ const r_Minterval& gridDesc,
+ long& numberParts,
+ vector< r_Minterval>*& grid ) // grid r_Minterval*& grid)
+{
+ cout << "calculateGrid( " << baseTile << ", "<< gridDesc << ") "<< endl;
+ numberParts = gridDesc.cell_count( );
+ grid = new vector<r_Minterval>(numberParts); //new r_Minterval[numberParts];
+ r_Point ix( baseTile.dimension( ));
+ r_Point ext = baseTile.get_extent( );
+ for ( int i= 0; i < numberParts ; i++ )
+ {
+ ix = gridDesc.cell_point( i )* ext;
+ (*grid)[i] = baseTile.create_translation( ix );
+ // grid[i] = r_Minterval( baseTile.create_translation( ix ) );
+ }
+
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+createTilesDomains( ofstream& outPopFile, // file for test_populate
+ ofstream& outBMFile, // file for benchmark
+ float alignFactor,
+ vector< r_Minterval >*& tgIntsVec,
+ int numberTiles,
+ unsigned dim )
+{
+
+ if( alignFactor > 1 || alignFactor == 0 )
+ {
+ cout <<"Error: invalid alignment factor." << endl;
+ exit(0);
+ }
+
+ cout << "Alignment factor wanted " << alignFactor << endl;
+ cout << "Number of tiles, dim " << numberTiles << ", "<< dim << endl;
+
+ // number of partitions of the total grid
+ double ntgdouble = numberTiles/alignFactor;
+ // cout <<"Number of tiles in total grid (double)== " << ntgdouble << endl;
+ long ntg = ntgdouble;
+ cout <<"Number of tiles in total grid (long)== " << ntg << endl;
+
+ // r_Minterval* tgInts;
+
+ float f = float (1/ float(dim) );
+ long n = pow( ntg, f);
+ cout <<"Number of tiles in d-1 first directions (n) == " << n << endl;
+ r_Minterval tile(dim);
+ const unsigned tileLength = 5;
+ r_Minterval totalGrid( dim );
+ for (int i = 0; i < dim -1; i++ )
+ {
+ tile[i].set_interval( r_Range( 0 ), tileLength-1 );
+ totalGrid[i].set_interval( r_Range( 0 ), n-1 );
+ }
+ long n1 = pow(n,dim-1);
+ n1 = ntg/n1;
+ cout << "Number of tiles in direction d (n1) == " << n1 << endl;
+ tile[dim-1].set_interval( r_Range( 0 ), tileLength-1 );
+ totalGrid[dim-1].set_interval( r_Range( 0 ), n1-1 );
+
+ long ntg1;
+ calculateGrid( tile, totalGrid, ntg1, tgIntsVec );
+
+ if ( ntg1 < numberTiles )
+ {
+ cout <<"Error: number of partitions in total grid less than numberTiles";
+ cout <<"Exiting the program (integer arithmetic)"<< endl;
+ // exit(0);
+ }
+
+ if ( ntg1 != ntg )
+ {
+ cout << "Warning: number of partitions in total grid is not as expected " << endl;
+ cout << "Alignment factor won't be as expected (integer arithmetic)"<< endl;
+ }
+
+ cout << endl;
+
+ //tgIntsVec = new vector< r_Minterval >( tgInts, tgInts+ntg1 );
+
+ // delete tgInts; // ????
+
+ cout << "Number of tiles in total grid " << ntg1 << endl;
+ /*
+ for( i =0; i < tgIntsVec->size( ); i++ )
+ cout << "Interval "<< i << (*tgIntsVec)[i] <<endl;
+ */
+ int numberMerges = ntg1-numberTiles;
+ int cont = 1;
+ for ( i = 0; i < numberMerges && cont ; )
+ {
+ int found = 0;
+ int r = rand( ) % (tgIntsVec->size( ) );
+ // merge randomly
+ int notFinished = 1;
+
+ int contr = 1;
+ for( int ri = 0; contr && cont ; ri++)
+ {
+ notFinished = 1;
+ int init = rand( ) % tgIntsVec->size( );
+ for( int j = init; notFinished ; )
+ {
+ // cout <<"i,j"<< i <<","<< j<<endl;
+ if( (*tgIntsVec)[j].is_mergeable( (*tgIntsVec)[r]) )
+ {
+
+ if ( i % 100 == 0 )
+ cout << numberMerges-i << ". Merging j,r "<< j <<","<< r << " "
+ << (*tgIntsVec)[j] << ", " << (*tgIntsVec)[r] << " resulting ";
+ /*
+ cout << numberMerges-i << ". Merging j,r "<< j <<","<< r << " "
+ << (*tgIntsVec)[j] << ", " << (*tgIntsVec)[r] << " resulting ";
+ */
+
+ (*tgIntsVec)[j] = (*tgIntsVec)[j].closure_with( (*tgIntsVec)[r] );
+ tgIntsVec->erase( tgIntsVec->begin( ) + r );
+
+ if ( i % 100 == 0 )
+ {
+ if ( r < j )
+ cout << (*tgIntsVec)[j-1] <<endl;
+ else
+ cout << (*tgIntsVec)[j] <<endl;
+ }
+
+ i++;
+ notFinished = 0;
+ found = 1;
+ }
+ j = (j+1) % tgIntsVec->size( );
+ if ( j == init )
+ notFinished = 0;
+ }
+ // cout << " r == " << r << ", j == " << j << " , notFinished == " << notFinished << endl;
+ // cout << " ri == " << ri << " , tgIntsVec->size( ) " << tgIntsVec->size( ) << endl;
+ r = (r+1) % tgIntsVec->size( );
+ if ( found )
+ contr = 0; // already found
+ else
+ {
+ if ( ri >= tgIntsVec->size( ) )
+ cont = 0; // no more merges possible
+ else
+ r = (r+1) % tgIntsVec->size( );
+ }
+ }
+ }
+
+ cout << "======================================================="<< endl;
+ cout << "Results : "<< endl;
+ cout << " Alignement Factor wanted :" << alignFactor << endl;
+ cout << " Number of Resulting Tiles " << tgIntsVec->size( ) << endl;
+
+ cout << " Resulting Tiles " << endl;
+
+ unsigned ntilesObta = tgIntsVec->size( );
+ cout << "NTiles obtained " << ntilesObta << endl;
+
+ float faObta = float ( tgIntsVec->size( ))/ntg1;
+ cout <<" Alignment factor obtained "<< faObta << endl;
+
+ /*
+ * Benchmark file format:
+ * Dim \t ntiles \t af \t random \t h \t occ
+ */
+ outBMFile << dim << "\t";
+ outBMFile << ntilesObta << "\t";
+ outBMFile << faObta << "\t";
+ if ( randomInsertion )
+ outBMFile <<"1\t";
+ else
+ outBMFile << "0\t";
+
+ // Visual_Tiling_2D visTil( dom, "TilesImage");
+
+ /*
+ * Pop file format:
+ * Database: BmarkIxBase
+ *
+ * MDDColl: Ix2D_1000N_5AF_Set; Char2DSet
+ *
+ * MDDObj: [ 0:*, 0:*] ; Char2D
+ *
+ * HowToStore:
+ * IndexType: R+TreeIx
+ */
+ char collName[100];
+ char collTypeName[100];
+ char mddTypeName[100];
+ int faInt = faObta*100;
+ if ( randomInsertion )
+ sprintf( collName, "Ix%dD_%dN_%dAF_RND_Set", dim, ntilesObta, faInt);
+ else
+ sprintf( collName, "Ix%dD_%dN_%dAF_Set", dim, ntilesObta, faInt);
+ r_Minterval dom( dim );
+ for ( int d = 0; d < dim; d++ )
+ dom[d].set_interval((r_Range)0,'*');
+
+ sprintf( collTypeName, "Char%dDSet", dim);
+ sprintf( mddTypeName, "Char%dD", dim );
+ outPopFile << "Database: BmarkIxBase " << endl << endl;
+ outPopFile << "MDDColl: " << collName << "; " << collTypeName << endl<< endl;
+ outPopFile << "MDDObj: " << dom << " ; " << mddTypeName << endl;
+ outPopFile << "HowToStore:" << endl;
+ outPopFile << "IndexType: R+TreeIx " << endl << endl;
+ if ( randomInsertion )
+ {
+ unsigned vecSz = tgIntsVec->size( );
+ vector< r_Minterval >* tgIntsVec2;
+ tgIntsVec2 = new vector<r_Minterval>(vecSz);
+ unsigned tix = i;
+ for( i = 0; i < vecSz; i++ )
+ {
+ tix = rand( ) % tgIntsVec->size( );
+ outPopFile <<"Tile : "<< " "<< (*tgIntsVec)[tix] << "; 0x0000" << endl;
+ (*tgIntsVec2)[i] = (*tgIntsVec)[tix];
+ tgIntsVec->erase( tgIntsVec->begin( ) + tix );
+ }
+ vector< r_Minterval >* tmpIntsVec;
+ tmpIntsVec = tgIntsVec;
+ tgIntsVec = tgIntsVec2;
+ delete tmpIntsVec;
+ }
+ else
+ {
+ for( i = 0; i < tgIntsVec->size( ); i++ )
+ {
+ outPopFile <<"Tile : "<< " "<< (*tgIntsVec)[i] << "; 0x0000" << endl;
+ }
+ }
+
+ /* For debugging purposes:
+ if( !isDisjunctive( *tgIntsVec ))
+ {
+ cout <<"Error: Nondisjunctive partition, exiting program "<< endl;
+ exit( 0);
+ }
+ else cout <<" Disjunctive partition OK " << endl;
+ */
+
+ if( tgIntsVec->size( ) != numberTiles )
+ {
+ cout <<"Error: tgIntsVec->size( ) != numberTiles "<< endl;
+ // exit( 0);
+ }
+ // calculateAlignFactor( tgIntsVec );
+
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+/*
+void
+createTilesArr( Tile** tiles,
+ float alignFactor,
+ vector< r_Minterval >* tgIntsVec )
+{
+
+ ULongType anyType;
+ char* anyCells;
+
+ for( i = 0; i < tgIntsVec->size( ); i++ )
+ {
+ anyCells = (char*)malloc(tilesDomains[i].cell_count() * anyType.getSize());
+ tiles[i] =
+ new PersTile( (*tgIntsVec)[i], (const BaseType*) &anyType, anyCells);
+ }
+
+}
+*/
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+float
+calculateAlignFactor( const vector<r_Minterval>& part )
+{
+ float fa;
+ // for ( int i = 0; i < part.size( ); i++ ) ;
+
+ return fa;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+int isDisjunctive( const vector<r_Minterval>& parts )
+{
+ for( int i = 0; i < parts.size( ); i++ )
+ {
+ r_Minterval inter = parts[i];
+ for( int j = i+1; j < parts.size( ); j++ )
+ {
+ if( inter.intersects_with( parts[j] ))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*************************************************************
+ * Function name.:
+ * void
+ * testCompareIxs( char* index, char* index1, )
+ *
+ * Arguments.....:
+ * index : name of first index
+ * index1: name of second index
+ *
+ ************************************************************/
+void
+testCompareIxs( )
+{
+ DBMDDObjIxId accessedIndex;
+ CharType anyType;
+ // char anyCell[4];
+ cout << "....testCompareIxs"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ MultiDimIx< Tile >* ix = 0;
+ MultiDimIx< Tile >* ix1 = 0;
+ PersIx* dix;
+ PersIx* dix1;
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ if (accessedIndex->isRoot( ) && accessedIndex->isLeaf( ) )
+ {
+ // to avoid mem leaks in repeated executions of this test program
+ if ( ix1 ) delete ix1;
+ cout << endl << "Creating DirIx ... ";
+ dix1 = new PersDirIx( accessedIndex, (const BaseType*) &anyType );
+ ix1 = new DirIx< PersDirIx, Tile >( (PersDirIx*)dix1 );
+ }
+ else
+ {
+ // to avoid mem leaks in repeated executions of this test program
+ if ( ix ) delete ix;
+ cout << endl << "Creating R+-tree ... ";
+ dix = new PersHierIx( accessedIndex, (const BaseType*) &anyType );
+ ix = new RPlusTreeIx<Tile>( dix,maximumFill );
+ }
+ cout << endl;
+ }
+ cout <<"OK"<<endl;
+
+ const int numInts = 30;
+ r_Minterval searchInts[numInts];
+
+ for( i = 0; i < numInts ; i++ )
+ {
+ r_Range l1= rand( ) % 25; r_Range l2 = rand( ) % 30;
+ searchInts[i] = r_Minterval( 2 );
+ searchInts[i] << r_Sinterval( l1, l1+rand() % 50 );
+ searchInts[i] << r_Sinterval( l2, l2 +rand( ) % 50 );
+
+ /*
+ searchInts[0] = r_Minterval( "[0:100,0:100]");
+ searchInts[1] = r_Minterval( "[150:200,100:250]");
+ searchInts[2] = r_Minterval( "[100:300,250:400]");
+ searchInts[1] = r_Minterval( "[50:100,100:250]");
+ searchInts[1] = r_Minterval( "[50:73,90:94]");
+ */
+ }
+
+ testCompareIxs( "R+-tree ", "DirIx ", ix, ix1, searchInts, numInts);
+
+ delete ix; delete ix1;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+testCompareIxs( char* index, char* index1,
+ MultiDimIx<Tile>* ix, MultiDimIx<Tile>* ix1,
+ r_Minterval* searchInts, int numInts)
+{
+ cout << "....testCompareIxs"<< endl;
+
+ //ULongType anyType;
+ // char anyCell[4];
+
+
+ cout << "Comparison of Index " << index << endl;
+ cout << "with Index1 " << index1 << endl;
+
+ for( int i = 0; i < numInts; i++ )
+ {
+ Timer time; Timer time1;
+ RMTimer* rtime = new RMTimer( index, "intersect" );
+ RMTimer* rtime1 = new RMTimer( index1, "intersect" );
+
+ cout << "Intersect with "<< searchInts[i] << endl;
+
+ // Index
+ time.start( ); rtime->start( );
+ vector< Tile* >* rqResult = ix->intersect( searchInts[i] );
+ int num, num1;
+ rtime->stop( ); time.stop( );
+ if ( rqResult )
+ {
+ num = rqResult->size( );
+ cout << index << endl << " No. of tiles, time , time/noTiles = "
+ << rqResult->size( ) << " , "<< time << " , ";
+ if ( rqResult->size( ) ) cout << time.ellapsed_sec( )/rqResult->size( ) << endl;
+ }
+ else
+ {
+ cout << "No tiles intersected "<< endl;
+ num = 0;
+ }
+ delete rtime;
+
+ // Index 1
+ time1.start( ); rtime1->start( );
+ vector< Tile* >* rqResult1 = ix1->intersect( searchInts[i] );
+ rtime1->stop( ); time1.stop( );
+ if ( rqResult1 )
+ {
+ num1 = rqResult1->size( );
+ cout << index1 << endl << " No. of tiles, time1, time1/noTiles = "
+ << rqResult1->size( ) << " , "<< time1 << " , ";
+ if ( rqResult1->size( ) ) cout << time1.ellapsed_sec( )/rqResult1->size( ) << endl;
+ }
+ else
+ {
+ cout << "No tiles intersected "<< endl;
+ num1 = 0;
+ }
+ delete rtime1;
+ if ( num != num1 )
+ cout << "Error !!!!" << endl;
+
+ // Index
+ cout << "Result " << index << endl;
+ if ( rqResult )
+ {
+ for( int j = 0; j < rqResult->size( ); j++)
+ {
+ cout << ( *rqResult )[j]->getDomain( ) << endl;
+ delete (*rqResult)[j];
+ }
+ delete rqResult;
+ }
+
+ // Index1
+ cout << "Result " << index1 << endl;
+ if ( rqResult1 )
+ {
+ for( int j = 0; j < rqResult1->size( ); j++)
+ {
+ cout << ( *rqResult1 )[j]->getDomain( ) << endl;
+ delete (*rqResult1)[j];
+ }
+ delete rqResult1;
+ }
+ cout << endl;
+ }
+
+}
diff --git a/indexmgr/transdirix.cc b/indexmgr/transdirix.cc
new file mode 100644
index 0000000..60129c3
--- /dev/null
+++ b/indexmgr/transdirix.cc
@@ -0,0 +1,269 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: transdirix.cc
+ *
+ * MODULE: indexmgr
+ * CLASS: TransDirIx
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+static const char rcsid[] = "@(#)transdirix, TransDirIx: $Id: transdirix.cc,v 1.17 2002/05/16 16:26:10 coman Exp $";
+
+#include <iostream>
+#include "indexmgr/keyobject.hh"
+#include "indexmgr/transdirix.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/oidif.hh"
+#include "tilemgr/tile.hh"
+
+IndexDS*
+TransDirIx::getNewInstance() const
+ {
+ return new TransDirIx(getDimension());
+ }
+
+void
+TransDirIx::freeDS()
+ {
+ }
+
+unsigned int
+TransDirIx::getOptimalSize() const
+ {
+ return 1000;
+ }
+
+unsigned int
+TransDirIx::getDimension() const
+ {
+ return currDomain.dimension();
+ }
+
+bool
+TransDirIx::isPersistent() const
+ {
+ return false;
+ }
+
+TransDirIx::TransDirIx(r_Dimension dim)
+ : currDomain(dim),
+ tiles()
+ {
+ RMDBGONCE(2, RMDebug::module_indexif, "TransDirIx", "TransDirIx() " << (r_Ptr)this);
+ }
+
+void
+TransDirIx::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ stream << "TransDirIx " << currDomain << endl;
+ KeyObjectVector::const_iterator entryIt = tiles.begin();
+
+ int i = 0;
+ while (entryIt != tiles.end())
+ {
+ stream << i << ". " << (*entryIt).getDomain() << endl;
+ entryIt++;
+ i++;
+ }
+ }
+
+void
+TransDirIx::insertObject(const KeyObject& newKeyObject, unsigned int pos)
+ {
+ if (pos < 0 || pos > getSize())
+ {
+ RMInit::logOut << "TransDirIx::insertObject(" << newKeyObject << ", " << pos << ") pos out of range" << endl;
+ throw r_Error(TRANSIENT_INDEX_OUT_OF_BOUNDS);
+ }
+ else {
+ if (tiles.size() == 0)
+ currDomain = newKeyObject.getDomain();
+ else
+ currDomain.closure_with(newKeyObject.getDomain());
+ tiles.insert(tiles.begin() + pos, newKeyObject);
+ }
+ }
+
+bool
+TransDirIx::removeObject(const KeyObject& tileToRemove)
+ {
+ bool found = false;
+ for (KeyObjectVector::iterator iter = tiles.begin(); iter != tiles.end(); iter++)
+ {
+ if ((*iter).getTransObject() == tileToRemove.getTransObject())
+ {
+ found = true;
+ tiles.erase(iter);
+ break;
+ }
+ }
+ return found;
+ }
+
+OId::OIdPrimitive
+TransDirIx::getIdentifier() const
+ {
+ return (OId::OIdPrimitive)(r_Ptr)this;
+ }
+
+void
+TransDirIx::setAssignedDomain(const r_Minterval& newDomain)
+ {
+ currDomain = newDomain;
+ }
+
+
+const KeyObject&
+TransDirIx::getObject(unsigned int pos) const
+ {
+ return tiles[pos];
+ }
+
+r_Minterval
+TransDirIx::getObjectDomain(unsigned int pos) const
+ {
+ return tiles[pos].getDomain();
+ }
+
+void
+TransDirIx::getObjects(KeyObjectVector& objs) const
+ {
+ objs = tiles;
+ }
+
+r_Minterval
+TransDirIx::getCoveredDomain() const
+ {
+ return currDomain;
+ }
+
+unsigned int
+TransDirIx::getSize() const
+ {
+ return tiles.size();
+ }
+
+r_Bytes
+TransDirIx::getTotalStorageSize() const
+ {
+ // size of currDomain field:
+ r_Bytes sz = currDomain.get_storage_size();
+
+ // size of tiles vector
+ // even though the size of each entry summed here corresponds to the
+ // KeyObject, it should be added here since it
+ // is "additional data" stored due to the storage structure adopted.
+ // For each entry (tile), there is a domain specification, a pointer and
+ // an r_Bytes size field:
+ sz += tiles.size() * (currDomain.get_storage_size() + sizeof(KeyObject) + sizeof (r_Bytes));
+
+ return sz;
+ }
+
+TransDirIx::~TransDirIx()
+ {
+ RMDBGENTER(2, RMDebug::module_indexif, "TransDirIx", "~TransDirIx() " << (r_Ptr)this);
+ for (unsigned int i = 0; i < tiles.size(); i++)
+ {
+ delete tiles[i].getTransObject();
+ }
+ RMDBGEXIT(2, RMDebug::module_indexif, "TransDirIx", "~TransDirIx() " << (r_Ptr)this);
+ }
+
+std::vector< r_Minterval* >*
+TransDirIx::getObjectDomains(void) const
+ {
+ std::vector< r_Minterval* >* te = new std::vector< r_Minterval* >();
+ te->reserve(tiles.size());
+ int end = tiles.size();
+ for (int i = 0; i < end; i++)
+ {
+ (*te)[i] = new r_Minterval(tiles[i].getDomain());
+ }
+ return te;
+ }
+
+bool
+TransDirIx::isValid() const
+ {
+ return true;
+ }
+
+bool
+TransDirIx::isUnderFull() const
+ {
+ return false;
+ }
+
+bool
+TransDirIx::isOverFull() const
+ {
+ return false;
+ }
+
+bool
+TransDirIx::isSameAs(const IndexDS* ix) const
+ {
+ if (ix->isPersistent())
+ return false;
+ else
+ if (ix == this)
+ return true;
+ else
+ return false;
+ }
+
+void
+TransDirIx::setObject(const KeyObject& theKey, unsigned int i)
+ {
+ tiles[i] = theKey;
+ }
+
+void
+TransDirIx::setObjectDomain(const r_Minterval& dom, unsigned int i)
+ {
+ tiles[i].setDomain(dom);
+ }
+
+r_Minterval
+TransDirIx::getAssignedDomain(void) const
+ {
+ return currDomain;
+ }
+
+bool
+TransDirIx::removeObject(unsigned int pos)
+ {
+ bool found = false;
+ if (pos < tiles.size())
+ {
+ found = true;
+ tiles.erase(tiles.begin() + pos);
+ }
+ return found;
+ }
+
diff --git a/indexmgr/transdirix.hh b/indexmgr/transdirix.hh
new file mode 100644
index 0000000..f5e829d
--- /dev/null
+++ b/indexmgr/transdirix.hh
@@ -0,0 +1,141 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: transdirix.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: TransDirIx
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _TRANSDIRIX_HH_
+#define _TRANSDIRIX_HH_
+
+#include "indexmgr/indexds.hh"
+#include "reladminif/lists.h"
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+A TransDirIx object is the data structure for an index of a transient MDD
+object. It is to be used with DirIndexLogic.
+A transient directory index keeps track of the current domain of the object.
+It is a very simple structure, consisting of the current domain of the object
+and a set of entries, one for each object belonging to the mdd object.
+
+For documentation on methods see IndexDS.
+*/
+
+class TransDirIx : public IndexDS
+ {
+
+ public:
+
+ TransDirIx(r_Dimension dim);
+ /*@Doc:
+ Creates a new transient index for an object with dimensionality
+ {\tt dim}.
+ */
+
+ void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ void insertObject(const KeyObject& newKeyObject, unsigned int pos);
+ /*@Doc:
+ Inserts a new tile in the index at position {\tt pos}, which must be
+ between 0 and {\tt getNumberElems()} (that is, {\tt pos } is
+ interpreted as an index in the new list. If {\tt pos} is getNumberElems(),
+ the element is put at the end of the list. All elements at following
+ positions are shifted to the right. The new tile to insert ({\tt newKeyObject})
+ must be transient (of type TransKeyObject). The current domain is updated.
+ */
+
+ virtual void setObject(const KeyObject& theKey, unsigned int pos);
+
+ virtual void setObjectDomain(const r_Minterval& dom, unsigned int pos);
+
+ bool removeObject(unsigned int pos);
+
+ bool removeObject(const KeyObject& theKey);
+
+ virtual bool isValid() const;
+
+ virtual bool isUnderFull() const;
+
+ virtual bool isOverFull() const;
+
+ virtual bool isSameAs(const IndexDS* pix) const;
+
+ const KeyObject& getObject(unsigned int pos) const;
+
+ r_Minterval getObjectDomain(unsigned int pos) const;
+
+ DomainPVector* getObjectDomains() const;
+
+ void getObjects(KeyObjectVector&) const;
+
+ r_Minterval getCoveredDomain() const;
+
+ r_Minterval getAssignedDomain() const;
+
+ r_Dimension getDimension() const;
+
+ void setAssignedDomain(const r_Minterval& domain);
+
+ unsigned int getSize() const;
+
+ r_Bytes getTotalStorageSize() const;
+
+ bool isPersistent() const;
+
+ virtual ~TransDirIx();
+ /*@Doc:
+ Destructor - deletes tiles from main memory.
+ */
+
+ virtual unsigned int getOptimalSize() const;
+
+ virtual void freeDS();
+ /*@Doc:
+ does not do anything - there is no persistent data structure
+ */
+
+ virtual OId::OIdPrimitive getIdentifier() const;
+
+ virtual IndexDS* getNewInstance() const;
+ private:
+
+ r_Minterval currDomain;
+ /**
+ Always set automatically to the MBR of the tiles in {\tt tiles}.
+ If the number of tiles is zero, the currDomain is invalid (may have any
+ values). All methods dealing with the currDomain must then check whether
+ the object has tiles in order to operate on the currDomain.
+ */
+
+ KeyObjectVector tiles;
+ };
+
+
+#endif