BTreeReaderImpl.h

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/btree/BTreeReaderImpl.h#17 $
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 #ifndef Fennel_BTreeReaderImpl_Included
00025 #define Fennel_BTreeReaderImpl_Included
00026 
00027 #include "fennel/btree/BTreeReader.h"
00028 
00029 FENNEL_BEGIN_NAMESPACE
00030 
00031 inline TupleData const &BTreeReader::getSearchKey()
00032 {
00033     assert(pSearchKey);
00034     return *pSearchKey;
00035 }
00036 
00037 inline uint BTreeReader::binarySearch(
00038     BTreeNode const &node,
00039     DuplicateSeek dupSeek,
00040     bool leastUpper,
00041     bool &found)
00042 {
00043     return getNodeAccessor(node).binarySearch(
00044         node,
00045         keyDescriptor,
00046         getSearchKey(),
00047         dupSeek,
00048         leastUpper,
00049         comparisonKeyData,
00050         found);
00051 }
00052 
00053 inline bool BTreeReader::adjustRootLockMode(LockMode &lockMode)
00054 {
00055     if (lockMode == leafLockMode) {
00056         // We already got the correct lock mode.
00057         return true;
00058     }
00059 
00060     // Oops, we got the wrong lock mode.  Next time we'll get it right.
00061     rootLockMode = leafLockMode;
00062     lockMode = leafLockMode;
00063 
00064     // We can try an upgrade.  If it succeeds, great.  Otherwise, it will fail
00065     // immediately so we can do it the hard way.
00066     if (pageLock.tryUpgrade()) {
00067         return true;
00068     }
00069 
00070     // Shucks, have to unlock and retry original operation.
00071     pageLock.unlock();
00072     return false;
00073 }
00074 
00075 inline int BTreeReader::compareFirstKey(BTreeNode const &node)
00076 {
00077     return getNodeAccessor(node).compareFirstKey(
00078         node,
00079         keyDescriptor,
00080         getSearchKey(),
00081         comparisonKeyData);
00082 }
00083 
00084 inline void BTreeReader::accessTupleInline(BTreeNode const &node, uint iEntry)
00085 {
00086     getNodeAccessor(node).accessTupleInline(node, iEntry);
00087 }
00088 
00089 inline void BTreeReader::accessLeafTuple()
00090 {
00091     BTreeNode const &node = pageLock.getNodeForRead();
00092     getLeafNodeAccessor(node).accessTuple(node,iTupleOnLowestLevel);
00093 }
00094 
00095 template <bool leafLockCoupling,class PageStack>
00096 inline bool BTreeReader::searchForKeyTemplate(
00097     TupleData const &key, DuplicateSeek dupSeek, bool leastUpper,
00098     PageStack &pageStack, PageId startPageId, LockMode initialLockMode,
00099     ReadMode readMode)
00100 {
00101     pSearchKey = &key;
00102 
00103     // At each level, we may have to search right due to splits.  To bound
00104     // this search, we record the parent's notion of the PageId for the
00105     // right sibling of the child page.  Lehman-Yao uses keys instead, but
00106     // PageId should work as well?
00107     PageId rightSearchTerminator = NULL_PAGE_ID;
00108     pageId = startPageId;
00109     LockMode lockMode = initialLockMode;
00110     bool lockCoupling = false;
00111     bool foundKeyAndMovedRight = false;
00112     for (;;) {
00113         if (leafLockCoupling && lockCoupling) {
00114             pageLock.lockPageWithCoupling(pageId,lockMode);
00115         } else {
00116             pageLock.lockPage(pageId,lockMode);
00117         }
00118 
00119         BTreeNode const *pNode = &(pageLock.getNodeForRead());
00120 
00121         // TODO:  pull this out of loop
00122         if (!pNode->height && !adjustRootLockMode(lockMode)) {
00123             // Retry with correct lock mode
00124             continue;
00125         }
00126 
00127         bool found;
00128         uint iKeyBound = binarySearch(*pNode,dupSeek,leastUpper,found);
00129         if (foundKeyAndMovedRight && !found) {
00130             // if we previously located our desired key on the page to
00131             // the left of this one and had to search to the right because
00132             // we're doing a DUP_SEEK_END search, but the key doesn't
00133             // exist on the current page, then we should revert back to the
00134             // prior "found" status, since we did find the key
00135             assert(iKeyBound == 0);
00136             found = true;
00137         }
00138 
00139         // if we're searching for the greatest lower bound, we didn't
00140         // find an exact match, and we're positioned at the rightmost
00141         // key entry, need to search the first key in the right sibling
00142         // to be sure we have the correct glb
00143         if (!leastUpper && !found && iKeyBound == pNode->nEntries - 1 &&
00144             pNode->rightSibling != NULL_PAGE_ID)
00145         {
00146             // not currently handling leaf lock coupling for reads,
00147             // which is the only time we're searching for glb
00148             assert(leafLockCoupling == false);
00149 
00150             PageId siblingPageId = pNode->rightSibling;
00151             pageLock.unlock();
00152             pageLock.lockPage(siblingPageId, lockMode);
00153             BTreeNode const &rightNode = pageLock.getNodeForRead();
00154             int res = compareFirstKey(rightNode);
00155 
00156             pageLock.unlock();
00157             if (res < 0) {
00158                 // stick with the current node, so go back and relock it
00159                 // and reset the tuple accessor back to the prior key
00160                 //
00161                 // FIXME zfong 7-Dec-2005: Need to handle case where a
00162                 // node split has occurred since the current node was
00163                 // unlocked.  To do so, need to search starting at the
00164                 // current node and continue searching right until you
00165                 // find a node whose right sibling is equal to the
00166                 // original right sibling.  The key we want should then
00167                 // be the last entry on that node.
00168                 pageLock.lockPage(pageId, lockMode);
00169                 pNode = &(pageLock.getNodeForRead());
00170                 accessTupleInline(*pNode, iKeyBound);
00171             } else {
00172                 // switch over to the right sibling, unless we're only
00173                 // searching a single leaf page
00174                 if (readMode == READ_LEAF_ONLY) {
00175                     assert(rightNode.height == 0);
00176                     // need to relock the original page and position to the
00177                     // last key on the page
00178                     pageLock.lockPage(pageId, lockMode);
00179                     iTupleOnLowestLevel = iKeyBound;
00180                     return false;
00181                 }
00182                 pageId = siblingPageId;
00183                 foundKeyAndMovedRight = false;
00184                 continue;
00185             }
00186         }
00187 
00188         if (iKeyBound == pNode->nEntries) {
00189             assert(!found || (dupSeek == DUP_SEEK_END));
00190             // What we're searching for is bigger than everything on
00191             // this node.
00192             if (pNode->rightSibling == rightSearchTerminator) {
00193                 // No need to search rightward.  This should only
00194                 // happen at the leaf level (since we never delete keys from
00195                 // nodes, the upper bound should match at parent and child
00196                 // levels.)
00197                 assert(!pNode->height);
00198                 if (rightSearchTerminator == NULL_PAGE_ID) {
00199                     singular = true;
00200                 }
00201             } else {
00202                 // have to search right
00203                 foundKeyAndMovedRight = found;
00204                 pageId = pNode->rightSibling;
00205                 if (leafLockCoupling && !pNode->height) {
00206                     lockCoupling = true;
00207                 }
00208                 continue;
00209             }
00210         }
00211 
00212         switch (pNode->height) {
00213         case 0:
00214             // at leaf level
00215             iTupleOnLowestLevel = iKeyBound;
00216             return found;
00217 
00218         case 1:
00219             if (readMode == READ_NONLEAF_ONLY) {
00220                 iTupleOnLowestLevel = iKeyBound;
00221                 return found;
00222             }
00223             // prepare to hit rock bottom
00224             lockMode = leafLockMode;
00225             break;
00226         }
00227 
00228         // leave a trail of breadcrumbs
00229         pageStack.push_back(pageId);
00230 
00231         // we'll continue search on child
00232         pageId = getChildForCurrent();
00233         foundKeyAndMovedRight = false;
00234 
00235         // Record the successor child as a terminator for rightward
00236         // searches once we descend to the child level, unless we're doing
00237         // a partial key search or a DUP_SEEK_END search.  In those
00238         // exception cases, when the last key value in a parent does not
00239         // exist in the leaf, we have to continue reading to the right.
00240         // That condition occurs if the last key was deleted from the leaf.
00241         // Because we didn't make a corresponding update in the parent node,
00242         // we find a match in the parent, but not the leaf.
00243         if ((*pSearchKey).size() == keyDescriptor.size() &&
00244             dupSeek != DUP_SEEK_END)
00245         {
00246             if (iKeyBound < (pNode->nEntries - 1)) {
00247                 rightSearchTerminator = getChild(*pNode,iKeyBound + 1);
00248             } else {
00249                 // have to consult our own sibling to find the successor
00250                 // child
00251                 // need to get the pageId first, then unlock.
00252                 PageId rightSiblingPageId = pNode->rightSibling;
00253                 pageLock.unlock();
00254                 rightSearchTerminator = getFirstChild(rightSiblingPageId);
00255             }
00256         }
00257     }
00258 }
00259 
00260 FENNEL_END_NAMESPACE
00261 
00262 #endif
00263 
00264 // End BTreeReaderImpl.h

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