build fix
[LibreOffice.git] / store / source / stortree.cxx
blob1b5e2277d6d89420d7604041f1e58797fe67aa1d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <memory>
24 #include "stortree.hxx"
26 #include "sal/types.h"
27 #include "sal/log.hxx"
28 #include "osl/diagnose.h"
30 #include "store/types.h"
32 #include "storbase.hxx"
33 #include "storbios.hxx"
35 using namespace store;
37 /*========================================================================
39 * OStoreBTreeNodeData implementation.
41 *======================================================================*/
43 * OStoreBTreeNodeData.
45 OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize)
46 : PageData (nPageSize)
48 base::m_aGuard.m_nMagic = store::htonl(self::theTypeId);
49 base::m_aDescr.m_nUsed = store::htons(self::thePageSize); // usageCount(0)
50 self::m_aGuard.m_nMagic = store::htonl(0); // depth(0)
52 sal_uInt16 const n = capacityCount();
53 T const t;
55 for (sal_uInt16 i = 1; i < n; i++)
57 // cppcheck-suppress arrayIndexOutOfBounds
58 m_pData[i] = t;
63 * find.
65 sal_uInt16 OStoreBTreeNodeData::find (const T& t) const
67 sal_Int32 l = 0;
68 sal_Int32 r = usageCount() - 1;
70 while (l < r)
72 sal_Int32 const m = ((l + r) >> 1);
74 if (t.m_aKey == m_pData[m].m_aKey)
75 return (sal_uInt16)m;
76 if (t.m_aKey < m_pData[m].m_aKey)
77 r = m - 1;
78 else
79 l = m + 1;
82 sal_uInt16 const k = ((sal_uInt16)(r));
83 if ((k < capacityCount()) && (t.m_aKey < m_pData[k].m_aKey))
84 return k - 1;
85 else
86 return k;
90 * insert.
92 void OStoreBTreeNodeData::insert (sal_uInt16 i, const T& t)
94 sal_uInt16 const n = usageCount();
95 sal_uInt16 const m = capacityCount();
96 if ((n < m) && (i < m))
98 // shift right.
99 memmove (&(m_pData[i + 1]), &(m_pData[i]), (n - i) * sizeof(T));
101 // insert.
102 m_pData[i] = t;
103 usageCount (n + 1);
108 * remove.
110 void OStoreBTreeNodeData::remove (sal_uInt16 i)
112 sal_uInt16 const n = usageCount();
113 if (i < n)
115 // shift left.
116 memmove (&(m_pData[i]), &(m_pData[i + 1]), (n - i - 1) * sizeof(T));
118 // truncate.
119 m_pData[n - 1] = T();
120 usageCount (n - 1);
125 * split (left half copied from right half of left page).
127 void OStoreBTreeNodeData::split (const self& rPageL)
129 sal_uInt16 const h = capacityCount() / 2;
130 memcpy (&(m_pData[0]), &(rPageL.m_pData[h]), h * sizeof(T));
131 truncate (h);
135 * truncate.
137 void OStoreBTreeNodeData::truncate (sal_uInt16 n)
139 sal_uInt16 const m = capacityCount();
140 T const t;
142 for (sal_uInt16 i = n; i < m; i++)
143 m_pData[i] = t;
144 usageCount (n);
147 /*========================================================================
149 * OStoreBTreeNodeObject implementation.
151 *======================================================================*/
153 * guard.
155 storeError OStoreBTreeNodeObject::guard (sal_uInt32 nAddr)
157 return PageHolderObject< page >::guard (m_xPage, nAddr);
161 * verify.
163 storeError OStoreBTreeNodeObject::verify (sal_uInt32 nAddr) const
165 return PageHolderObject< page >::verify (m_xPage, nAddr);
169 * split.
171 storeError OStoreBTreeNodeObject::split (
172 sal_uInt16 nIndexL,
173 PageHolderObject< page > & rxPageL,
174 OStorePageBIOS & rBIOS)
176 PageHolderObject< page > xPage (m_xPage);
177 if (!xPage.is())
178 return store_E_InvalidAccess;
180 // Check left page usage.
181 if (!rxPageL.is())
182 return store_E_InvalidAccess;
183 if (!rxPageL->querySplit())
184 return store_E_None;
186 // Construct right page.
187 PageHolderObject< page > xPageR;
188 if (!xPageR.construct (rBIOS.allocator()))
189 return store_E_OutOfMemory;
191 // Split right page off left page.
192 xPageR->split (*rxPageL);
193 xPageR->depth (rxPageL->depth());
195 // Allocate right page.
196 self aNodeR (xPageR.get());
197 storeError eErrCode = rBIOS.allocate (aNodeR);
198 if (eErrCode != store_E_None)
199 return eErrCode;
201 // Truncate left page.
202 rxPageL->truncate (rxPageL->capacityCount() / 2);
204 // Save left page.
205 self aNodeL (rxPageL.get());
206 eErrCode = rBIOS.saveObjectAt (aNodeL, aNodeL.location());
207 if (eErrCode != store_E_None)
208 return eErrCode;
210 // Insert right page.
211 OStorePageLink aLink (xPageR->location());
212 xPage->insert (nIndexL + 1, T(xPageR->m_pData[0].m_aKey, aLink));
214 // Save this page and leave.
215 return rBIOS.saveObjectAt (*this, location());
219 * remove (down to leaf node, recursive).
221 storeError OStoreBTreeNodeObject::remove (
222 sal_uInt16 nIndexL,
223 OStoreBTreeEntry & rEntryL,
224 OStorePageBIOS & rBIOS)
226 PageHolderObject< page > xImpl (m_xPage);
227 page & rPage = (*xImpl);
229 // Check depth.
230 storeError eErrCode = store_E_None;
231 if (rPage.depth())
233 // Check link entry.
234 T const aEntryL (rPage.m_pData[nIndexL]);
235 if (!(rEntryL.compare (aEntryL) == T::COMPARE_EQUAL))
236 return store_E_InvalidAccess;
238 // Load link node.
239 self aNodeL;
240 eErrCode = rBIOS.loadObjectAt (aNodeL, aEntryL.m_aLink.location());
241 if (eErrCode != store_E_None)
242 return eErrCode;
244 // Recurse: remove from link node.
245 eErrCode = aNodeL.remove (0, rEntryL, rBIOS);
246 if (eErrCode != store_E_None)
247 return eErrCode;
249 // Check resulting link node usage.
250 PageHolderObject< page > xPageL (aNodeL.get());
251 if (xPageL->usageCount() == 0)
253 // Free empty link node.
254 eErrCode = rBIOS.free (xPageL->location());
255 if (eErrCode != store_E_None)
256 return eErrCode;
258 // Remove index.
259 rPage.remove (nIndexL);
260 touch();
262 else
265 // Relink.
266 rPage.m_pData[nIndexL].m_aKey = xPageL->m_pData[0].m_aKey;
267 touch();
270 else
272 // Check leaf entry.
273 if (!(rEntryL.compare (rPage.m_pData[nIndexL]) == T::COMPARE_EQUAL))
274 return store_E_NotExists;
276 // Save leaf entry.
277 rEntryL = rPage.m_pData[nIndexL];
279 // Remove leaf index.
280 rPage.remove (nIndexL);
281 touch();
284 // Check for modified node.
285 if (dirty())
287 // Save this page.
288 eErrCode = rBIOS.saveObjectAt (*this, location());
291 // Done.
292 return eErrCode;
295 /*========================================================================
297 * OStoreBTreeRootObject implementation.
299 *======================================================================*/
301 * testInvariant.
302 * Precond: root node page loaded.
304 void OStoreBTreeRootObject::testInvariant (char const * message)
306 OSL_PRECOND(m_xPage.get() != nullptr, "OStoreBTreeRootObject::testInvariant(): Null pointer");
307 SAL_WARN_IF( (m_xPage->location() - m_xPage->size()) != 0, "store", message);
311 * loadOrCreate.
313 storeError OStoreBTreeRootObject::loadOrCreate (
314 sal_uInt32 nAddr,
315 OStorePageBIOS & rBIOS)
317 storeError eErrCode = rBIOS.loadObjectAt (*this, nAddr);
318 if (eErrCode != store_E_NotExists)
319 return eErrCode;
321 eErrCode = construct<page>(rBIOS.allocator());
322 if (eErrCode != store_E_None)
323 return eErrCode;
325 eErrCode = rBIOS.allocate (*this);
326 if (eErrCode != store_E_None)
327 return eErrCode;
329 // Notify caller of the creation.
330 testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
331 return store_E_Pending;
335 * change.
337 storeError OStoreBTreeRootObject::change (
338 PageHolderObject< page > & rxPageL,
339 OStorePageBIOS & rBIOS)
341 PageHolderObject< page > xPage (m_xPage);
342 testInvariant("OStoreBTreeRootObject::change(): enter");
344 // Save root location.
345 sal_uInt32 const nRootAddr = xPage->location();
347 // Construct new root.
348 if (!rxPageL.construct (rBIOS.allocator()))
349 return store_E_OutOfMemory;
351 // Save this as prev root.
352 storeError eErrCode = rBIOS.allocate (*this);
353 if (eErrCode != store_E_None)
354 return store_E_OutOfMemory;
356 // Setup new root.
357 rxPageL->depth (xPage->depth() + 1);
358 rxPageL->m_pData[0] = xPage->m_pData[0];
359 rxPageL->m_pData[0].m_aLink = xPage->location();
360 rxPageL->usageCount(1);
362 // Change root.
363 rxPageL.swap (xPage);
365 std::shared_ptr<PageData> tmp (xPage.get());
366 tmp.swap (m_xPage);
369 // Save this as new root and finish.
370 eErrCode = rBIOS.saveObjectAt (*this, nRootAddr);
371 testInvariant("OStoreBTreeRootObject::change(): leave");
372 return eErrCode;
376 * find_lookup (w/o split()).
377 * Precond: root node page loaded.
379 storeError OStoreBTreeRootObject::find_lookup (
380 OStoreBTreeNodeObject & rNode, // [out]
381 sal_uInt16 & rIndex, // [out]
382 OStorePageKey const & rKey,
383 OStorePageBIOS & rBIOS)
385 // Init node w/ root page.
386 testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
388 std::shared_ptr<PageData> tmp (m_xPage);
389 tmp.swap (rNode.get());
392 // Setup BTree entry.
393 T const entry (rKey);
395 // Check current page.
396 PageHolderObject< page > xPage (rNode.get());
397 for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >())
399 // Find next page.
400 page const & rPage = (*xPage);
401 sal_uInt16 const i = rPage.find(entry);
402 sal_uInt16 const n = rPage.usageCount();
403 if (!(i < n))
405 // Path to entry not exists (Must not happen(?)).
406 return store_E_NotExists;
409 // Check address.
410 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
411 if (nAddr == STORE_PAGE_NULL)
413 // Path to entry not exists (Must not happen(?)).
414 return store_E_NotExists;
417 // Load next page.
418 storeError eErrCode = rBIOS.loadObjectAt (rNode, nAddr);
419 if (eErrCode != store_E_None)
420 return eErrCode;
423 // Find index.
424 page const & rPage = (*xPage);
425 rIndex = rPage.find(entry);
426 if (!(rIndex < rPage.usageCount()))
427 return store_E_NotExists;
429 // Compare entry.
430 T::CompareResult eResult = entry.compare(rPage.m_pData[rIndex]);
431 if (eResult == T::COMPARE_LESS)
433 SAL_WARN("store", "store::BTreeRoot::find_lookup(): sort error");
434 return store_E_Unknown;
437 // Greater or Equal.
438 testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
439 return store_E_None;
443 * find_insert (possibly with split()).
444 * Precond: root node page loaded.
446 storeError OStoreBTreeRootObject::find_insert (
447 OStoreBTreeNodeObject & rNode, // [out]
448 sal_uInt16 & rIndex, // [out]
449 OStorePageKey const & rKey,
450 OStorePageBIOS & rBIOS)
452 testInvariant("OStoreBTreeRootObject::find_insert(): enter");
454 // Check for RootNode split.
455 PageHolderObject< page > xRoot (m_xPage);
456 if (xRoot->querySplit())
458 PageHolderObject< page > xPageL;
460 // Change root.
461 storeError eErrCode = change (xPageL, rBIOS);
462 if (eErrCode != store_E_None)
463 return eErrCode;
465 // Split left page (prev root).
466 eErrCode = split (0, xPageL, rBIOS);
467 if (eErrCode != store_E_None)
468 return eErrCode;
471 // Init node w/ root page.
473 std::shared_ptr<PageData> tmp (m_xPage);
474 tmp.swap (rNode.get());
477 // Setup BTree entry.
478 T const entry (rKey);
480 // Check current Page.
481 PageHolderObject< page > xPage (rNode.get());
482 for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >())
484 // Find next page.
485 page const & rPage = (*xPage);
486 sal_uInt16 const i = rPage.find (entry);
487 sal_uInt16 const n = rPage.usageCount();
488 if (!(i < n))
490 // Path to entry not exists (Must not happen(?)).
491 return store_E_NotExists;
494 // Check address.
495 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
496 if (nAddr == STORE_PAGE_NULL)
498 // Path to entry not exists (Must not happen(?)).
499 return store_E_NotExists;
502 // Load next page.
503 OStoreBTreeNodeObject aNext;
504 storeError eErrCode = rBIOS.loadObjectAt (aNext, nAddr);
505 if (eErrCode != store_E_None)
506 return eErrCode;
508 // Check for next node split.
509 PageHolderObject< page > xNext (aNext.get());
510 if (xNext->querySplit())
512 // Split next node.
513 eErrCode = rNode.split (i, xNext, rBIOS);
514 if (eErrCode != store_E_None)
515 return eErrCode;
517 // Restart.
518 continue;
521 // Let next page be current.
522 std::shared_ptr<PageData> tmp (aNext.get());
523 tmp.swap (rNode.get());
526 // Find index.
527 page const & rPage = (*xPage);
528 rIndex = rPage.find(entry);
529 if (rIndex < rPage.usageCount())
531 // Compare entry.
532 T::CompareResult result = entry.compare (rPage.m_pData[rIndex]);
533 if (result == T::COMPARE_LESS)
535 SAL_WARN("store", "store::BTreeRoot::find_insert(): sort error");
536 return store_E_Unknown;
539 if (result == T::COMPARE_EQUAL)
540 return store_E_AlreadyExists;
543 // Greater or not (yet) existing.
544 testInvariant("OStoreBTreeRootObject::find_insert(): leave");
545 return store_E_None;
548 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */