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 .
20 #include "stortree.hxx"
22 #include "sal/types.h"
23 #include "sal/log.hxx"
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
++)
53 // cppcheck-suppress arrayIndexOutOfBounds
61 sal_uInt16
OStoreBTreeNodeData::find (const T
& t
) const
64 sal_Int32 r
= usageCount() - 1;
68 sal_Int32
const m
= ((l
+ r
) >> 1);
70 if (t
.m_aKey
== m_pData
[m
].m_aKey
)
72 if (t
.m_aKey
< m_pData
[m
].m_aKey
)
78 sal_uInt16
const k
= ((sal_uInt16
)(r
));
79 if ((k
< capacityCount()) && (t
.m_aKey
< m_pData
[k
].m_aKey
))
88 void OStoreBTreeNodeData::insert (sal_uInt16 i
, const T
& t
)
90 sal_uInt16
const n
= usageCount();
91 sal_uInt16
const m
= capacityCount();
92 if ((n
< m
) && (i
< m
))
95 memmove (&(m_pData
[i
+ 1]), &(m_pData
[i
]), (n
- i
) * sizeof(T
));
106 void OStoreBTreeNodeData::remove (sal_uInt16 i
)
108 sal_uInt16
const n
= usageCount();
112 memmove (&(m_pData
[i
]), &(m_pData
[i
+ 1]), (n
- i
- 1) * sizeof(T
));
115 m_pData
[n
- 1] = T();
121 * split (left half copied from right half of left page).
123 void OStoreBTreeNodeData::split (const self
& rPageL
)
125 sal_uInt16
const h
= capacityCount() / 2;
126 memcpy (&(m_pData
[0]), &(rPageL
.m_pData
[h
]), h
* sizeof(T
));
133 void OStoreBTreeNodeData::truncate (sal_uInt16 n
)
135 sal_uInt16
const m
= capacityCount();
138 for (sal_uInt16 i
= n
; i
< m
; i
++)
143 /*========================================================================
145 * OStoreBTreeNodeObject implementation.
147 *======================================================================*/
151 storeError
OStoreBTreeNodeObject::guard (sal_uInt32 nAddr
)
153 return PageHolderObject
< page
>::guard (m_xPage
, nAddr
);
159 storeError
OStoreBTreeNodeObject::verify (sal_uInt32 nAddr
) const
161 return PageHolderObject
< page
>::verify (m_xPage
, nAddr
);
167 storeError
OStoreBTreeNodeObject::split (
169 PageHolderObject
< page
> & rxPageL
,
170 OStorePageBIOS
& rBIOS
)
172 PageHolderObject
< page
> xPage (m_xPage
);
174 return store_E_InvalidAccess
;
176 // Check left page usage.
178 return store_E_InvalidAccess
;
179 if (!rxPageL
->querySplit())
182 // Construct right page.
183 PageHolderObject
< page
> xPageR
;
184 if (!xPageR
.construct (rBIOS
.allocator()))
185 return store_E_OutOfMemory
;
187 // Split right page off left page.
188 xPageR
->split (*rxPageL
);
189 xPageR
->depth (rxPageL
->depth());
191 // Allocate right page.
192 self
aNodeR (xPageR
.get());
193 storeError eErrCode
= rBIOS
.allocate (aNodeR
);
194 if (eErrCode
!= store_E_None
)
197 // Truncate left page.
198 rxPageL
->truncate (rxPageL
->capacityCount() / 2);
201 self
aNodeL (rxPageL
.get());
202 eErrCode
= rBIOS
.saveObjectAt (aNodeL
, aNodeL
.location());
203 if (eErrCode
!= store_E_None
)
206 // Insert right page.
207 OStorePageLink
aLink (xPageR
->location());
208 xPage
->insert (nIndexL
+ 1, T(xPageR
->m_pData
[0].m_aKey
, aLink
));
210 // Save this page and leave.
211 return rBIOS
.saveObjectAt (*this, location());
215 * remove (down to leaf node, recursive).
217 storeError
OStoreBTreeNodeObject::remove (
219 OStoreBTreeEntry
& rEntryL
,
220 OStorePageBIOS
& rBIOS
)
222 PageHolderObject
< page
> xImpl (m_xPage
);
223 page
& rPage
= (*xImpl
);
226 storeError eErrCode
= store_E_None
;
230 T
const aEntryL (rPage
.m_pData
[nIndexL
]);
231 if (!(rEntryL
.compare (aEntryL
) == T::COMPARE_EQUAL
))
232 return store_E_InvalidAccess
;
236 eErrCode
= rBIOS
.loadObjectAt (aNodeL
, aEntryL
.m_aLink
.location());
237 if (eErrCode
!= store_E_None
)
240 // Recurse: remove from link node.
241 eErrCode
= aNodeL
.remove (0, rEntryL
, rBIOS
);
242 if (eErrCode
!= store_E_None
)
245 // Check resulting link node usage.
246 PageHolderObject
< page
> xPageL (aNodeL
.get());
247 if (xPageL
->usageCount() == 0)
249 // Free empty link node.
250 eErrCode
= rBIOS
.free (xPageL
->location());
251 if (eErrCode
!= store_E_None
)
255 rPage
.remove (nIndexL
);
262 rPage
.m_pData
[nIndexL
].m_aKey
= xPageL
->m_pData
[0].m_aKey
;
269 if (!(rEntryL
.compare (rPage
.m_pData
[nIndexL
]) == T::COMPARE_EQUAL
))
270 return store_E_NotExists
;
273 rEntryL
= rPage
.m_pData
[nIndexL
];
275 // Remove leaf index.
276 rPage
.remove (nIndexL
);
280 // Check for modified node.
284 eErrCode
= rBIOS
.saveObjectAt (*this, location());
291 /*========================================================================
293 * OStoreBTreeRootObject implementation.
295 *======================================================================*/
298 * Precond: root node page loaded.
300 void OStoreBTreeRootObject::testInvariant (char const * message
)
302 OSL_PRECOND(m_xPage
.get() != 0, "OStoreBTreeRootObject::testInvariant(): Null pointer");
303 SAL_WARN_IF( (m_xPage
->location() - m_xPage
->size()) != 0, "store", message
);
309 storeError
OStoreBTreeRootObject::loadOrCreate (
311 OStorePageBIOS
& rBIOS
)
313 storeError eErrCode
= rBIOS
.loadObjectAt (*this, nAddr
);
314 if (eErrCode
!= store_E_NotExists
)
317 eErrCode
= construct
<page
>(rBIOS
.allocator());
318 if (eErrCode
!= store_E_None
)
321 eErrCode
= rBIOS
.allocate (*this);
322 if (eErrCode
!= store_E_None
)
325 // Notify caller of the creation.
326 testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
327 return store_E_Pending
;
333 storeError
OStoreBTreeRootObject::change (
334 PageHolderObject
< page
> & rxPageL
,
335 OStorePageBIOS
& rBIOS
)
337 PageHolderObject
< page
> xPage (m_xPage
);
338 testInvariant("OStoreBTreeRootObject::change(): enter");
340 // Save root location.
341 sal_uInt32
const nRootAddr
= xPage
->location();
343 // Construct new root.
344 if (!rxPageL
.construct (rBIOS
.allocator()))
345 return store_E_OutOfMemory
;
347 // Save this as prev root.
348 storeError eErrCode
= rBIOS
.allocate (*this);
349 if (eErrCode
!= store_E_None
)
350 return store_E_OutOfMemory
;
353 rxPageL
->depth (xPage
->depth() + 1);
354 rxPageL
->m_pData
[0] = xPage
->m_pData
[0];
355 rxPageL
->m_pData
[0].m_aLink
= xPage
->location();
356 rxPageL
->usageCount(1);
359 rxPageL
.swap (xPage
);
361 PageHolder
tmp (xPage
.get());
365 // Save this as new root and finish.
366 eErrCode
= rBIOS
.saveObjectAt (*this, nRootAddr
);
367 testInvariant("OStoreBTreeRootObject::change(): leave");
372 * find_lookup (w/o split()).
373 * Precond: root node page loaded.
375 storeError
OStoreBTreeRootObject::find_lookup (
376 OStoreBTreeNodeObject
& rNode
, // [out]
377 sal_uInt16
& rIndex
, // [out]
378 OStorePageKey
const & rKey
,
379 OStorePageBIOS
& rBIOS
)
381 // Init node w/ root page.
382 testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
384 PageHolder
tmp (m_xPage
);
385 tmp
.swap (rNode
.get());
388 // Setup BTree entry.
389 T
const entry (rKey
);
391 // Check current page.
392 PageHolderObject
< page
> xPage (rNode
.get());
393 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
396 page
const & rPage
= (*xPage
);
397 sal_uInt16
const i
= rPage
.find(entry
);
398 sal_uInt16
const n
= rPage
.usageCount();
401 // Path to entry not exists (Must not happen(?)).
402 return store_E_NotExists
;
406 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
407 if (nAddr
== STORE_PAGE_NULL
)
409 // Path to entry not exists (Must not happen(?)).
410 return store_E_NotExists
;
414 storeError eErrCode
= rBIOS
.loadObjectAt (rNode
, nAddr
);
415 if (eErrCode
!= store_E_None
)
420 page
const & rPage
= (*xPage
);
421 rIndex
= rPage
.find(entry
);
422 if (!(rIndex
< rPage
.usageCount()))
423 return store_E_NotExists
;
426 T::CompareResult eResult
= entry
.compare(rPage
.m_pData
[rIndex
]);
427 if (eResult
== T::COMPARE_LESS
)
429 SAL_WARN("store", "store::BTreeRoot::find_lookup(): sort error");
430 return store_E_Unknown
;
434 testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
439 * find_insert (possibly with split()).
440 * Precond: root node page loaded.
442 storeError
OStoreBTreeRootObject::find_insert (
443 OStoreBTreeNodeObject
& rNode
, // [out]
444 sal_uInt16
& rIndex
, // [out]
445 OStorePageKey
const & rKey
,
446 OStorePageBIOS
& rBIOS
)
448 testInvariant("OStoreBTreeRootObject::find_insert(): enter");
450 // Check for RootNode split.
451 PageHolderObject
< page
> xRoot (m_xPage
);
452 if (xRoot
->querySplit())
454 PageHolderObject
< page
> xPageL
;
457 storeError eErrCode
= change (xPageL
, rBIOS
);
458 if (eErrCode
!= store_E_None
)
461 // Split left page (prev root).
462 eErrCode
= split (0, xPageL
, rBIOS
);
463 if (eErrCode
!= store_E_None
)
467 // Init node w/ root page.
469 PageHolder
tmp (m_xPage
);
470 tmp
.swap (rNode
.get());
473 // Setup BTree entry.
474 T
const entry (rKey
);
476 // Check current Page.
477 PageHolderObject
< page
> xPage (rNode
.get());
478 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
481 page
const & rPage
= (*xPage
);
482 sal_uInt16
const i
= rPage
.find (entry
);
483 sal_uInt16
const n
= rPage
.usageCount();
486 // Path to entry not exists (Must not happen(?)).
487 return store_E_NotExists
;
491 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
492 if (nAddr
== STORE_PAGE_NULL
)
494 // Path to entry not exists (Must not happen(?)).
495 return store_E_NotExists
;
499 OStoreBTreeNodeObject aNext
;
500 storeError eErrCode
= rBIOS
.loadObjectAt (aNext
, nAddr
);
501 if (eErrCode
!= store_E_None
)
504 // Check for next node split.
505 PageHolderObject
< page
> xNext (aNext
.get());
506 if (xNext
->querySplit())
509 eErrCode
= rNode
.split (i
, xNext
, rBIOS
);
510 if (eErrCode
!= store_E_None
)
517 // Let next page be current.
518 PageHolder
tmp (aNext
.get());
519 tmp
.swap (rNode
.get());
523 page
const & rPage
= (*xPage
);
524 rIndex
= rPage
.find(entry
);
525 if (rIndex
< rPage
.usageCount())
528 T::CompareResult result
= entry
.compare (rPage
.m_pData
[rIndex
]);
529 if (result
== T::COMPARE_LESS
)
531 SAL_WARN("store", "store::BTreeRoot::find_insert(): sort error");
532 return store_E_Unknown
;
535 if (result
== T::COMPARE_EQUAL
)
536 return store_E_AlreadyExists
;
539 // Greater or not (yet) existing.
540 testInvariant("OStoreBTreeRootObject::find_insert(): leave");
544 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */