270061398c
2008/04/01 15:42:44 thb 1.7.38.3: #i85898# Stripping all external header guards 2008/04/01 12:41:55 thb 1.7.38.2: #i85898# Stripping all external header guards 2008/03/31 15:27:47 rt 1.7.38.1: #i87441# Change license header to LPGL v3.
565 lines
14 KiB
C++
565 lines
14 KiB
C++
/*************************************************************************
|
|
*
|
|
* 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
|
|
* <http://www.openoffice.org/license.html>
|
|
* 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 <sal/types.h>
|
|
#include <rtl/memory.h>
|
|
#include <osl/diagnose.h>
|
|
#include <osl/endian.h>
|
|
#include <osl/mutex.hxx>
|
|
#include <store/types.h>
|
|
|
|
#ifndef _STORE_STORBASE_HXX
|
|
#include <storbase.hxx>
|
|
#endif
|
|
#include <stortree.hxx>
|
|
|
|
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);
|
|
}
|
|
|