/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: stortree.cxx,v $ * $Revision: 1.8 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org 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 Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_store.hxx" #define _STORE_STORTREE_CXX "$Revision: 1.8 $" #include #include #include #include #include #include #ifndef _STORE_STORBASE_HXX #include #endif #include using namespace store; /*======================================================================== * * OStoreBTreeNodeData implementation. * *======================================================================*/ /* * OStoreBTreeNodeData. */ OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize) : OStorePageData (nPageSize) { initialize(); } /* * initialize. */ void OStoreBTreeNodeData::initialize (void) { base::m_aGuard.m_nMagic = STORE_MAGIC_BTREENODE; base::m_aDescr.m_nUsed = base::size() + self::size(); self::m_aGuard.m_nMagic = 0; sal_uInt16 i, n = capacityCount(); T t; for (i = 1; i < n; i++) m_pData[i] = t; } /* * swap. */ void OStoreBTreeNodeData::swap ( const D& #ifdef OSL_BIGENDIAN rDescr #endif /* OSL_BIGENDIAN */ ) { #ifdef OSL_BIGENDIAN m_aGuard.swap(); sal_uInt16 i, n = sal_uInt16(capacity(rDescr) / sizeof(T)); for (i = 0; i < n; i++) m_pData[i].swap(); #endif /* OSL_BIGENDIAN */ } /* * find. */ sal_uInt16 OStoreBTreeNodeData::find (const T& t) const { register sal_Int32 l = 0; register sal_Int32 r = usageCount() - 1; while (l < r) { register sal_Int32 m = ((l + r) >> 1); if (t.m_aKey == m_pData[m].m_aKey) return ((sal_uInt16)(m)); if (t.m_aKey < m_pData[m].m_aKey) r = m - 1; else l = m + 1; } sal_uInt16 k = ((sal_uInt16)(r)); if ((k < capacityCount()) && (t.m_aKey < m_pData[k].m_aKey)) return(k - 1); else return(k); } /* * insert. */ void OStoreBTreeNodeData::insert (sal_uInt16 i, const T& t) { sal_uInt16 n = usageCount(); sal_uInt16 m = capacityCount(); if ((n < m) && (i < m)) { // shift right. rtl_moveMemory (&m_pData[i + 1], &m_pData[i], (n - i) * sizeof(T)); // insert. m_pData[i] = t; base::m_aDescr.m_nUsed += sal_uInt16(sizeof(T)); } } /* * remove. */ void OStoreBTreeNodeData::remove (sal_uInt16 i) { sal_uInt16 n = usageCount(); if (i < n) { // shift left. rtl_moveMemory ( &m_pData[i], &m_pData[i + 1], (n - i - 1) * sizeof(T)); // truncate. m_pData[n - 1] = T(); base::m_aDescr.m_nUsed -= sal_uInt16(sizeof(T)); } } /* * merge. */ void OStoreBTreeNodeData::merge (const self& rPageR) { if (queryMerge (rPageR)) { sal_uInt16 n = usageCount(); sal_uInt16 m = rPageR.usageCount(); rtl_copyMemory (&m_pData[n], &rPageR.m_pData[0], m * sizeof(T)); usageCount (n + m); } } /* * split. */ void OStoreBTreeNodeData::split (const self& rPageL) { sal_uInt16 h = capacityCount() / 2; rtl_copyMemory (&m_pData[0], &rPageL.m_pData[h], h * sizeof(T)); truncate (h); } /* * truncate. */ void OStoreBTreeNodeData::truncate (sal_uInt16 n) { sal_uInt16 m = capacityCount(); T t; for (sal_uInt16 i = n; i < m; i++) m_pData[i] = t; usageCount (n); } /*======================================================================== * * OStoreBTreeNodeObject implementation. * *======================================================================*/ /* * swap. */ void OStoreBTreeNodeObject::swap ( const D& #ifdef OSL_BIGENDIAN rDescr #endif /* OSL_BIGENDIAN */ ) { #ifdef OSL_BIGENDIAN base::swap (rDescr); m_rPage.swap (rDescr); #endif /* OSL_BIGENDIAN */ } /* * guard. */ void OStoreBTreeNodeObject::guard (const D& rDescr) { base::guard (rDescr); m_rPage.guard (rDescr); } /* * verify. */ storeError OStoreBTreeNodeObject::verify (const D& rDescr) { storeError eErrCode = base::verify (rDescr); if (eErrCode != store_E_None) return eErrCode; else return m_rPage.verify (rDescr); } /* * split. */ storeError OStoreBTreeNodeObject::split ( sal_uInt16 nIndexL, OStoreBTreeNodeData &rPageL, OStoreBTreeNodeData &rPageR, OStorePageBIOS &rBIOS, osl::Mutex *pMutex) { // Check usage. if (!rPageL.querySplit()) return store_E_None; // Enter. STORE_METHOD_ENTER(pMutex); // Save PageDescriptor. D aDescr (m_rPage.m_aDescr); // Acquire Lock. storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); if (eErrCode != store_E_None) STORE_METHOD_LEAVE(pMutex, eErrCode); // Begin PageL Lock (NYI). // Split right page off left page. rPageR.split (rPageL); rPageR.depth (rPageL.depth()); // Allocate right page. self aNodeR (rPageR); eErrCode = rBIOS.allocate (aNodeR); if (eErrCode != store_E_None) { rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } // Truncate left page. rPageL.truncate (rPageL.capacityCount() / 2); // Save left page. self aNodeL (rPageL); eErrCode = rBIOS.save (aNodeL); if (eErrCode != store_E_None) { // Must not happen. OSL_TRACE("OStoreBTreeNodeObject::split(): save() failed"); // Release Lock and Leave. rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } // End PageL Lock (NYI). // Insert right page. T entry; entry.m_aKey = rPageR.m_pData[0].m_aKey; entry.m_aLink.m_nAddr = rPageR.location(); m_rPage.insert (nIndexL + 1, entry); // Save this page. eErrCode = rBIOS.save (*this); if (eErrCode != store_E_None) { // Must not happen. OSL_TRACE("OStoreBTreeNodeObject::split(): save() failed"); // Release Lock and Leave. rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } #if 0 /* PERFORMANCE */ eErrCode = rBIOS.flush(); #endif /* PERFORMANCE */ // Release Lock and Leave. eErrCode = rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } /* * remove (down to leaf node, recursive). */ storeError OStoreBTreeNodeObject::remove ( sal_uInt16 nIndexL, OStoreBTreeEntry &rEntryL, OStoreBTreeNodeData &rPageL, #if 0 /* NYI */ OStoreBTreeNodeData &rPageR, #endif /* NYI */ OStorePageBIOS &rBIOS, osl::Mutex *pMutex) { // Enter. STORE_METHOD_ENTER(pMutex); // Save PageDescriptor. D aDescr (m_rPage.m_aDescr); // Acquire Lock. storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); if (eErrCode != store_E_None) STORE_METHOD_LEAVE(pMutex, eErrCode); // Check depth. if (m_rPage.depth()) { // Check link entry. if (!(rEntryL.compare (m_rPage.m_pData[nIndexL]) == T::COMPARE_EQUAL)) { rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, store_E_InvalidAccess); } // Load link node. self aNodeL (rPageL); aNodeL.location (m_rPage.m_pData[nIndexL].m_aLink.m_nAddr); eErrCode = rBIOS.load (aNodeL); if (eErrCode != store_E_None) { rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } // Remove from link node (using current page as link buffer). eErrCode = aNodeL.remove (0, rEntryL, m_rPage, rBIOS, NULL); if (eErrCode != store_E_None) { rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } // Reload current page. m_rPage.location (aDescr.m_nAddr); eErrCode = rBIOS.load (*this); if (eErrCode != store_E_None) { // Must not happen. OSL_TRACE("OStoreBTreeNodeObject::remove(): load() failed"); // Release Lock and Leave. rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } // Check link node usage. if (rPageL.usageCount() == 0) { // Free empty link node. eErrCode = rBIOS.free (aNodeL); if (eErrCode != store_E_None) { rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } // Remove index. m_rPage.remove (nIndexL); touch(); } else { #if 0 /* NYI */ // Check for right sibling. sal_uInt16 nIndexR = nIndexL + 1; if (nIndexR < m_rPage.usageCount()) { // Load right link node. self aNodeR (rPageR); aNodeR.location (m_rPage.m_pData[nIndexR].m_aLink.m_nAddr); eErrCode = rBIOS.load (aNodeR); if (eErrCode == store_E_None) { if (rPageL.queryMerge (rPageR)) { rPageL.merge (rPageR); eErrCode = rBIOS.free (rPageR); } } } #endif /* NYI */ // Relink. m_rPage.m_pData[nIndexL].m_aKey = rPageL.m_pData[0].m_aKey; touch(); } } else { // Check leaf entry. if (!(rEntryL.compare (m_rPage.m_pData[nIndexL]) == T::COMPARE_EQUAL)) { rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, store_E_NotExists); } // Save leaf entry. rEntryL = m_rPage.m_pData[nIndexL]; // Remove leaf index. m_rPage.remove (nIndexL); touch(); } // Check for modified node. if (dirty()) { // Save this page. eErrCode = rBIOS.save (*this); if (eErrCode != store_E_None) { // Must not happen. OSL_TRACE("OStoreBTreeNodeObject::remove(): save() failed"); // Release Lock and Leave. rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } } // Release Lock and Leave. eErrCode = rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } /*======================================================================== * * OStoreBTreeRootObject implementation. * *======================================================================*/ /* * change. */ storeError OStoreBTreeRootObject::change ( OStoreBTreeNodeData &rPageL, OStorePageBIOS &rBIOS, osl::Mutex *pMutex) { // Enter. STORE_METHOD_ENTER(pMutex); // Save PageDescriptor. OStorePageDescriptor aDescr (m_rPage.m_aDescr); // Acquire Lock. storeError eErrCode = rBIOS.acquireLock (aDescr.m_nAddr, aDescr.m_nSize); if (eErrCode != store_E_None) STORE_METHOD_LEAVE(pMutex, eErrCode); // Change root. rPageL = m_rPage; base aNodeL (rPageL); eErrCode = rBIOS.allocate (aNodeL); if (eErrCode != store_E_None) { // Release Lock and Leave. rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } m_rPage.m_pData[0].m_aKey = rPageL.m_pData[0].m_aKey; m_rPage.m_pData[0].m_aLink.m_nAddr = rPageL.location(); m_rPage.truncate (1); m_rPage.depth (m_rPage.depth() + 1); // Save root. eErrCode = rBIOS.save (*this); if (eErrCode != store_E_None) { // Must not happen. OSL_TRACE("OStoreBTreeRootObject::change(): save() failed"); // Release Lock and Leave. rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } #if 1 /* ROBUSTNESS */ eErrCode = rBIOS.flush(); #endif /* ROBUSTNESS */ // Done. Release Lock and Leave. eErrCode = rBIOS.releaseLock (aDescr.m_nAddr, aDescr.m_nSize); STORE_METHOD_LEAVE(pMutex, eErrCode); } /* * split. */ storeError OStoreBTreeRootObject::split ( sal_uInt16, OStoreBTreeNodeData &rPageL, OStoreBTreeNodeData &rPageR, OStorePageBIOS &rBIOS, osl::Mutex *pMutex) { // Check usage. if (!querySplit()) return store_E_None; // Enter. STORE_METHOD_ENTER(pMutex); // Change root. storeError eErrCode = change (rPageL, rBIOS, NULL); if (eErrCode != store_E_None) STORE_METHOD_LEAVE(pMutex, eErrCode); // Split Left Page. eErrCode = base::split (0, rPageL, rPageR, rBIOS, NULL); // Leave. STORE_METHOD_LEAVE(pMutex, eErrCode); }