BTreeVerifier.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/btree/BTreeVerifier.cpp#15 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2005-2009 SQLstream, Inc.
00006 // Copyright (C) 2005-2009 LucidEra, Inc.
00007 // Portions Copyright (C) 1999-2009 John V. Sichi
00008 //
00009 // This program is free software; you can redistribute it and/or modify it
00010 // under the terms of the GNU General Public License as published by the Free
00011 // Software Foundation; either version 2 of the License, or (at your option)
00012 // any later version approved by The Eigenbase Project.
00013 //
00014 // This program is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with this program; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 #include "fennel/common/CommonPreamble.h"
00025 #include "fennel/btree/BTreeVerifier.h"
00026 #include "fennel/btree/BTreeAccessBaseImpl.h"
00027 
00028 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/btree/BTreeVerifier.cpp#15 $");
00029 
00030 // TODO:  change asserts to proper excns
00031 
00032 BTreeVerifier::BTreeVerifier(BTreeDescriptor const &descriptor)
00033     : BTreeAccessBase(descriptor)
00034 {
00035     permAssert(getRootPageId() != NULL_PAGE_ID);
00036     keyData.compute(keyDescriptor);
00037     keyData2 = keyData;
00038 }
00039 
00040 BTreeVerifier::~BTreeVerifier()
00041 {
00042 }
00043 
00044 void BTreeVerifier::verify(bool strictInit, bool keysInit, bool leafInit)
00045 {
00046     strict = strictInit;
00047     keys = keysInit;
00048     leaf = leafInit;
00049     lowerBoundKey.clear();
00050     upperBoundKey.clear();
00051     stats.nLevels = MAXU;
00052     stats.nNonLeafNodes = 0;
00053     stats.nLeafNodes = 0;
00054     stats.nTuples = 0;
00055     stats.nUniqueKeys = 0;
00056     PageId pageId = getRootPageId();
00057     do {
00058         expectedRightSibling = NULL_PAGE_ID;
00059         if (isMAXU(stats.nLevels)) {
00060             expectedHeight = MAXU;
00061         } else {
00062             expectedHeight = stats.nLevels - 1;
00063         }
00064         pageId = verifyNode(pageId);
00065     } while (pageId != NULL_PAGE_ID);
00066 }
00067 
00068 // TODO:  guard against cyclic sibling links
00069 
00070 PageId BTreeVerifier::verifyNode(
00071     PageId pageId)
00072 {
00073     BTreePageLock pageLock;
00074     pageLock.accessSegment(treeDescriptor.segmentAccessor);
00075     pageLock.lockShared(pageId);
00076     BTreeNode const &node = pageLock.getNodeForRead();
00077     PageId returnPageId = NULL_PAGE_ID;
00078 
00079     // for optimized build, we don't check node magic numbers implicitly,
00080     // so do it explicitly here
00081     permAssert(node.magicNumber == BTreeNode::MAGIC_NUMBER);
00082 
00083     if (isMAXU(expectedHeight)) {
00084         stats.nLevels = node.height + 1;
00085     } else {
00086         permAssert(node.height == expectedHeight);
00087     }
00088 
00089     if (strict) {
00090         permAssert(node.rightSibling == getRightSibling(pageId));
00091         permAssert(node.rightSibling == expectedRightSibling);
00092     } else {
00093         if (node.rightSibling != expectedRightSibling) {
00094             permAssert(node.rightSibling != NULL_PAGE_ID);
00095             returnPageId = node.rightSibling;
00096         }
00097     }
00098 
00099     BTreeNodeAccessor &nodeAccessor = getNodeAccessor(node);
00100 
00101     // TODO:  delegate to nodeAccessor for checking node integrity
00102 
00103     // verify key ordering, including lower bound
00104     if (keys) {
00105         bool countUniqueKeys = (node.height == 0);
00106         keyData = lowerBoundKey;
00107         uint nKeys = nodeAccessor.getKeyCount(node);
00108         for (uint i = 0; i < nKeys; ++i) {
00109             nodeAccessor.accessTuple(node,i);
00110             nodeAccessor.unmarshalKey(keyData2);
00111             if (keyData.size()) {
00112                 int c = keyDescriptor.compareTuples(keyData,keyData2);
00113 
00114                 // TODO:  move this somewhere else
00115                 if (c > 0) {
00116                     nodeAccessor.dumpNode(std::cerr,node,pageId);
00117                 }
00118                 permAssert(c <= 0);
00119                 // TODO:  for unique, assert(c == 0)
00120 
00121                 if (countUniqueKeys && c == -1) {
00122                     // Only count differences in the first column of the key.
00123                     stats.nUniqueKeys++;
00124                 }
00125             } else if (countUniqueKeys) {
00126                 stats.nUniqueKeys++;
00127             }
00128             keyData = keyData2;
00129         }
00130     }
00131 
00132     // verify upper bound (using last key left over from previous loop)
00133     if (keyData.size() && upperBoundKey.size()) {
00134         keyData2 = upperBoundKey;
00135         int c = keyDescriptor.compareTuples(keyData,keyData2);
00136         permAssert(c <= 0);
00137     }
00138     if (node.height) {
00139         stats.nNonLeafNodes++;
00140         verifyChildren(node);
00141     } else {
00142         stats.nLeafNodes++;
00143         stats.nTuples += node.nEntries;
00144     }
00145     return returnPageId;
00146 }
00147 
00148 void BTreeVerifier::verifyChildren(BTreeNode const &node)
00149 {
00150     // skip over leaf nodes if we are not traversing them
00151     if (node.height == 1 && !leaf) {
00152         stats.nLeafNodes += node.nEntries;
00153         return;
00154     }
00155 
00156     BTreeNodeAccessor &nodeAccessor = getNodeAccessor(node);
00157     for (uint i = 0; i < node.nEntries; ++i) {
00158         PageId nextChildPageId;
00159         if (i + 1 < node.nEntries) {
00160             nextChildPageId = getChild(node,i + 1);
00161         } else {
00162             nextChildPageId = getFirstChild(node.rightSibling);
00163         }
00164         PageId childPageId = getChild(node,i);
00165         do {
00166             expectedRightSibling = nextChildPageId;
00167             expectedHeight = node.height - 1;
00168             nodeAccessor.accessTuple(node,i);
00169             nodeAccessor.unmarshalKey(keyData);
00170             if (nextChildPageId == NULL_PAGE_ID) {
00171                 // pretend last key is +infinity
00172                 upperBoundKey.clear();
00173             } else {
00174                 upperBoundKey = keyData;
00175             }
00176             childPageId = verifyNode(childPageId);
00177         } while (childPageId != NULL_PAGE_ID);
00178         nodeAccessor.accessTuple(node,i);
00179         nodeAccessor.unmarshalKey(keyData);
00180         lowerBoundKey = keyData;
00181     }
00182 }
00183 
00184 BTreeStatistics const &BTreeVerifier::getStatistics()
00185 {
00186     return stats;
00187 }
00188 
00189 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/btree/BTreeVerifier.cpp#15 $");
00190 
00191 // End BTreeVerifier.cpp

Generated on Mon Jun 22 04:00:13 2009 for Fennel by  doxygen 1.5.1