1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "stortree.hxx"
32 #include "sal/types.h"
33 #include "osl/diagnose.h"
35 #include "store/types.h"
37 #include "storbase.hxx"
38 #include "storbios.hxx"
40 using namespace store
;
42 /*========================================================================
44 * OStoreBTreeNodeData implementation.
46 *======================================================================*/
48 * OStoreBTreeNodeData.
50 OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize
)
51 : OStorePageData (nPageSize
)
53 base::m_aGuard
.m_nMagic
= store::htonl(self::theTypeId
);
54 base::m_aDescr
.m_nUsed
= store::htons(self::thePageSize
); // usageCount(0)
55 self::m_aGuard
.m_nMagic
= store::htonl(0); // depth(0)
57 sal_uInt16
const n
= capacityCount();
60 for (sal_uInt16 i
= 1; i
< n
; i
++)
67 sal_uInt16
OStoreBTreeNodeData::find (const T
& t
) const
69 register sal_Int32 l
= 0;
70 register sal_Int32 r
= usageCount() - 1;
74 register sal_Int32
const m
= ((l
+ r
) >> 1);
76 if (t
.m_aKey
== m_pData
[m
].m_aKey
)
77 return ((sal_uInt16
)(m
));
78 if (t
.m_aKey
< m_pData
[m
].m_aKey
)
84 sal_uInt16
const k
= ((sal_uInt16
)(r
));
85 if ((k
< capacityCount()) && (t
.m_aKey
< m_pData
[k
].m_aKey
))
94 void OStoreBTreeNodeData::insert (sal_uInt16 i
, const T
& t
)
96 sal_uInt16
const n
= usageCount();
97 sal_uInt16
const m
= capacityCount();
98 if ((n
< m
) && (i
< m
))
101 memmove (&(m_pData
[i
+ 1]), &(m_pData
[i
]), (n
- i
) * sizeof(T
));
112 void OStoreBTreeNodeData::remove (sal_uInt16 i
)
114 sal_uInt16
const n
= usageCount();
118 memmove (&(m_pData
[i
]), &(m_pData
[i
+ 1]), (n
- i
- 1) * sizeof(T
));
121 m_pData
[n
- 1] = T();
127 * split (left half copied from right half of left page).
129 void OStoreBTreeNodeData::split (const self
& rPageL
)
131 sal_uInt16
const h
= capacityCount() / 2;
132 memcpy (&(m_pData
[0]), &(rPageL
.m_pData
[h
]), h
* sizeof(T
));
139 void OStoreBTreeNodeData::truncate (sal_uInt16 n
)
141 sal_uInt16
const m
= capacityCount();
144 for (sal_uInt16 i
= n
; i
< m
; i
++)
149 /*========================================================================
151 * OStoreBTreeNodeObject implementation.
153 *======================================================================*/
157 storeError
OStoreBTreeNodeObject::guard (sal_uInt32 nAddr
)
159 return PageHolderObject
< page
>::guard (m_xPage
, nAddr
);
165 storeError
OStoreBTreeNodeObject::verify (sal_uInt32 nAddr
) const
167 return PageHolderObject
< page
>::verify (m_xPage
, nAddr
);
173 storeError
OStoreBTreeNodeObject::split (
175 PageHolderObject
< page
> & rxPageL
,
176 OStorePageBIOS
& rBIOS
)
178 PageHolderObject
< page
> xPage (m_xPage
);
180 return store_E_InvalidAccess
;
182 // Check left page usage.
184 return store_E_InvalidAccess
;
185 if (!rxPageL
->querySplit())
188 // Construct right page.
189 PageHolderObject
< page
> xPageR
;
190 if (!xPageR
.construct (rBIOS
.allocator()))
191 return store_E_OutOfMemory
;
193 // Split right page off left page.
194 xPageR
->split (*rxPageL
);
195 xPageR
->depth (rxPageL
->depth());
197 // Allocate right page.
198 self
aNodeR (xPageR
.get());
199 storeError eErrCode
= rBIOS
.allocate (aNodeR
);
200 if (eErrCode
!= store_E_None
)
203 // Truncate left page.
204 rxPageL
->truncate (rxPageL
->capacityCount() / 2);
207 self
aNodeL (rxPageL
.get());
208 eErrCode
= rBIOS
.saveObjectAt (aNodeL
, aNodeL
.location());
209 if (eErrCode
!= store_E_None
)
212 // Insert right page.
213 OStorePageLink
aLink (xPageR
->location());
214 xPage
->insert (nIndexL
+ 1, T(xPageR
->m_pData
[0].m_aKey
, aLink
));
216 // Save this page and leave.
217 return rBIOS
.saveObjectAt (*this, location());
221 * remove (down to leaf node, recursive).
223 storeError
OStoreBTreeNodeObject::remove (
225 OStoreBTreeEntry
& rEntryL
,
226 OStorePageBIOS
& rBIOS
)
228 PageHolderObject
< page
> xImpl (m_xPage
);
229 page
& rPage
= (*xImpl
);
232 storeError eErrCode
= store_E_None
;
236 T
const aEntryL (rPage
.m_pData
[nIndexL
]);
237 if (!(rEntryL
.compare (aEntryL
) == T::COMPARE_EQUAL
))
238 return store_E_InvalidAccess
;
242 eErrCode
= rBIOS
.loadObjectAt (aNodeL
, aEntryL
.m_aLink
.location());
243 if (eErrCode
!= store_E_None
)
246 // Recurse: remove from link node.
247 eErrCode
= aNodeL
.remove (0, rEntryL
, rBIOS
);
248 if (eErrCode
!= store_E_None
)
251 // Check resulting link node usage.
252 PageHolderObject
< page
> xPageL (aNodeL
.get());
253 if (xPageL
->usageCount() == 0)
255 // Free empty link node.
256 eErrCode
= rBIOS
.free (xPageL
->location());
257 if (eErrCode
!= store_E_None
)
261 rPage
.remove (nIndexL
);
268 rPage
.m_pData
[nIndexL
].m_aKey
= xPageL
->m_pData
[0].m_aKey
;
275 if (!(rEntryL
.compare (rPage
.m_pData
[nIndexL
]) == T::COMPARE_EQUAL
))
276 return store_E_NotExists
;
279 rEntryL
= rPage
.m_pData
[nIndexL
];
281 // Remove leaf index.
282 rPage
.remove (nIndexL
);
286 // Check for modified node.
290 eErrCode
= rBIOS
.saveObjectAt (*this, location());
297 /*========================================================================
299 * OStoreBTreeRootObject implementation.
301 *======================================================================*/
304 * Precond: root node page loaded.
306 bool OStoreBTreeRootObject::testInvariant (char const * message
)
308 OSL_PRECOND(m_xPage
.get() != 0, "OStoreBTreeRootObject::testInvariant(): Null pointer");
309 bool result
= ((m_xPage
->location() - m_xPage
->size()) == 0);
310 OSL_POSTCOND(result
, message
); (void) message
;
317 storeError
OStoreBTreeRootObject::loadOrCreate (
319 OStorePageBIOS
& rBIOS
)
321 storeError eErrCode
= rBIOS
.loadObjectAt (*this, nAddr
);
322 if (eErrCode
!= store_E_NotExists
)
325 eErrCode
= construct
<page
>(rBIOS
.allocator());
326 if (eErrCode
!= store_E_None
)
329 eErrCode
= rBIOS
.allocate (*this);
330 if (eErrCode
!= store_E_None
)
333 // Notify caller of the creation.
334 (void) testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave");
335 return store_E_Pending
;
341 storeError
OStoreBTreeRootObject::change (
342 PageHolderObject
< page
> & rxPageL
,
343 OStorePageBIOS
& rBIOS
)
345 PageHolderObject
< page
> xPage (m_xPage
);
346 (void) testInvariant("OStoreBTreeRootObject::change(): enter");
348 // Save root location.
349 sal_uInt32
const nRootAddr
= xPage
->location();
351 // Construct new root.
352 if (!rxPageL
.construct (rBIOS
.allocator()))
353 return store_E_OutOfMemory
;
355 // Save this as prev root.
356 storeError eErrCode
= rBIOS
.allocate (*this);
357 if (eErrCode
!= store_E_None
)
358 return store_E_OutOfMemory
;
361 rxPageL
->depth (xPage
->depth() + 1);
362 rxPageL
->m_pData
[0] = xPage
->m_pData
[0];
363 rxPageL
->m_pData
[0].m_aLink
= xPage
->location();
364 rxPageL
->usageCount(1);
367 rxPageL
.swap (xPage
);
369 PageHolder
tmp (xPage
.get());
373 // Save this as new root and finish.
374 eErrCode
= rBIOS
.saveObjectAt (*this, nRootAddr
);
375 (void) testInvariant("OStoreBTreeRootObject::change(): leave");
380 * find_lookup (w/o split()).
381 * Precond: root node page loaded.
383 storeError
OStoreBTreeRootObject::find_lookup (
384 OStoreBTreeNodeObject
& rNode
, // [out]
385 sal_uInt16
& rIndex
, // [out]
386 OStorePageKey
const & rKey
,
387 OStorePageBIOS
& rBIOS
)
389 // Init node w/ root page.
390 (void) testInvariant("OStoreBTreeRootObject::find_lookup(): enter");
392 PageHolder
tmp (m_xPage
);
393 tmp
.swap (rNode
.get());
396 // Setup BTree entry.
397 T
const entry (rKey
);
399 // Check current page.
400 PageHolderObject
< page
> xPage (rNode
.get());
401 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
404 page
const & rPage
= (*xPage
);
405 sal_uInt16
const i
= rPage
.find(entry
);
406 sal_uInt16
const n
= rPage
.usageCount();
409 // Path to entry not exists (Must not happen(?)).
410 return store_E_NotExists
;
414 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
415 if (nAddr
== STORE_PAGE_NULL
)
417 // Path to entry not exists (Must not happen(?)).
418 return store_E_NotExists
;
422 storeError eErrCode
= rBIOS
.loadObjectAt (rNode
, nAddr
);
423 if (eErrCode
!= store_E_None
)
428 page
const & rPage
= (*xPage
);
429 rIndex
= rPage
.find(entry
);
430 if (!(rIndex
< rPage
.usageCount()))
431 return store_E_NotExists
;
434 T::CompareResult eResult
= entry
.compare(rPage
.m_pData
[rIndex
]);
435 OSL_POSTCOND(eResult
!= T::COMPARE_LESS
, "store::BTreeRoot::find_lookup(): sort error");
436 if (eResult
== T::COMPARE_LESS
)
437 return store_E_Unknown
;
440 (void) testInvariant("OStoreBTreeRootObject::find_lookup(): leave");
445 * find_insert (possibly with split()).
446 * Precond: root node page loaded.
448 storeError
OStoreBTreeRootObject::find_insert (
449 OStoreBTreeNodeObject
& rNode
, // [out]
450 sal_uInt16
& rIndex
, // [out]
451 OStorePageKey
const & rKey
,
452 OStorePageBIOS
& rBIOS
)
454 (void) testInvariant("OStoreBTreeRootObject::find_insert(): enter");
456 // Check for RootNode split.
457 PageHolderObject
< page
> xRoot (m_xPage
);
458 if (xRoot
->querySplit())
460 PageHolderObject
< page
> xPageL
;
463 storeError eErrCode
= change (xPageL
, rBIOS
);
464 if (eErrCode
!= store_E_None
)
467 // Split left page (prev root).
468 eErrCode
= split (0, xPageL
, rBIOS
);
469 if (eErrCode
!= store_E_None
)
473 // Init node w/ root page.
475 PageHolder
tmp (m_xPage
);
476 tmp
.swap (rNode
.get());
479 // Setup BTree entry.
480 T
const entry (rKey
);
482 // Check current Page.
483 PageHolderObject
< page
> xPage (rNode
.get());
484 for (; xPage
->depth() > 0; xPage
= rNode
.makeHolder
< page
>())
487 page
const & rPage
= (*xPage
);
488 sal_uInt16
const i
= rPage
.find (entry
);
489 sal_uInt16
const n
= rPage
.usageCount();
492 // Path to entry not exists (Must not happen(?)).
493 return store_E_NotExists
;
497 sal_uInt32
const nAddr
= rPage
.m_pData
[i
].m_aLink
.location();
498 if (nAddr
== STORE_PAGE_NULL
)
500 // Path to entry not exists (Must not happen(?)).
501 return store_E_NotExists
;
505 OStoreBTreeNodeObject aNext
;
506 storeError eErrCode
= rBIOS
.loadObjectAt (aNext
, nAddr
);
507 if (eErrCode
!= store_E_None
)
510 // Check for next node split.
511 PageHolderObject
< page
> xNext (aNext
.get());
512 if (xNext
->querySplit())
515 eErrCode
= rNode
.split (i
, xNext
, rBIOS
);
516 if (eErrCode
!= store_E_None
)
523 // Let next page be current.
524 PageHolder
tmp (aNext
.get());
525 tmp
.swap (rNode
.get());
529 page
const & rPage
= (*xPage
);
530 rIndex
= rPage
.find(entry
);
531 if (rIndex
< rPage
.usageCount())
534 T::CompareResult result
= entry
.compare (rPage
.m_pData
[rIndex
]);
535 OSL_POSTCOND(result
!= T::COMPARE_LESS
, "store::BTreeRoot::find_insert(): sort error");
536 if (result
== T::COMPARE_LESS
)
537 return store_E_Unknown
;
539 if (result
== T::COMPARE_EQUAL
)
540 return store_E_AlreadyExists
;
543 // Greater or not (yet) existing.
544 (void) testInvariant("OStoreBTreeRootObject::find_insert(): leave");
548 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */