/* \newpage ---- This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //[_] [\_] //characters [1] verbatim: [$] [$] //characters [2] formula: [$] [$] //characters [3] capital: [\textsc{] [}] //characters [4] teletype: [\texttt{] [}] 1.1 Headerfile "GTree[_]Tree.h"[4] January-May 2008, Mirko Dibbert */ #ifndef __GTREE_TREE_H__ #define __GTREE_TREE_H__ #include #include "GTree_Header.h" #include "GTree_FileNode.h" #include "GTree_TreeManager.h" namespace gtree { /* Class ~Tree~ This is the base class for trees. */ template class Tree : public ObjCounter { public: /* Default constructor. */ Tree(bool temporary = false); /* Constructor (reads a previously stored tree from file). */ Tree(SmiFileId fileId); /* Default copy constructor. */ Tree(const Tree& tree); /* Destructor. */ ~Tree(); /* Deletes the tree file. */ inline void deleteFile(); /* Returns the file id of the "SmiRecordFile"[4], that contains the tree. */ inline SmiFileId fileId(); /* Returns the count of all Internal nodes. */ inline unsigned internalCount(); /* Returns the count of all leafes. */ inline unsigned leafCount(); /* Returns the count of all entries, stored in the tree. */ inline unsigned entryCount(); /* Returns the height of the tree. */ inline unsigned height(); /* Returns the count of open general trees. */ inline unsigned openTrees(); /* Returns the count of open general tree nodes. */ inline unsigned openNodes(); /* Returns the count of open general tree entries. */ inline unsigned openEntries(); protected: /* Adds a new protoype node. */ inline void addNodePrototype(NodeBase* node); /* Creates a new node. */ inline NodePtr createNode(NodeTypeId type, unsigned level = 0); /* Creates a new node on the same level as "treeMngr->curNode()"[4]. */ inline NodePtr createNeighbourNode(NodeTypeId type); /* Creates a new node on root level. */ inline NodePtr createRoot(NodeTypeId type); /* Creates a new node on root level and inserts the given entries. */ inline NodePtr createRoot( NodeTypeId type, InternalEntry *e1, InternalEntry *e2); /* Reads the specified node from file. */ inline NodePtr getNode( SmiRecordId nodeId, unsigned level = 0) const; /* Method initPath (initiates a new tree manager path from root) */ inline void initPath(SmiRecordId root, int level); /* Method initPath (initiates a new tree manager path from header.root) */ inline void initPath(); private: /* Reads the header from "file"[4]. */ void readHeader(); /* Writes the header to "file"[4]. */ void writeHeader(); protected: THeader header; // contains the header of the tree file SmiRecordFile file; // contais the tree file private: bool temporary; /* true, if the file should be dropped when the tree is deleted. */ unsigned headerPageCount; // count of header pages protected: NodeManager* nodeMngr; /* reference to the tree file and the node prototypes */ TTreeManager* treeMngr; // reference to the tree manager }; // class Tree ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* Tree constructor (new file): */ template gtree::Tree::Tree(bool _temporary) : header(), file(true, PAGESIZE), temporary(_temporary), nodeMngr(new NodeManager(&file)), treeMngr(new TTreeManager(nodeMngr)) { #ifdef __GTREE_DEBUG Msg::showDbgMsg(); #endif file.Create(); // create header page(s), compute headerPageCount SmiRecordId headerId; SmiRecord headerRecord; headerPageCount = 0; while (sizeof(THeader) > headerPageCount*PAGESIZE) { ++headerPageCount; file.AppendRecord(headerId, headerRecord); assert(headerId == headerPageCount); } } /* Tree constructor (reads from file): */ template gtree::Tree::Tree(SmiFileId fileId) : header(), file(true), temporary(false), nodeMngr(new NodeManager(&file)), treeMngr(new TTreeManager(nodeMngr)) { #ifdef __GTREE_DEBUG Msg::showDbgMsg(); #endif bool t1 = file.Open(fileId); assert(t1); // compute headerPageCount headerPageCount = 0; while (sizeof(THeader) > headerPageCount*PAGESIZE) ++headerPageCount; readHeader(); } /* Tree copy constructor: */ template gtree::Tree::Tree( const Tree& tree) : file(true, PAGESIZE), temporary(tree.temporary), nodeMngr(new NodeManager(&file)), treeMngr(new TTreeManager(nodeMngr)) { #ifdef __GTREE_DEBUG Msg::showDbgMsg(); #endif file.Create(); // create header page(s), compute headerPageCount SmiRecordId headerId; SmiRecord headerRecord; headerPageCount = 0; while (sizeof(THeader) > headerPageCount*PAGESIZE) { ++headerPageCount; file.AppendRecord(headerId, headerRecord); assert(headerId == headerPageCount); } // copy header memcpy((void*)&header, &tree.header, sizeof(THeader)); nodeMngr->copyPrototypes(tree.nodeMngr); // disable node cache, while copying the tree structure treeMngr->disableCache(); std::stack > remaining; std::stack indizes; unsigned curIndex = 0; // read tree root and create new root NodePtr source = tree.getNode(tree.header.root); NodePtr target = createNode(source->typeId()); header.root = target->getNodeId(); // copy tree structure (copies the tree node by node and updates // the chield node pointers, needs enough memory to hold // header.height nodes open at one time) if (source->isLeaf()) { for (unsigned i = 0; i < source->entryCount(); ++i) target->insertCopy(source->baseEntry(i)); } else { NodePtr chield = tree.getNode(source->chield(curIndex)); NodePtr newChield = createNode(chield->typeId()); target->insertCopy(source->baseEntry(curIndex)); static_cast(target->baseEntry(curIndex))-> setChield(newChield); // push current node to stack, if // further entries are remaining if (++curIndex < source->entryCount()) { remaining.push(std::pair(source, target)); indizes.push(curIndex); } // push chield node to stack remaining.push(std::pair(chield, newChield)); indizes.push(0); } while (!remaining.empty()) { source = remaining.top().first; target = remaining.top().second; curIndex = indizes.top(); remaining.pop(); indizes.pop(); if (source->isLeaf()) { for (unsigned i = 0; i < source->entryCount(); ++i) target->insertCopy(source->baseEntry(i)); } else { NodePtr chield = tree.getNode(source->chield(curIndex)); NodePtr newChield = createNode(chield->typeId()); target->insertCopy(source->baseEntry(curIndex)); static_cast(target-> baseEntry(curIndex))->setChield(newChield); // push current node to stack, if // further entries are remaining if (++curIndex < source->entryCount()) { remaining.push( std::pair(source, target)); indizes.push(curIndex); } // push chield node to stack remaining.push( std::pair(chield, newChield)); indizes.push(0); } } treeMngr->enableCache(); } // tree copy constructor /* Tree destructor: */ template gtree::Tree::~Tree() { delete treeMngr; delete nodeMngr; if (temporary) deleteFile(); if (file.IsOpen()) { writeHeader(); file.Close(); } #ifdef __GTREE_DEBUG /* print count of open objects only for the last remaining tree (otherwhise the warning message would appear allways, if more than one tree exists, e.g. when calling the copy constructor)*/ if (openTrees() == 1) { if (openNodes()) Msg::memoryLeak_Warning(openNodes(), "nodes"); if (openEntries()) Msg::memoryLeak_Warning(openEntries(), "entries"); } #endif } // Tree destructor /* Method ~readHeader~: */ template void gtree::Tree::readHeader() { // create buffer char buffer[headerPageCount*PAGESIZE]; memset(buffer, 0, headerPageCount*PAGESIZE); // read header-data from file SmiRecord record; SmiRecordId curPage = 1; for (unsigned i = 0; i < headerPageCount; ++i) { file.SelectRecord(curPage, record, SmiFile::ReadOnly); record.Read(buffer + (i*PAGESIZE), PAGESIZE, 0); ++curPage; } // copy buffer to header memcpy((void*)&header, buffer, sizeof(THeader)); } // Tree::readHeader /* Method ~writeHeader~: */ template void gtree::Tree::writeHeader() { // create buffer and copy header to buffer char buffer[headerPageCount*PAGESIZE]; memset(buffer, 0, headerPageCount*PAGESIZE); memcpy(buffer, &header, sizeof(THeader)); // write header-data to file SmiRecord record; SmiRecordId curPage = 1; for (unsigned i = 0; i < headerPageCount; ++i) { file.SelectRecord(curPage, record, SmiFile::Update); record.Write(buffer + (i*PAGESIZE), PAGESIZE, 0); ++curPage; } } // Tree::writeHeader /* Method ~deleteFile~: */ template void gtree::Tree::deleteFile() { if (file.IsOpen()) file.Close(); file.Drop(); } /* Method ~fileId~: */ template SmiFileId gtree::Tree::fileId() { return file.GetFileId(); } /* Method ~internalCount~: */ template unsigned gtree::Tree::internalCount() { return header.internalCount; } /* Method ~leafCount~: */ template unsigned gtree::Tree::leafCount() { return header.leafCount; } /* Method ~entryCount~: */ template unsigned gtree::Tree::entryCount() { return header.entryCount; } /* Method ~height~: */ template unsigned gtree::Tree::height() { return header.height; } /* Method ~openTrees~: */ template unsigned gtree::Tree::openTrees() { return ObjCounter::openObjects(); } /* Method ~openNodes~: */ template unsigned gtree::Tree::openNodes() { return ObjCounter::openObjects(); } /* Method ~openEntries~: */ template unsigned gtree::Tree::openEntries() { return ObjCounter::openObjects(); } /* Method ~addNodePrototype~: */ template void gtree::Tree::addNodePrototype( NodeBase* node) { nodeMngr->addPrototype(node); } /* Method ~createNode~: */ template NodePtr gtree::Tree:: createNode(NodeTypeId type, unsigned level /* = 0 */) { if (level == 0) ++header.leafCount; else ++header.internalCount; return treeMngr->createNode(type, level); } /* Method ~createNeighbourNode~: */ template NodePtr gtree::Tree:: createNeighbourNode(NodeTypeId type) { if (treeMngr->curNode()->isLeaf()) ++header.leafCount; else ++header.internalCount; return treeMngr->createNeighbourNode(type); } /* Method ~createRoot~: */ template NodePtr gtree::Tree::createRoot( NodeTypeId type) { NodePtr root(treeMngr->createNode(type, header.height)); header.root = root->getNodeId(); if (header.height == 0) { ++header.leafCount; } else { ++header.internalCount; } ++header.height; return root; } /* Method ~createRoot~: */ template NodePtr gtree::Tree::createRoot( NodeTypeId type, InternalEntry *e1, InternalEntry *e2) { NodePtr root(treeMngr->createNode(type, header.height)); treeMngr->insert(root, e1); treeMngr->insert(root, e2); header.root = root->getNodeId(); ++header.height; ++header.internalCount; return root; } /* Method ~getNode~: */ template NodePtr gtree::Tree:: getNode( SmiRecordId nodeId, unsigned level) const { return treeMngr->getNode(nodeId, level); } /* Method initPath: */ template void gtree::Tree::initPath( SmiRecordId root, int level) { treeMngr->initPath(root, level); } /* Method initPath: */ template void gtree::Tree::initPath() { treeMngr->initPath(header.root, header.height-1); } } // namespace gtree #endif // #define __GTREE_TREE_H__