LibreOffice Module store (master) 1
stortree.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <memory>
23#include <string.h>
24
25#include "stortree.hxx"
26
27#include <sal/types.h>
28#include <sal/log.hxx>
29#include <osl/diagnose.h>
30
31#include <store/types.h>
32
33#include "storbase.hxx"
34#include "storbios.hxx"
35
36using namespace store;
37
38OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize)
39 : PageData (nPageSize)
40{
43 self::m_aGuard.m_nMagic = store::htonl(0); // depth(0)
44
45 sal_uInt16 const n = capacityCount();
46 T const t;
47
48 for (sal_uInt16 i = 1; i < n; i++)
49 {
50 // cppcheck-suppress arrayIndexOutOfBounds
51 m_pData[i] = t;
52 }
53}
54
55/*
56 * find.
57 */
58sal_uInt16 OStoreBTreeNodeData::find (const T& t) const
59{
60 sal_Int32 l = 0;
61 sal_Int32 r = usageCount() - 1;
62
63 while (l < r)
64 {
65 sal_Int32 const m = ((l + r) >> 1);
66
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)
70 r = m - 1;
71 else
72 l = m + 1;
73 }
74
75 sal_uInt16 const k = static_cast<sal_uInt16>(r);
76 if ((k < capacityCount()) && (t.m_aKey < m_pData[k].m_aKey))
77 return k - 1;
78 else
79 return k;
80}
81
82void OStoreBTreeNodeData::insert (sal_uInt16 i, const T& t)
83{
84 sal_uInt16 const n = usageCount();
85 sal_uInt16 const m = capacityCount();
86 if ((n < m) && (i < m))
87 {
88 // shift right.
89 memmove (&(m_pData[i + 1]), &(m_pData[i]), (n - i) * sizeof(T));
90
91 // insert.
92 m_pData[i] = t;
93 usageCount (n + 1);
94 }
95}
96
97void OStoreBTreeNodeData::remove (sal_uInt16 i)
98{
99 sal_uInt16 const n = usageCount();
100 if (i < n)
101 {
102 // shift left.
103 memmove (&(m_pData[i]), &(m_pData[i + 1]), (n - i - 1) * sizeof(T));
104
105 // truncate.
106 m_pData[n - 1] = T();
107 usageCount (n - 1);
108 }
109}
110
111/*
112 * split (left half copied from right half of left page).
113 */
115{
116 sal_uInt16 const h = capacityCount() / 2;
117 memcpy (&(m_pData[0]), &(rPageL.m_pData[h]), h * sizeof(T));
118 truncate (h);
119}
120
122{
123 sal_uInt16 const m = capacityCount();
124 T const t;
125
126 for (sal_uInt16 i = n; i < m; i++)
127 m_pData[i] = t;
128 usageCount (n);
129}
130
132{
134}
135
137{
139}
140
142 sal_uInt16 nIndexL,
143 PageHolderObject< page > & rxPageL,
144 OStorePageBIOS & rBIOS)
145{
147 if (!xPage.is())
149
150 // Check left page usage.
151 if (!rxPageL.is())
153 if (!rxPageL->querySplit())
154 return store_E_None;
155
156 // Construct right page.
158 if (!xPageR.construct (rBIOS.allocator()))
159 return store_E_OutOfMemory;
160
161 // Split right page off left page.
162 xPageR->split (*rxPageL);
163 xPageR->depth (rxPageL->depth());
164
165 // Allocate right page.
166 self aNodeR (xPageR.get());
167 storeError eErrCode = rBIOS.allocate (aNodeR);
168 if (eErrCode != store_E_None)
169 return eErrCode;
170
171 // Truncate left page.
172 rxPageL->truncate (rxPageL->capacityCount() / 2);
173
174 // Save left page.
175 self aNodeL (rxPageL.get());
176 eErrCode = rBIOS.saveObjectAt (aNodeL, aNodeL.location());
177 if (eErrCode != store_E_None)
178 return eErrCode;
179
180 // Insert right page.
181 OStorePageLink aLink (xPageR->location());
182 xPage->insert (nIndexL + 1, T(xPageR->m_pData[0].m_aKey, aLink));
183
184 // Save this page and leave.
185 return rBIOS.saveObjectAt (*this, location());
186}
187
188/*
189 * remove (down to leaf node, recursive).
190 */
192 sal_uInt16 nIndexL,
193 OStoreBTreeEntry & rEntryL,
194 OStorePageBIOS & rBIOS)
195{
197 page & rPage = *xImpl;
198
199 // Check depth.
200 storeError eErrCode = store_E_None;
201 if (rPage.depth())
202 {
203 // Check link entry.
204 T const aEntryL (rPage.m_pData[nIndexL]);
205 if (rEntryL.compare (aEntryL) != T::COMPARE_EQUAL)
207
208 // Load link node.
209 self aNodeL;
210 eErrCode = rBIOS.loadObjectAt (aNodeL, aEntryL.m_aLink.location());
211 if (eErrCode != store_E_None)
212 return eErrCode;
213
214 // Recurse: remove from link node.
215 eErrCode = aNodeL.remove (0, rEntryL, rBIOS);
216 if (eErrCode != store_E_None)
217 return eErrCode;
218
219 // Check resulting link node usage.
220 PageHolderObject< page > xPageL (aNodeL.get());
221 if (xPageL->usageCount() == 0)
222 {
223 // Free empty link node.
224 eErrCode = rBIOS.free (xPageL->location());
225 if (eErrCode != store_E_None)
226 return eErrCode;
227
228 // Remove index.
229 rPage.remove (nIndexL);
230 touch();
231 }
232 else
233 {
234
235 // Relink.
236 rPage.m_pData[nIndexL].m_aKey = xPageL->m_pData[0].m_aKey;
237 touch();
238 }
239 }
240 else
241 {
242 // Check leaf entry.
243 if (rEntryL.compare (rPage.m_pData[nIndexL]) != T::COMPARE_EQUAL)
244 return store_E_NotExists;
245
246 // Save leaf entry.
247 rEntryL = rPage.m_pData[nIndexL];
248
249 // Remove leaf index.
250 rPage.remove (nIndexL);
251 touch();
252 }
253
254 // Check for modified node.
255 if (dirty())
256 {
257 // Save this page.
258 eErrCode = rBIOS.saveObjectAt (*this, location());
259 }
260
261 // Done.
262 return eErrCode;
263}
264
265/*
266 * testInvariant.
267 * Precond: root node page loaded.
268 */
269void OStoreBTreeRootObject::testInvariant (char const * message) const
270{
271 OSL_PRECOND(m_xPage != nullptr, "OStoreBTreeRootObject::testInvariant(): Null pointer");
272 SAL_WARN_IF( (m_xPage->location() - m_xPage->size()) != 0, "store", message);
273}
274
276 sal_uInt32 nAddr,
277 OStorePageBIOS & rBIOS)
278{
279 storeError eErrCode = rBIOS.loadObjectAt (*this, nAddr);
280 if (eErrCode != store_E_NotExists)
281 return eErrCode;
282
283 eErrCode = construct<page>(rBIOS.allocator());
284 if (eErrCode != store_E_None)
285 return eErrCode;
286
287 eErrCode = rBIOS.allocate (*this);
288 if (eErrCode != store_E_None)
289 return eErrCode;
290
291 // Notify caller of the creation.
292 testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
293 return store_E_Pending;
294}
295
297 PageHolderObject< page > & rxPageL,
298 OStorePageBIOS & rBIOS)
299{
301 testInvariant("OStoreBTreeRootObject::change(): enter");
302
303 // Save root location.
304 sal_uInt32 const nRootAddr = xPage->location();
305
306 // Construct new root.
307 if (!rxPageL.construct (rBIOS.allocator()))
308 return store_E_OutOfMemory;
309
310 // Save this as prev root.
311 storeError eErrCode = rBIOS.allocate (*this);
312 if (eErrCode != store_E_None)
313 return store_E_OutOfMemory;
314
315 // Setup new root.
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);
320
321 // Change root.
322 rxPageL.swap (xPage);
323 {
324 std::shared_ptr<PageData> tmp (xPage.get());
325 tmp.swap (m_xPage);
326 }
327
328 // Save this as new root and finish.
329 eErrCode = rBIOS.saveObjectAt (*this, nRootAddr);
330 testInvariant("OStoreBTreeRootObject::change(): leave");
331 return eErrCode;
332}
333
334/*
335 * find_lookup (w/o split()).
336 * Precond: root node page loaded.
337 */
339 OStoreBTreeNodeObject & rNode, // [out]
340 sal_uInt16 & rIndex, // [out]
341 OStorePageKey const & rKey,
342 OStorePageBIOS & rBIOS) const
343{
344 // Init node w/ root page.
345 testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
346 {
347 std::shared_ptr<PageData> tmp (m_xPage);
348 tmp.swap (rNode.get());
349 }
350
351 // Setup BTree entry.
352 T const entry (rKey);
353
354 // Check current page.
355 PageHolderObject< page > xPage (rNode.get());
356 for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >())
357 {
358 // Find next page.
359 page const & rPage = *xPage;
360 sal_uInt16 const i = rPage.find(entry);
361 sal_uInt16 const n = rPage.usageCount();
362 if (i >= n)
363 {
364 // Path to entry not exists (Must not happen(?)).
365 return store_E_NotExists;
366 }
367
368 // Check address.
369 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
370 if (nAddr == STORE_PAGE_NULL)
371 {
372 // Path to entry not exists (Must not happen(?)).
373 return store_E_NotExists;
374 }
375
376 // Load next page.
377 storeError eErrCode = rBIOS.loadObjectAt (rNode, nAddr);
378 if (eErrCode != store_E_None)
379 return eErrCode;
380 }
381
382 // Find index.
383 page const & rPage = *xPage;
384 rIndex = rPage.find(entry);
385 if (rIndex >= rPage.usageCount())
386 return store_E_NotExists;
387
388 // Compare entry.
389 T::CompareResult eResult = entry.compare(rPage.m_pData[rIndex]);
390 if (eResult == T::COMPARE_LESS)
391 {
392 SAL_WARN("store", "store::BTreeRoot::find_lookup(): sort error");
393 return store_E_Unknown;
394 }
395
396 // Greater or Equal.
397 testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
398 return store_E_None;
399}
400
401/*
402 * find_insert (possibly with split()).
403 * Precond: root node page loaded.
404 */
406 OStoreBTreeNodeObject & rNode, // [out]
407 sal_uInt16 & rIndex, // [out]
408 OStorePageKey const & rKey,
409 OStorePageBIOS & rBIOS)
410{
411 testInvariant("OStoreBTreeRootObject::find_insert(): enter");
412
413 // Check for RootNode split.
415 if (xRoot->querySplit())
416 {
418
419 // Change root.
420 storeError eErrCode = change (xPageL, rBIOS);
421 if (eErrCode != store_E_None)
422 return eErrCode;
423
424 // Split left page (prev root).
425 eErrCode = split (0, xPageL, rBIOS);
426 if (eErrCode != store_E_None)
427 return eErrCode;
428 }
429
430 // Init node w/ root page.
431 {
432 std::shared_ptr<PageData> tmp (m_xPage);
433 tmp.swap (rNode.get());
434 }
435
436 // Setup BTree entry.
437 T const entry (rKey);
438
439 // Check current Page.
440 PageHolderObject< page > xPage (rNode.get());
441 for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >())
442 {
443 // Find next page.
444 page const & rPage = *xPage;
445 sal_uInt16 const i = rPage.find (entry);
446 sal_uInt16 const n = rPage.usageCount();
447 if (i >= n)
448 {
449 // Path to entry not exists (Must not happen(?)).
450 return store_E_NotExists;
451 }
452
453 // Check address.
454 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
455 if (nAddr == STORE_PAGE_NULL)
456 {
457 // Path to entry not exists (Must not happen(?)).
458 return store_E_NotExists;
459 }
460
461 // Load next page.
463 storeError eErrCode = rBIOS.loadObjectAt (aNext, nAddr);
464 if (eErrCode != store_E_None)
465 return eErrCode;
466
467 // Check for next node split.
468 PageHolderObject< page > xNext (aNext.get());
469 if (xNext->querySplit())
470 {
471 // Split next node.
472 eErrCode = rNode.split (i, xNext, rBIOS);
473 if (eErrCode != store_E_None)
474 return eErrCode;
475
476 // Restart.
477 continue;
478 }
479
480 // Let next page be current.
481 std::shared_ptr<PageData> tmp (aNext.get());
482 tmp.swap (rNode.get());
483 }
484
485 // Find index.
486 page const & rPage = *xPage;
487 rIndex = rPage.find(entry);
488 if (rIndex < rPage.usageCount())
489 {
490 // Compare entry.
491 T::CompareResult result = entry.compare (rPage.m_pData[rIndex]);
492 if (result == T::COMPARE_LESS)
493 {
494 SAL_WARN("store", "store::BTreeRoot::find_insert(): sort error");
495 return store_E_Unknown;
496 }
497
500 }
501
502 // Greater or not (yet) existing.
503 testInvariant("OStoreBTreeRootObject::find_insert(): leave");
504 return store_E_None;
505}
506
507/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
virtual storeError guard(sal_uInt32 nAddr) override
Definition: stortree.cxx:131
storeError split(sal_uInt16 nIndexL, PageHolderObject< page > &rxPageL, OStorePageBIOS &rBIOS)
split.
Definition: stortree.cxx:141
virtual storeError verify(sal_uInt32 nAddr) const override
Definition: stortree.cxx:136
storeError remove(sal_uInt16 nIndexL, OStoreBTreeEntry &rEntryL, OStorePageBIOS &rBIOS)
remove (down to leaf node, recursive).
Definition: stortree.cxx:191
storeError loadOrCreate(sal_uInt32 nAddr, OStorePageBIOS &rBIOS)
Definition: stortree.cxx:275
storeError find_lookup(OStoreBTreeNodeObject &rNode, sal_uInt16 &rIndex, OStorePageKey const &rKey, OStorePageBIOS &rBIOS) const
find_lookup (w/o split()).
Definition: stortree.cxx:338
storeError change(PageHolderObject< page > &rxPageL, OStorePageBIOS &rBIOS)
change (Root).
Definition: stortree.cxx:296
storeError find_insert(OStoreBTreeNodeObject &rNode, sal_uInt16 &rIndex, OStorePageKey const &rKey, OStorePageBIOS &rBIOS)
find_insert (possibly with split()).
Definition: stortree.cxx:405
void testInvariant(char const *message) const
testInvariant.
Definition: stortree.cxx:269
rtl::Reference< PageData::Allocator > & allocator()
Definition: storbios.hxx:57
storeError saveObjectAt(OStorePageObject &rPage, sal_uInt32 nAddr)
Definition: storbios.cxx:822
storeError loadObjectAt(OStorePageObject &rPage, sal_uInt32 nAddr)
Page I/O.
Definition: storbios.cxx:781
storeError free(sal_uInt32 nAddr)
Definition: storbios.cxx:760
storeError allocate(OStorePageObject &rPage)
Definition: storbios.cxx:715
bool dirty() const
State.
Definition: storbase.hxx:586
sal_uInt32 location() const
Location.
Definition: storbase.hxx:601
PageHolderObject< U > makeHolder() const
Definition: storbase.hxx:561
std::shared_ptr< PageData > & get()
Definition: storbase.hxx:580
std::shared_ptr< PageData > m_xPage
Representation.
Definition: storbase.hxx:546
bool construct(rtl::Reference< PageData::Allocator > const &rxAllocator)
Definition: storbase.hxx:419
void swap(PageHolderObject< T > &rhs)
Definition: storbase.hxx:433
static storeError verify(std::shared_ptr< PageData > const &rxPage, sal_uInt32 nAddr)
Definition: storbase.hxx:499
static storeError guard(std::shared_ptr< PageData > const &rxPage, sal_uInt32 nAddr)
Definition: storbase.hxx:485
std::shared_ptr< PageData > & get()
Definition: storbase.hxx:454
sal_Int64 n
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
int i
m
Old OStorePageCache implementation.
Definition: lockbyte.cxx:133
sal_uInt32 htonl(sal_uInt32 h)
Definition: storbase.hxx:69
sal_uInt16 htons(sal_uInt16 h)
Definition: storbase.hxx:66
sal_Int32 h
#define STORE_PAGE_NULL
Definition: storbase.hxx:114
CompareResult compare(const OStoreBTreeEntry &rOther) const
Definition: stortree.hxx:61
void split(const self &rPageL)
split (left half copied from right half of left page).
Definition: stortree.cxx:114
static const sal_uInt32 theTypeId
Definition: stortree.hxx:85
void remove(sal_uInt16 i)
Definition: stortree.cxx:97
sal_uInt16 capacityCount() const
capacityCount (must be even).
Definition: stortree.hxx:98
void truncate(sal_uInt16 n)
truncate (to n elements).
Definition: stortree.cxx:121
static const sal_uInt16 thePageSize
Definition: stortree.hxx:88
void insert(sal_uInt16 i, const T &t)
Definition: stortree.cxx:82
sal_uInt16 usageCount() const
Definition: stortree.hxx:108
sal_uInt16 find(const T &t) const
Definition: stortree.cxx:58
OStoreBTreeEntry T
Definition: stortree.hxx:80
sal_uInt32 m_nMagic
Representation.
Definition: storbase.hxx:77
G m_aGuard
Representation.
Definition: storbase.hxx:243
sal_uInt32 location() const
location.
Definition: storbase.hxx:256
storeError
Error Code enumeration.
Definition: types.h:73
@ store_E_Unknown
Definition: types.h:95
@ store_E_OutOfMemory
Definition: types.h:90
@ store_E_None
Definition: types.h:74
@ store_E_InvalidAccess
Definition: types.h:80
@ store_E_AlreadyExists
Definition: types.h:84
@ store_E_NotExists
Definition: types.h:85
@ store_E_Pending
Definition: types.h:92
Any result