1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "stortree.hxx"
23 #include "sal/types.h"
24 #include "osl/diagnose.h"
26 #include "store/types.h"
28 #include "storbase.hxx"
29 #include "storbios.hxx"
31 using namespace store
;
33 /*========================================================================
35 * OStoreBTreeNodeData implementation.
37 *======================================================================*/
39 * OStoreBTreeNodeData.
41 OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize
)
42 : OStorePageData (nPageSize
)
44 base::m_aGuard
.m_nMagic
= store::htonl(self::theTypeId
);
45 base::m_aDescr
.m_nUsed
= store::htons(self::thePageSize
); // usageCount(0)
46 self::m_aGuard
.m_nMagic
= store::htonl(0); // depth(0)
48 sal_uInt16
const n
= capacityCount();
51 for (sal_uInt16 i
= 1; i
< n
; i
++)
58 sal_uInt16
OStoreBTreeNodeData::find (const T
& t
) const
60 register sal_Int32 l
= 0;
61 register sal_Int32 r
= usageCount() - 1;
65 register sal_Int32
const m
= ((l
+ r
) >> 1);
67 if (t
.m_aKey
== m_pData
[m
].m_aKey
)
68 return ((sal_uInt16
)(m
));
69 if (t
.m_aKey
< m_pData
[m
].m_aKey
)
75 sal_uInt16
const k
= ((sal_uInt16
)(r
));
76 if ((k
< capacityCount()) && (t
.m_aKey
< m_pData
[k
].m_aKey
))
85 void OStoreBTreeNodeData::insert (sal_uInt16 i
, const T
& t
)
87 sal_uInt16
const n
= usageCount();
88 sal_uInt16
const m
= capacityCount();
89 if ((n
< m
) && (i
< m
))
92 memmove (&(m_pData
[i
+ 1]), &(m_pData
[i
]), (n
- i
) * sizeof(T
));
103 void OStoreBTreeNodeData::remove (sal_uInt16 i
)
105 sal_uInt16
const n
= usageCount();
109 memmove (&(m_pData
[i
]), &(m_pData
[i
+ 1]), (n
- i
- 1) * sizeof(T
));
112 m_pData
[n
- 1] = T();
118 * split (left half copied from right half of left page).
120 void OStoreBTreeNodeData::split (const self
& rPageL
)
122 sal_uInt16
const h
= capacityCount() / 2;
123 memcpy (&(m_pData
[0]), &(rPageL
.m_pData
[h
]), h
* sizeof(T
));
130 void OStoreBTreeNodeData::truncate (sal_uInt16 n
)
132 sal_uInt16
const m
= capacityCount();
135 for (sal_uInt16 i
= n
; i
< m
; i
++)
140 /*========================================================================
142 * OStoreBTreeNodeObject implementation.
144 *======================================================================*/
148 storeError
OStoreBTreeNodeObject::guard (sal_uInt32 nAddr
)
150 return PageHolderObject
< page
>::guard (m_xPage
, nAddr
);
156 storeError
OStoreBTreeNodeObject::verify (sal_uInt32 nAddr
) const
158 return PageHolderObject
< page
>::verify (m_xPage
, nAddr
);
164 storeError
OStoreBTreeNodeObject::split (
166 PageHolderObject
< page
> & rxPageL
,
167 OStorePageBIOS
& rBIOS
)
169 PageHolderObject
< page
> xPage (m_xPage
);
171 return store_E_InvalidAccess
;
173 // Check left page usage.
175 return store_E_InvalidAccess
;
176 if (!rxPageL
->querySplit())
179 // Construct right page.
180 PageHolderObject
< page
> xPageR
;
181 if (!xPageR
.construct (rBIOS
.allocator()))
182 return store_E_OutOfMemory
;
184 // Split right page off left page.
185 xPageR
->split (*rxPageL
);
186 xPageR
->depth (rxPageL
->depth());
188 // Allocate right page.
189 self
aNodeR (xPageR
.get());
190 storeError eErrCode
= rBIOS
.allocate (aNodeR
);
191 if (eErrCode
!= store_E_None
)
194 // Truncate left page.
195 rxPageL
->truncate (rxPageL
->capacityCount() / 2);
198 self
aNodeL (rxPageL
.get());
199 eErrCode
= rBIOS
.saveObjectAt (aNodeL
, aNodeL
.location());
200 if (eErrCode
!= store_E_None
)
203 // Insert right page.
204 OStorePageLink
aLink (xPageR
->location());
205 xPage
->insert (nIndexL
+ 1, T(xPageR
->m_pData
[0].m_aKey
, aLink
));
207 // Save this page and leave.
208 return rBIOS
.saveObjectAt (*this, location());
212 * remove (down to leaf node, recursive).
214 storeError
OStoreBTreeNodeObject::remove (
216 OStoreBTreeEntry
& rEntryL
,
217 OStorePageBIOS
& rBIOS
)
219 PageHolderObject
< page
> xImpl (m_xPage
);
220 page
& rPage
= (*xImpl
);
223 storeError eErrCode
= store_E_None
;
227 T
const aEntryL (rPage
.m_pData
[nIndexL
]);
228 if (!(rEntryL
.compare (aEntryL
) == T::COMPARE_EQUAL
))
229 return store_E_InvalidAccess
;
233 eErrCode
= rBIOS
.loadObjectAt (aNodeL
, aEntryL
.m_aLink
.location());
234 if (eErrCode
!= store_E_None
)
237 // Recurse: remove from link node.
238 eErrCode
= aNodeL
.remove (0, rEntryL
, rBIOS
);
239 if (eErrCode
!= store_E_None
)
242 // Check resulting link node usage.
243 PageHolderObject
< page
> xPageL (aNodeL
.get());
244 if (xPageL
->usageCount() == 0)
246 // Free empty link node.
247 eErrCode
= rBIOS
.free (xPageL
->location());
248 if (eErrCode
!= store_E_None
)
252 rPage
.remove (nIndexL
);
259 rPage
.m_pData
[nIndexL
].m_aKey
= xPageL
->m_pData
[0].m_aKey
;
266 if (!(rEntryL
.compare (rPage
.m_pData
[nIndexL
]) == T::COMPARE_EQUAL
))
267 return store_E_NotExists
;
270 rEntryL
= rPage
.m_pData
[nIndexL
];
272 // Remove leaf index.
273 rPage
.remove (nIndexL
);
277 // Check for modified node.
281 eErrCode
= rBIOS
.saveObjectAt (*this, location());
288 /*========================================================================
290 * OStoreBTreeRootObject implementation.
292 *======================================================================*/
295 * Precond: root node page loaded.
297 bool OStoreBTreeRootObject::testInvariant (char const * message
)
299 OSL_PRECOND(m_xPage
.get() != 0, "OStoreBTreeRootObject::testInvariant(): Null pointer");
300 bool result
= ((m_xPage
->location() - m_xPage
->size()) == 0);
301 OSL_POSTCOND(result
, message
); (void) message
;
308 storeError
OStoreBTreeRootObject::loadOrCreate (
310 OStorePageBIOS
& rBIOS
)
312 storeError eErrCode
= rBIOS
.loadObjectAt (*this, nAddr
);
313 if (eErrCode
!= store_E_NotExists
)
316 eErrCode
= construct
<page
>(rBIOS
.allocator());
317 if (eErrCode
!= store_E_None
)
320 eErrCode
= rBIOS
.allocate (*this);
321 if (eErrCode
!= store_E_None
)
324 // Notify caller of the creation.
325 (void) testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
326 return store_E_Pending
;
332 storeError
OStoreBTreeRootObject::change (
333 PageHolderObject
< page
> & rxPageL
,
334 OStorePageBIOS
& rBIOS
)
336 PageHolderObject
< page
> xPage (m_xPage
);
337 (void) testInvariant("OStoreBTreeRootObject::change(): enter");
339 // Save root location.
340 sal_uInt32
const nRootAddr
= xPage
->location();
342 // Construct new root.
343 if (!rxPageL
.construct (rBIOS
.allocator()))
344 return store_E_OutOfMemory
;
346 // Save this as prev root.
347 storeError eErrCode
= rBIOS
.allocate (*this);
348 if (eErrCode
!= store_E_None
)
349 return store_E_OutOfMemory
;
352 rxPageL
->depth (xPage
->depth() + 1);
353 rxPageL
->m_pData
[0] = xPage
->m_pData
[0];
354 rxPageL
->m_pData
[0].m_aLink
= xPage
->location();
355 rxPageL
->usageCount(1);
358 rxPageL
.swap (xPage
);
360 PageHolder
tmp (xPage
.get());
364 // Save this as new root and finish.
365 eErrCode
= rBIOS
.saveObjectAt (*this, nRootAddr
);
366 (void) testInvariant("OStoreBTreeRootObject::change(): leave");
371 * find_lookup (w/o split()).
372 * Precond: root node page loaded.
374 storeError
OStoreBTreeRootObject::find_lookup (
375 OStoreBTreeNodeObject
& rNode
, // [out]
376 sal_uInt16
& rIndex
, // [out]
377 OStorePageKey
const & rKey
,
378 OStorePageBIOS
& rBIOS
)
380 // Init node w/ root page.
381 (void) testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
383 PageHolder
tmp (m_xPage
);
384 tmp
.swap (rNode
.get());
387 // Setup BTree entry.
388 T
const entry (rKey
);
390 // Check current page.
391 PageHolderObject
< page
> xPage (rNode
.get());
392 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
395 page
const & rPage
= (*xPage
);
396 sal_uInt16
const i
= rPage
.find(entry
);
397 sal_uInt16
const n
= rPage
.usageCount();
400 // Path to entry not exists (Must not happen(?)).
401 return store_E_NotExists
;
405 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
406 if (nAddr
== STORE_PAGE_NULL
)
408 // Path to entry not exists (Must not happen(?)).
409 return store_E_NotExists
;
413 storeError eErrCode
= rBIOS
.loadObjectAt (rNode
, nAddr
);
414 if (eErrCode
!= store_E_None
)
419 page
const & rPage
= (*xPage
);
420 rIndex
= rPage
.find(entry
);
421 if (!(rIndex
< rPage
.usageCount()))
422 return store_E_NotExists
;
425 T::CompareResult eResult
= entry
.compare(rPage
.m_pData
[rIndex
]);
426 OSL_POSTCOND(eResult
!= T::COMPARE_LESS
, "store::BTreeRoot::find_lookup(): sort error");
427 if (eResult
== T::COMPARE_LESS
)
428 return store_E_Unknown
;
431 (void) testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
436 * find_insert (possibly with split()).
437 * Precond: root node page loaded.
439 storeError
OStoreBTreeRootObject::find_insert (
440 OStoreBTreeNodeObject
& rNode
, // [out]
441 sal_uInt16
& rIndex
, // [out]
442 OStorePageKey
const & rKey
,
443 OStorePageBIOS
& rBIOS
)
445 (void) testInvariant("OStoreBTreeRootObject::find_insert(): enter");
447 // Check for RootNode split.
448 PageHolderObject
< page
> xRoot (m_xPage
);
449 if (xRoot
->querySplit())
451 PageHolderObject
< page
> xPageL
;
454 storeError eErrCode
= change (xPageL
, rBIOS
);
455 if (eErrCode
!= store_E_None
)
458 // Split left page (prev root).
459 eErrCode
= split (0, xPageL
, rBIOS
);
460 if (eErrCode
!= store_E_None
)
464 // Init node w/ root page.
466 PageHolder
tmp (m_xPage
);
467 tmp
.swap (rNode
.get());
470 // Setup BTree entry.
471 T
const entry (rKey
);
473 // Check current Page.
474 PageHolderObject
< page
> xPage (rNode
.get());
475 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
478 page
const & rPage
= (*xPage
);
479 sal_uInt16
const i
= rPage
.find (entry
);
480 sal_uInt16
const n
= rPage
.usageCount();
483 // Path to entry not exists (Must not happen(?)).
484 return store_E_NotExists
;
488 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
489 if (nAddr
== STORE_PAGE_NULL
)
491 // Path to entry not exists (Must not happen(?)).
492 return store_E_NotExists
;
496 OStoreBTreeNodeObject aNext
;
497 storeError eErrCode
= rBIOS
.loadObjectAt (aNext
, nAddr
);
498 if (eErrCode
!= store_E_None
)
501 // Check for next node split.
502 PageHolderObject
< page
> xNext (aNext
.get());
503 if (xNext
->querySplit())
506 eErrCode
= rNode
.split (i
, xNext
, rBIOS
);
507 if (eErrCode
!= store_E_None
)
514 // Let next page be current.
515 PageHolder
tmp (aNext
.get());
516 tmp
.swap (rNode
.get());
520 page
const & rPage
= (*xPage
);
521 rIndex
= rPage
.find(entry
);
522 if (rIndex
< rPage
.usageCount())
525 T::CompareResult result
= entry
.compare (rPage
.m_pData
[rIndex
]);
526 OSL_POSTCOND(result
!= T::COMPARE_LESS
, "store::BTreeRoot::find_insert(): sort error");
527 if (result
== T::COMPARE_LESS
)
528 return store_E_Unknown
;
530 if (result
== T::COMPARE_EQUAL
)
531 return store_E_AlreadyExists
;
534 // Greater or not (yet) existing.
535 (void) testInvariant("OStoreBTreeRootObject::find_insert(): leave");
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */