1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: stortree.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_store.hxx"
34 #include "stortree.hxx"
36 #include "sal/types.h"
37 #include "osl/diagnose.h"
39 #include "store/types.h"
41 #include "storbase.hxx"
42 #include "storbios.hxx"
44 using namespace store
;
46 /*========================================================================
48 * OStoreBTreeNodeData implementation.
50 *======================================================================*/
52 * OStoreBTreeNodeData.
54 OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize
)
55 : OStorePageData (nPageSize
)
57 base::m_aGuard
.m_nMagic
= store::htonl(self::theTypeId
);
58 base::m_aDescr
.m_nUsed
= store::htons(self::thePageSize
); // usageCount(0)
59 self::m_aGuard
.m_nMagic
= store::htonl(0); // depth(0)
61 sal_uInt16
const n
= capacityCount();
64 for (sal_uInt16 i
= 1; i
< n
; i
++)
71 sal_uInt16
OStoreBTreeNodeData::find (const T
& t
) const
73 register sal_Int32 l
= 0;
74 register sal_Int32 r
= usageCount() - 1;
78 register sal_Int32
const m
= ((l
+ r
) >> 1);
80 if (t
.m_aKey
== m_pData
[m
].m_aKey
)
81 return ((sal_uInt16
)(m
));
82 if (t
.m_aKey
< m_pData
[m
].m_aKey
)
88 sal_uInt16
const k
= ((sal_uInt16
)(r
));
89 if ((k
< capacityCount()) && (t
.m_aKey
< m_pData
[k
].m_aKey
))
98 void OStoreBTreeNodeData::insert (sal_uInt16 i
, const T
& t
)
100 sal_uInt16
const n
= usageCount();
101 sal_uInt16
const m
= capacityCount();
102 if ((n
< m
) && (i
< m
))
105 memmove (&(m_pData
[i
+ 1]), &(m_pData
[i
]), (n
- i
) * sizeof(T
));
116 void OStoreBTreeNodeData::remove (sal_uInt16 i
)
118 sal_uInt16
const n
= usageCount();
122 memmove (&(m_pData
[i
]), &(m_pData
[i
+ 1]), (n
- i
- 1) * sizeof(T
));
125 m_pData
[n
- 1] = T();
132 * merge (with right page).
134 void OStoreBTreeNodeData::merge (const self
& rPageR
)
136 sal_uInt16
const n
= usageCount();
137 sal_uInt16
const m
= rPageR
.usageCount();
138 if ((n
+ m
) <= capacityCount())
140 memcpy (&(m_pData
[n
]), &(rPageR
.m_pData
[0]), m
* sizeof(T
));
147 * split (left half copied from right half of left page).
149 void OStoreBTreeNodeData::split (const self
& rPageL
)
151 sal_uInt16
const h
= capacityCount() / 2;
152 memcpy (&(m_pData
[0]), &(rPageL
.m_pData
[h
]), h
* sizeof(T
));
159 void OStoreBTreeNodeData::truncate (sal_uInt16 n
)
161 sal_uInt16
const m
= capacityCount();
164 for (sal_uInt16 i
= n
; i
< m
; i
++)
169 /*========================================================================
171 * OStoreBTreeNodeObject implementation.
173 *======================================================================*/
177 storeError
OStoreBTreeNodeObject::guard (sal_uInt32 nAddr
)
179 return PageHolderObject
< page
>::guard (m_xPage
, nAddr
);
185 storeError
OStoreBTreeNodeObject::verify (sal_uInt32 nAddr
) const
189 return PageHolderObject
< page
>::verify (m_xPage
, nAddr
);
195 storeError
OStoreBTreeNodeObject::split (
197 PageHolderObject
< page
> & rxPageL
,
198 OStorePageBIOS
& rBIOS
)
200 PageHolderObject
< page
> xPage (m_xPage
);
202 return store_E_InvalidAccess
;
204 // Check left page usage.
206 return store_E_InvalidAccess
;
207 if (!rxPageL
->querySplit())
210 // Save PageDescriptor.
211 OStorePageDescriptor
aDescr (xPage
->m_aDescr
);
212 aDescr
.m_nAddr
= store::ntohl(aDescr
.m_nAddr
);
213 aDescr
.m_nSize
= store::ntohs(aDescr
.m_nSize
);
216 storeError eErrCode
= rBIOS
.acquireLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
217 if (eErrCode
!= store_E_None
)
220 // [Begin PageL Lock (NYI)]
222 // Construct right page.
223 PageHolderObject
< page
> xPageR
;
224 if (!xPageR
.construct (rBIOS
.allocator()))
226 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
227 return store_E_OutOfMemory
;
230 // Split right page off left page.
231 xPageR
->split (*rxPageL
);
232 xPageR
->depth (rxPageL
->depth());
234 // Allocate right page.
235 self
aNodeR (xPageR
.get());
236 eErrCode
= rBIOS
.allocate (aNodeR
);
237 if (eErrCode
!= store_E_None
)
239 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
243 // Truncate left page.
244 rxPageL
->truncate (rxPageL
->capacityCount() / 2);
247 self
aNodeL (rxPageL
.get());
248 eErrCode
= rBIOS
.saveObjectAt (aNodeL
, aNodeL
.location());
249 if (eErrCode
!= store_E_None
)
252 OSL_TRACE("OStoreBTreeNodeObject::split(): save() failed");
254 // Release Lock and Leave.
255 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
259 // [End PageL Lock (NYI)]
261 // Insert right page.
262 OStorePageLink
aLink (xPageR
->location());
263 xPage
->insert (nIndexL
+ 1, T(xPageR
->m_pData
[0].m_aKey
, aLink
));
266 eErrCode
= rBIOS
.saveObjectAt (*this, location());
267 if (eErrCode
!= store_E_None
)
270 OSL_TRACE("OStoreBTreeNodeObject::split(): save() failed");
272 // Release Lock and Leave.
273 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
277 // Release Lock and Leave.
278 return rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
282 * remove (down to leaf node, recursive).
284 storeError
OStoreBTreeNodeObject::remove (
286 OStoreBTreeEntry
& rEntryL
,
287 OStorePageBIOS
& rBIOS
)
289 PageHolderObject
< page
> xImpl (m_xPage
);
290 page
& rPage
= (*xImpl
);
292 // Save PageDescriptor.
293 OStorePageDescriptor
aDescr (rPage
.m_aDescr
);
294 aDescr
.m_nAddr
= store::ntohl(aDescr
.m_nAddr
);
295 aDescr
.m_nSize
= store::ntohs(aDescr
.m_nSize
);
298 storeError eErrCode
= rBIOS
.acquireLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
299 if (eErrCode
!= store_E_None
)
306 T
const aEntryL (rPage
.m_pData
[nIndexL
]);
307 if (!(rEntryL
.compare (aEntryL
) == T::COMPARE_EQUAL
))
309 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
310 return store_E_InvalidAccess
;
315 eErrCode
= rBIOS
.loadObjectAt (aNodeL
, aEntryL
.m_aLink
.location());
316 if (eErrCode
!= store_E_None
)
318 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
322 // Recurse: remove from link node.
323 eErrCode
= aNodeL
.remove (0, rEntryL
, rBIOS
);
324 if (eErrCode
!= store_E_None
)
326 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
330 // Check resulting link node usage.
331 PageHolderObject
< page
> xPageL (aNodeL
.get());
332 if (xPageL
->usageCount() == 0)
334 // Free empty link node.
335 OStorePageData aPageHead
;
336 eErrCode
= rBIOS
.free (aPageHead
, xPageL
->location());
337 if (eErrCode
!= store_E_None
)
339 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
344 rPage
.remove (nIndexL
);
350 // Check for right sibling.
351 sal_uInt16
const nIndexR
= nIndexL
+ 1;
352 if (nIndexR
< rPage
.usageCount())
354 // Load right link node.
356 eErrCode
= rBIOS
.loadObjectAt (aNodeR
, rPage
.m_pData
[nIndexR
].m_aLink
.location());
357 if (eErrCode
== store_E_None
)
359 if (rPageL
.queryMerge (rPageR
))
361 rPageL
.merge (rPageR
);
363 eErrCode
= rBIOS
.free (aPageHead
, rPageR
.location());
370 rPage
.m_pData
[nIndexL
].m_aKey
= xPageL
->m_pData
[0].m_aKey
;
377 if (!(rEntryL
.compare (rPage
.m_pData
[nIndexL
]) == T::COMPARE_EQUAL
))
379 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
380 return store_E_NotExists
;
384 rEntryL
= rPage
.m_pData
[nIndexL
];
386 // Remove leaf index.
387 rPage
.remove (nIndexL
);
391 // Check for modified node.
395 eErrCode
= rBIOS
.saveObjectAt (*this, location());
396 if (eErrCode
!= store_E_None
)
399 OSL_TRACE("OStoreBTreeNodeObject::remove(): save() failed");
401 // Release Lock and Leave.
402 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
407 // Release Lock and Leave.
408 return rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
411 /*========================================================================
413 * OStoreBTreeRootObject implementation.
415 *======================================================================*/
418 * Precond: root node page loaded.
420 bool OStoreBTreeRootObject::testInvariant (char const * message
)
422 OSL_PRECOND(m_xPage
.get() != 0, "OStoreBTreeRootObject::testInvariant(): Null pointer");
423 bool result
= ((m_xPage
->location() - m_xPage
->size()) == 0);
424 OSL_POSTCOND(result
, message
); (void) message
;
431 storeError
OStoreBTreeRootObject::loadOrCreate (
433 OStorePageBIOS
& rBIOS
)
435 storeError eErrCode
= rBIOS
.loadObjectAt (*this, nAddr
);
436 if (eErrCode
!= store_E_NotExists
)
439 eErrCode
= construct
<page
>(rBIOS
.allocator());
440 if (eErrCode
!= store_E_None
)
443 eErrCode
= rBIOS
.allocate (*this);
444 if (eErrCode
!= store_E_None
)
447 // Notify caller of the creation.
448 (void) testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
449 return store_E_Pending
;
455 storeError
OStoreBTreeRootObject::change (
456 PageHolderObject
< page
> & rxPageL
,
457 OStorePageBIOS
& rBIOS
)
459 PageHolderObject
< page
> xPage (m_xPage
);
460 (void) testInvariant("OStoreBTreeRootObject::change(): enter");
462 // Save PageDescriptor.
463 OStorePageDescriptor
aDescr (xPage
->m_aDescr
);
464 aDescr
.m_nAddr
= store::ntohl(aDescr
.m_nAddr
);
465 aDescr
.m_nSize
= store::ntohs(aDescr
.m_nSize
);
467 // Save root location.
468 sal_uInt32
const nRootAddr
= xPage
->location();
471 storeError eErrCode
= rBIOS
.acquireLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
472 if (eErrCode
!= store_E_None
)
475 // Construct new root.
476 if (!rxPageL
.construct (rBIOS
.allocator()))
478 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
479 return store_E_OutOfMemory
;
482 // Save this as prev root.
483 eErrCode
= rBIOS
.allocate (*this);
484 if (eErrCode
!= store_E_None
)
486 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
487 return store_E_OutOfMemory
;
491 rxPageL
->depth (xPage
->depth() + 1);
492 rxPageL
->m_pData
[0] = xPage
->m_pData
[0];
493 rxPageL
->m_pData
[0].m_aLink
= xPage
->location();
494 rxPageL
->usageCount(1);
497 rxPageL
.swap (xPage
);
499 PageHolder
tmp (xPage
.get());
503 // Save this as new root.
504 eErrCode
= rBIOS
.saveObjectAt (*this, nRootAddr
);
505 if (eErrCode
!= store_E_None
)
508 OSL_TRACE("OStoreBTreeRootObject::change(): save() failed");
510 // Release Lock and Leave.
511 rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
515 // Flush for robustness.
516 (void) rBIOS
.flush();
518 // Done. Release Lock and Leave.
519 (void) testInvariant("OStoreBTreeRootObject::change(): leave");
520 return rBIOS
.releaseLock (aDescr
.m_nAddr
, aDescr
.m_nSize
);
524 * find_lookup (w/o split()).
525 * Precond: root node page loaded.
527 storeError
OStoreBTreeRootObject::find_lookup (
528 OStoreBTreeNodeObject
& rNode
, // [out]
529 sal_uInt16
& rIndex
, // [out]
530 OStorePageKey
const & rKey
,
531 OStorePageBIOS
& rBIOS
)
533 // Init node w/ root page.
534 (void) testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
536 PageHolder
tmp (m_xPage
);
537 tmp
.swap (rNode
.get());
540 // Setup BTree entry.
541 T
const entry (rKey
);
543 // Check current page.
544 PageHolderObject
< page
> xPage (rNode
.get());
545 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
548 page
const & rPage
= (*xPage
);
549 sal_uInt16
const i
= rPage
.find(entry
);
550 sal_uInt16
const n
= rPage
.usageCount();
553 // Path to entry not exists (Must not happen(?)).
554 return store_E_NotExists
;
558 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
559 if (nAddr
== STORE_PAGE_NULL
)
561 // Path to entry not exists (Must not happen(?)).
562 return store_E_NotExists
;
566 storeError eErrCode
= rBIOS
.loadObjectAt (rNode
, nAddr
);
567 if (eErrCode
!= store_E_None
)
572 page
const & rPage
= (*xPage
);
573 rIndex
= rPage
.find(entry
);
574 if (!(rIndex
< rPage
.usageCount()))
575 return store_E_NotExists
;
578 T::CompareResult eResult
= entry
.compare(rPage
.m_pData
[rIndex
]);
579 OSL_POSTCOND(eResult
!= T::COMPARE_LESS
, "store::BTreeRoot::find_lookup(): sort error");
580 if (eResult
== T::COMPARE_LESS
)
581 return store_E_Unknown
;
584 (void) testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
589 * find_insert (possibly with split()).
590 * Precond: root node page loaded.
592 storeError
OStoreBTreeRootObject::find_insert (
593 OStoreBTreeNodeObject
& rNode
, // [out]
594 sal_uInt16
& rIndex
, // [out]
595 OStorePageKey
const & rKey
,
596 OStorePageBIOS
& rBIOS
)
598 (void) testInvariant("OStoreBTreeRootObject::find_insert(): enter");
600 // Check for RootNode split.
601 PageHolderObject
< page
> xRoot (m_xPage
);
602 if (xRoot
->querySplit())
604 PageHolderObject
< page
> xPageL
;
607 storeError eErrCode
= change (xPageL
, rBIOS
);
608 if (eErrCode
!= store_E_None
)
611 // Split left page (prev root).
612 eErrCode
= split (0, xPageL
, rBIOS
);
613 if (eErrCode
!= store_E_None
)
617 // Init node w/ root page.
619 PageHolder
tmp (m_xPage
);
620 tmp
.swap (rNode
.get());
623 // Setup BTree entry.
624 T
const entry (rKey
);
626 // Check current Page.
627 PageHolderObject
< page
> xPage (rNode
.get());
628 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
631 page
const & rPage
= (*xPage
);
632 sal_uInt16
const i
= rPage
.find (entry
);
633 sal_uInt16
const n
= rPage
.usageCount();
636 // Path to entry not exists (Must not happen(?)).
637 return store_E_NotExists
;
641 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
642 if (nAddr
== STORE_PAGE_NULL
)
644 // Path to entry not exists (Must not happen(?)).
645 return store_E_NotExists
;
649 OStoreBTreeNodeObject aNext
;
650 storeError eErrCode
= rBIOS
.loadObjectAt (aNext
, nAddr
);
651 if (eErrCode
!= store_E_None
)
654 // Check for next node split.
655 PageHolderObject
< page
> xNext (aNext
.get());
656 if (xNext
->querySplit())
659 eErrCode
= rNode
.split (i
, xNext
, rBIOS
);
660 if (eErrCode
!= store_E_None
)
667 // Let next page be current.
668 PageHolder
tmp (aNext
.get());
669 tmp
.swap (rNode
.get());
673 page
const & rPage
= (*xPage
);
674 rIndex
= rPage
.find(entry
);
675 if (rIndex
< rPage
.usageCount())
678 T::CompareResult result
= entry
.compare (rPage
.m_pData
[rIndex
]);
679 OSL_POSTCOND(result
!= T::COMPARE_LESS
, "store::BTreeRoot::find_insert(): sort error");
680 if (result
== T::COMPARE_LESS
)
681 return store_E_Unknown
;
683 if (result
== T::COMPARE_EQUAL
)
684 return store_E_AlreadyExists
;
687 // Greater or not (yet) existing.
688 (void) testInvariant("OStoreBTreeRootObject::find_insert(): leave");