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 <sal/config.h>
25 #include "stortree.hxx"
27 #include <sal/types.h>
28 #include <sal/log.hxx>
29 #include <osl/diagnose.h>
31 #include <store/types.h>
33 #include "storbase.hxx"
34 #include "storbios.hxx"
36 using namespace store
;
38 OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize
)
39 : PageData (nPageSize
)
41 base::m_aGuard
.m_nMagic
= store::htonl(self::theTypeId
);
42 base::m_aDescr
.m_nUsed
= store::htons(self::thePageSize
); // usageCount(0)
43 self::m_aGuard
.m_nMagic
= store::htonl(0); // depth(0)
45 sal_uInt16
const n
= capacityCount();
48 for (sal_uInt16 i
= 1; i
< n
; i
++)
50 // cppcheck-suppress arrayIndexOutOfBounds
58 sal_uInt16
OStoreBTreeNodeData::find (const T
& t
) const
61 sal_Int32 r
= usageCount() - 1;
65 sal_Int32
const m
= ((l
+ r
) >> 1);
67 if (t
.m_aKey
== m_pData
[m
].m_aKey
)
68 return static_cast<sal_uInt16
>(m
);
69 if (t
.m_aKey
< m_pData
[m
].m_aKey
)
75 sal_uInt16
const k
= static_cast<sal_uInt16
>(r
& 0xFFFF);
76 if ((k
< capacityCount()) && (t
.m_aKey
< m_pData
[k
].m_aKey
))
82 void OStoreBTreeNodeData::insert (sal_uInt16 i
, const T
& t
)
84 sal_uInt16
const n
= usageCount();
85 sal_uInt16
const m
= capacityCount();
86 if ((n
< m
) && (i
< m
))
89 memmove (&(m_pData
[i
+ 1]), &(m_pData
[i
]), (n
- i
) * sizeof(T
));
97 void OStoreBTreeNodeData::remove (sal_uInt16 i
)
99 sal_uInt16
const n
= usageCount();
103 memmove (&(m_pData
[i
]), &(m_pData
[i
+ 1]), (n
- i
- 1) * sizeof(T
));
106 m_pData
[n
- 1] = T();
112 * split (left half copied from right half of left page).
114 void OStoreBTreeNodeData::split (const self
& rPageL
)
116 sal_uInt16
const h
= capacityCount() / 2;
117 memcpy (&(m_pData
[0]), &(rPageL
.m_pData
[h
]), h
* sizeof(T
));
121 void OStoreBTreeNodeData::truncate (sal_uInt16 n
)
123 sal_uInt16
const m
= capacityCount();
126 for (sal_uInt16 i
= n
; i
< m
; i
++)
131 storeError
OStoreBTreeNodeObject::guard (sal_uInt32 nAddr
)
133 return PageHolderObject
< page
>::guard (m_xPage
, nAddr
);
136 storeError
OStoreBTreeNodeObject::verify (sal_uInt32 nAddr
) const
138 return PageHolderObject
< page
>::verify (m_xPage
, nAddr
);
141 storeError
OStoreBTreeNodeObject::split (
143 PageHolderObject
< page
> & rxPageL
,
144 OStorePageBIOS
& rBIOS
)
146 PageHolderObject
< page
> xPage (m_xPage
);
148 return store_E_InvalidAccess
;
150 // Check left page usage.
152 return store_E_InvalidAccess
;
153 if (!rxPageL
->querySplit())
156 // Construct right page.
157 PageHolderObject
< page
> xPageR
;
158 if (!xPageR
.construct (rBIOS
.allocator()))
159 return store_E_OutOfMemory
;
161 // Split right page off left page.
162 xPageR
->split (*rxPageL
);
163 xPageR
->depth (rxPageL
->depth());
165 // Allocate right page.
166 self
aNodeR (xPageR
.get());
167 storeError eErrCode
= rBIOS
.allocate (aNodeR
);
168 if (eErrCode
!= store_E_None
)
171 // Truncate left page.
172 rxPageL
->truncate (rxPageL
->capacityCount() / 2);
175 self
aNodeL (rxPageL
.get());
176 eErrCode
= rBIOS
.saveObjectAt (aNodeL
, aNodeL
.location());
177 if (eErrCode
!= store_E_None
)
180 // Insert right page.
181 OStorePageLink
aLink (xPageR
->location());
182 xPage
->insert (nIndexL
+ 1, T(xPageR
->m_pData
[0].m_aKey
, aLink
));
184 // Save this page and leave.
185 return rBIOS
.saveObjectAt (*this, location());
189 * remove (down to leaf node, recursive).
191 storeError
OStoreBTreeNodeObject::remove (
193 OStoreBTreeEntry
& rEntryL
,
194 OStorePageBIOS
& rBIOS
)
196 PageHolderObject
< page
> xImpl (m_xPage
);
197 page
& rPage
= *xImpl
;
200 storeError eErrCode
= store_E_None
;
204 T
const aEntryL (rPage
.m_pData
[nIndexL
]);
205 if (rEntryL
.compare (aEntryL
) != T::COMPARE_EQUAL
)
206 return store_E_InvalidAccess
;
210 eErrCode
= rBIOS
.loadObjectAt (aNodeL
, aEntryL
.m_aLink
.location());
211 if (eErrCode
!= store_E_None
)
214 // Recurse: remove from link node.
215 eErrCode
= aNodeL
.remove (0, rEntryL
, rBIOS
);
216 if (eErrCode
!= store_E_None
)
219 // Check resulting link node usage.
220 PageHolderObject
< page
> xPageL (aNodeL
.get());
221 if (xPageL
->usageCount() == 0)
223 // Free empty link node.
224 eErrCode
= rBIOS
.free (xPageL
->location());
225 if (eErrCode
!= store_E_None
)
229 rPage
.remove (nIndexL
);
236 rPage
.m_pData
[nIndexL
].m_aKey
= xPageL
->m_pData
[0].m_aKey
;
243 if (rEntryL
.compare (rPage
.m_pData
[nIndexL
]) != T::COMPARE_EQUAL
)
244 return store_E_NotExists
;
247 rEntryL
= rPage
.m_pData
[nIndexL
];
249 // Remove leaf index.
250 rPage
.remove (nIndexL
);
254 // Check for modified node.
258 eErrCode
= rBIOS
.saveObjectAt (*this, location());
267 * Precond: root node page loaded.
269 void OStoreBTreeRootObject::testInvariant (char const * message
) const
271 OSL_PRECOND(m_xPage
!= nullptr, "OStoreBTreeRootObject::testInvariant(): Null pointer");
272 SAL_WARN_IF( (m_xPage
->location() - m_xPage
->size()) != 0, "store", message
);
275 storeError
OStoreBTreeRootObject::loadOrCreate (
277 OStorePageBIOS
& rBIOS
)
279 storeError eErrCode
= rBIOS
.loadObjectAt (*this, nAddr
);
280 if (eErrCode
!= store_E_NotExists
)
283 eErrCode
= construct
<page
>(rBIOS
.allocator());
284 if (eErrCode
!= store_E_None
)
287 eErrCode
= rBIOS
.allocate (*this);
288 if (eErrCode
!= store_E_None
)
291 // Notify caller of the creation.
292 testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
293 return store_E_Pending
;
296 storeError
OStoreBTreeRootObject::change (
297 PageHolderObject
< page
> & rxPageL
,
298 OStorePageBIOS
& rBIOS
)
300 PageHolderObject
< page
> xPage (m_xPage
);
301 testInvariant("OStoreBTreeRootObject::change(): enter");
303 // Save root location.
304 sal_uInt32
const nRootAddr
= xPage
->location();
306 // Construct new root.
307 if (!rxPageL
.construct (rBIOS
.allocator()))
308 return store_E_OutOfMemory
;
310 // Save this as prev root.
311 storeError eErrCode
= rBIOS
.allocate (*this);
312 if (eErrCode
!= store_E_None
)
313 return store_E_OutOfMemory
;
316 rxPageL
->depth (xPage
->depth() + 1);
317 rxPageL
->m_pData
[0] = xPage
->m_pData
[0];
318 rxPageL
->m_pData
[0].m_aLink
= xPage
->location();
319 rxPageL
->usageCount(1);
322 rxPageL
.swap (xPage
);
324 std::shared_ptr
<PageData
> tmp (xPage
.get());
328 // Save this as new root and finish.
329 eErrCode
= rBIOS
.saveObjectAt (*this, nRootAddr
);
330 testInvariant("OStoreBTreeRootObject::change(): leave");
335 * find_lookup (w/o split()).
336 * Precond: root node page loaded.
338 storeError
OStoreBTreeRootObject::find_lookup (
339 OStoreBTreeNodeObject
& rNode
, // [out]
340 sal_uInt16
& rIndex
, // [out]
341 OStorePageKey
const & rKey
,
342 OStorePageBIOS
& rBIOS
) const
344 // Init node w/ root page.
345 testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
347 std::shared_ptr
<PageData
> tmp (m_xPage
);
348 tmp
.swap (rNode
.get());
351 // Setup BTree entry.
352 T
const entry (rKey
);
354 // Check current page.
355 PageHolderObject
< page
> xPage (rNode
.get());
356 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
359 page
const & rPage
= *xPage
;
360 sal_uInt16
const i
= rPage
.find(entry
);
361 sal_uInt16
const n
= rPage
.usageCount();
364 // Path to entry not exists (Must not happen(?)).
365 return store_E_NotExists
;
369 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
370 if (nAddr
== STORE_PAGE_NULL
)
372 // Path to entry not exists (Must not happen(?)).
373 return store_E_NotExists
;
377 storeError eErrCode
= rBIOS
.loadObjectAt (rNode
, nAddr
);
378 if (eErrCode
!= store_E_None
)
383 page
const & rPage
= *xPage
;
384 rIndex
= rPage
.find(entry
);
385 if (rIndex
>= rPage
.usageCount())
386 return store_E_NotExists
;
389 T::CompareResult eResult
= entry
.compare(rPage
.m_pData
[rIndex
]);
390 if (eResult
== T::COMPARE_LESS
)
392 SAL_WARN("store", "store::BTreeRoot::find_lookup(): sort error");
393 return store_E_Unknown
;
397 testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
402 * find_insert (possibly with split()).
403 * Precond: root node page loaded.
405 storeError
OStoreBTreeRootObject::find_insert (
406 OStoreBTreeNodeObject
& rNode
, // [out]
407 sal_uInt16
& rIndex
, // [out]
408 OStorePageKey
const & rKey
,
409 OStorePageBIOS
& rBIOS
)
411 testInvariant("OStoreBTreeRootObject::find_insert(): enter");
413 // Check for RootNode split.
414 PageHolderObject
< page
> xRoot (m_xPage
);
415 if (xRoot
->querySplit())
417 PageHolderObject
< page
> xPageL
;
420 storeError eErrCode
= change (xPageL
, rBIOS
);
421 if (eErrCode
!= store_E_None
)
424 // Split left page (prev root).
425 eErrCode
= split (0, xPageL
, rBIOS
);
426 if (eErrCode
!= store_E_None
)
430 // Init node w/ root page.
432 std::shared_ptr
<PageData
> tmp (m_xPage
);
433 tmp
.swap (rNode
.get());
436 // Setup BTree entry.
437 T
const entry (rKey
);
439 // Check current Page.
440 PageHolderObject
< page
> xPage (rNode
.get());
441 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
444 page
const & rPage
= *xPage
;
445 sal_uInt16
const i
= rPage
.find (entry
);
446 sal_uInt16
const n
= rPage
.usageCount();
449 // Path to entry not exists (Must not happen(?)).
450 return store_E_NotExists
;
454 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
455 if (nAddr
== STORE_PAGE_NULL
)
457 // Path to entry not exists (Must not happen(?)).
458 return store_E_NotExists
;
462 OStoreBTreeNodeObject aNext
;
463 storeError eErrCode
= rBIOS
.loadObjectAt (aNext
, nAddr
);
464 if (eErrCode
!= store_E_None
)
467 // Check for next node split.
468 PageHolderObject
< page
> xNext (aNext
.get());
469 if (xNext
->querySplit())
472 eErrCode
= rNode
.split (i
, xNext
, rBIOS
);
473 if (eErrCode
!= store_E_None
)
480 // Let next page be current.
481 std::shared_ptr
<PageData
> tmp (aNext
.get());
482 tmp
.swap (rNode
.get());
486 page
const & rPage
= *xPage
;
487 rIndex
= rPage
.find(entry
);
488 if (rIndex
< rPage
.usageCount())
491 T::CompareResult result
= entry
.compare (rPage
.m_pData
[rIndex
]);
492 if (result
== T::COMPARE_LESS
)
494 SAL_WARN("store", "store::BTreeRoot::find_insert(): sort error");
495 return store_E_Unknown
;
498 if (result
== T::COMPARE_EQUAL
)
499 return store_E_AlreadyExists
;
502 // Greater or not (yet) existing.
503 testInvariant("OStoreBTreeRootObject::find_insert(): leave");
507 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */