Branch data Line data Source code
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 : :
21 : : #include "storbios.hxx"
22 : :
23 : : #include "sal/types.h"
24 : : #include "sal/macros.h"
25 : :
26 : : #include "rtl/alloc.h"
27 : : #include "rtl/ref.hxx"
28 : :
29 : : #include "osl/diagnose.h"
30 : : #include "osl/mutex.hxx"
31 : :
32 : : #include "store/types.h"
33 : : #include "object.hxx"
34 : : #include "lockbyte.hxx"
35 : : #include "storcach.hxx"
36 : :
37 : : using namespace store;
38 : :
39 : : /*========================================================================
40 : : *
41 : : * OStoreSuperBlock.
42 : : *
43 : : *======================================================================*/
44 : : #define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
45 : :
46 : : struct OStoreSuperBlock
47 : : {
48 : : typedef OStorePageGuard G;
49 : : typedef OStorePageDescriptor D;
50 : : typedef OStorePageLink L;
51 : :
52 : : /** Representation.
53 : : */
54 : : G m_aGuard;
55 : : D m_aDescr;
56 : : sal_uInt32 m_nMarked;
57 : : L m_aMarked;
58 : : sal_uInt32 m_nUnused;
59 : : L m_aUnused;
60 : :
61 : : /** theSize.
62 : : */
63 : : static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32));
64 : :
65 : : /** Construction.
66 : : */
67 : 35588 : explicit OStoreSuperBlock (sal_uInt16 nPageSize)
68 : : : m_aGuard (STORE_MAGIC_SUPERBLOCK),
69 : : m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
70 : 35588 : m_nMarked (store::htonl(0)),
71 : : m_aMarked (0),
72 : 35588 : m_nUnused (store::htonl(0)),
73 : 106764 : m_aUnused (0)
74 : 35588 : {}
75 : :
76 : : OStoreSuperBlock (const OStoreSuperBlock & rhs)
77 : : : m_aGuard (rhs.m_aGuard),
78 : : m_aDescr (rhs.m_aDescr),
79 : : m_nMarked (rhs.m_nMarked),
80 : : m_aMarked (rhs.m_aMarked),
81 : : m_nUnused (rhs.m_nUnused),
82 : : m_aUnused (rhs.m_aUnused)
83 : : {}
84 : :
85 : 30403 : OStoreSuperBlock& operator= (const OStoreSuperBlock & rhs)
86 : : {
87 : 30403 : m_aGuard = rhs.m_aGuard;
88 : 30403 : m_aDescr = rhs.m_aDescr;
89 : 30403 : m_nMarked = rhs.m_nMarked;
90 : 30403 : m_aMarked = rhs.m_aMarked;
91 : 30403 : m_nUnused = rhs.m_nUnused;
92 : 30403 : m_aUnused = rhs.m_aUnused;
93 : 30403 : return *this;
94 : : }
95 : :
96 : : /** Comparison.
97 : : */
98 : 159662 : sal_Bool operator== (const OStoreSuperBlock & rhs) const
99 : : {
100 : 159662 : return ((m_aGuard == rhs.m_aGuard ) &&
101 : 159662 : (m_aDescr == rhs.m_aDescr ) &&
102 : : (m_nMarked == rhs.m_nMarked) &&
103 : 159662 : (m_aMarked == rhs.m_aMarked) &&
104 : : (m_nUnused == rhs.m_nUnused) &&
105 [ + - + - ]: 478986 : (m_aUnused == rhs.m_aUnused) );
[ + - ][ + - ]
[ + - + - ]
106 : : }
107 : :
108 : : /** unused(Count|Head|Insert|Remove|Reset).
109 : : */
110 : 24152 : sal_uInt32 unusedCount (void) const
111 : : {
112 : 24152 : return store::ntohl(m_nUnused);
113 : : }
114 : 148522 : const L& unusedHead (void) const
115 : : {
116 : 148522 : return m_aUnused;
117 : : }
118 : 12087 : void unusedInsert (const L& rLink)
119 : : {
120 : 12087 : sal_uInt32 nUnused = unusedCount();
121 : 12087 : m_nUnused = store::htonl(nUnused + 1);
122 : 12087 : m_aUnused = rLink;
123 : 12087 : }
124 : 12065 : void unusedRemove (const L& rLink)
125 : : {
126 : 12065 : sal_uInt32 nUnused = unusedCount();
127 : 12065 : m_nUnused = store::htonl(nUnused - 1);
128 : 12065 : m_aUnused = rLink;
129 : 12065 : }
130 : 0 : void unusedReset (void)
131 : : {
132 : 0 : m_nUnused = store::htonl(0);
133 : 0 : m_aUnused = L(0);
134 : 0 : }
135 : :
136 : : /** guard (external representation).
137 : : */
138 : 30403 : void guard()
139 : : {
140 : 30403 : sal_uInt32 nCRC32 = 0;
141 : 30403 : nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
142 : 30403 : nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
143 : 30403 : m_aGuard.m_nCRC32 = store::htonl(nCRC32);
144 : 30403 : }
145 : :
146 : : /** verify (external representation).
147 : : */
148 : 320122 : storeError verify() const
149 : : {
150 : 320122 : sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
151 [ + + ]: 320122 : if (nMagic != STORE_MAGIC_SUPERBLOCK)
152 : 798 : return store_E_WrongFormat;
153 : :
154 : 319324 : sal_uInt32 nCRC32 = 0;
155 : 319324 : nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
156 : 319324 : nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
157 [ - + ]: 319324 : if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
158 : 0 : return store_E_InvalidChecksum;
159 : : else
160 : 320122 : return store_E_None;
161 : : }
162 : : };
163 : :
164 : : /*========================================================================
165 : : *
166 : : * SuperBlockPage interface.
167 : : *
168 : : *======================================================================*/
169 : : namespace store
170 : : {
171 : :
172 : : struct SuperBlockPage
173 : : {
174 : : typedef OStoreSuperBlock SuperBlock;
175 : :
176 : : /** Representation.
177 : : */
178 : : SuperBlock m_aSuperOne;
179 : : SuperBlock m_aSuperTwo;
180 : :
181 : : /** theSize.
182 : : */
183 : : static const size_t theSize = 2 * SuperBlock::theSize;
184 : : static const sal_uInt16 thePageSize = theSize;
185 : : STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize);
186 : :
187 : : /** Allocation.
188 : : */
189 : 11543 : static void * operator new (size_t n) SAL_THROW(())
190 : : {
191 : 11543 : return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
192 : : }
193 : 51880 : static void operator delete (void * p) SAL_THROW(())
194 : : {
195 : 51880 : rtl_freeMemory (p);
196 : 51880 : }
197 : :
198 : 6251 : static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize) SAL_THROW(())
199 : : {
200 : 6251 : return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
201 : : }
202 : : static void operator delete (void * p, SAL_UNUSED_PARAMETER sal_uInt16) SAL_THROW(())
203 : : {
204 : : rtl_freeMemory (p);
205 : : }
206 : :
207 : : /** Construction.
208 : : */
209 : 17794 : explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
210 : : : m_aSuperOne(nPageSize),
211 : 17794 : m_aSuperTwo(nPageSize)
212 : 17794 : {}
213 : :
214 : : /** save.
215 : : */
216 : 30403 : storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
217 : : {
218 : 30403 : m_aSuperOne.guard();
219 : 30403 : m_aSuperTwo = m_aSuperOne;
220 : 30403 : return rBIOS.write (0, this, nSize);
221 : : }
222 : :
223 : : /** Page allocation.
224 : : */
225 : : storeError unusedHead (
226 : : OStorePageBIOS & rBIOS,
227 : : PageData & rPageHead);
228 : :
229 : : storeError unusedPop (
230 : : OStorePageBIOS & rBIOS,
231 : : PageData const & rPageHead);
232 : :
233 : : storeError unusedPush (
234 : : OStorePageBIOS & rBIOS,
235 : : sal_uInt32 nAddr);
236 : :
237 : : /** verify (with repair).
238 : : */
239 : : storeError verify (OStorePageBIOS & rBIOS);
240 : : };
241 : :
242 : : } // namespace store
243 : :
244 : : /*========================================================================
245 : : *
246 : : * SuperBlockPage implementation.
247 : : *
248 : : *======================================================================*/
249 : : /*
250 : : * unusedHead(): get freelist head (alloc page, step 1).
251 : : */
252 : 136435 : storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
253 : : {
254 [ + - ]: 136435 : storeError eErrCode = verify (rBIOS);
255 [ - + ]: 136435 : if (eErrCode != store_E_None)
256 : 0 : return eErrCode;
257 : :
258 : : // Check freelist head.
259 : 136435 : OStorePageLink const aListHead (m_aSuperOne.unusedHead());
260 [ + + ]: 136435 : if (aListHead.location() == 0)
261 : : {
262 : : // Freelist empty, see SuperBlock::ctor().
263 : 124370 : rPageHead.location (STORE_PAGE_NULL);
264 : 124370 : return store_E_None;
265 : : }
266 : :
267 : : // Load PageHead.
268 [ + - ]: 12065 : eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
269 [ - + ]: 12065 : if (eErrCode != store_E_None)
270 : 0 : return eErrCode;
271 : :
272 : 12065 : eErrCode = rPageHead.verify (aListHead.location());
273 [ - + ]: 12065 : if (eErrCode != store_E_None)
274 : 0 : return eErrCode;
275 : :
276 : : // Verify page is unused.
277 : 12065 : sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
278 : : OSL_POSTCOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedHead(): page not free");
279 [ - + ]: 12065 : if (nAddr == STORE_PAGE_NULL)
280 : : {
281 : : // Page in use.
282 : 0 : rPageHead.location (STORE_PAGE_NULL);
283 : :
284 : : // Recovery: Reset freelist to empty.
285 : 0 : m_aSuperOne.unusedReset();
286 [ # # ]: 0 : eErrCode = save (rBIOS);
287 : : }
288 : 136435 : return eErrCode;
289 : : }
290 : :
291 : : /*
292 : : * unusedPop(): pop freelist head (alloc page, step 2).
293 : : */
294 : 12065 : storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
295 : : {
296 : 12065 : sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
297 : : OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
298 [ - + ]: 12065 : if (nAddr == STORE_PAGE_NULL)
299 : 0 : return store_E_CantSeek;
300 : :
301 : : // Pop from FreeList.
302 : 12065 : OStorePageLink const aListHead (nAddr);
303 : 12065 : m_aSuperOne.unusedRemove (aListHead);
304 [ + - ]: 12065 : return save (rBIOS);
305 : : }
306 : :
307 : : /*
308 : : * unusedPush(): push new freelist head.
309 : : */
310 : 12087 : storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
311 : : {
312 [ + - ]: 12087 : storeError eErrCode = verify (rBIOS);
313 [ - + ]: 12087 : if (eErrCode != store_E_None)
314 : 0 : return eErrCode;
315 : :
316 : 12087 : PageData aPageHead;
317 [ + - ]: 12087 : eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
318 [ - + ]: 12087 : if (eErrCode != store_E_None)
319 : 0 : return eErrCode;
320 : :
321 : 12087 : eErrCode = aPageHead.verify (nAddr);
322 [ - + ]: 12087 : if (eErrCode != store_E_None)
323 : 0 : return eErrCode;
324 : :
325 : 12087 : aPageHead.m_aUnused = m_aSuperOne.unusedHead();
326 : 12087 : aPageHead.guard (nAddr);
327 : :
328 [ + - ]: 12087 : eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
329 [ - + ]: 12087 : if (eErrCode != store_E_None)
330 : 0 : return eErrCode;
331 : :
332 : 12087 : OStorePageLink const aListHead (nAddr);
333 : 12087 : m_aSuperOne.unusedInsert(aListHead);
334 [ + - ]: 12087 : return save (rBIOS);
335 : : }
336 : :
337 : : /*
338 : : * verify (with repair).
339 : : */
340 : 160061 : storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS)
341 : : {
342 : : // Verify 1st copy.
343 : 160061 : storeError eErrCode = m_aSuperOne.verify();
344 [ + + ]: 160061 : if (eErrCode == store_E_None)
345 : : {
346 : : // Ok. Verify 2nd copy.
347 : 159662 : eErrCode = m_aSuperTwo.verify();
348 [ + - ]: 159662 : if (eErrCode == store_E_None)
349 : : {
350 : : // Ok. Ensure identical copies (1st copy wins).
351 [ - + ]: 159662 : if (!(m_aSuperOne == m_aSuperTwo))
352 : : {
353 : : // Different. Replace 2nd copy with 1st copy.
354 : 0 : m_aSuperTwo = m_aSuperOne;
355 : :
356 : : // Write back.
357 [ # # ]: 0 : if (rBIOS.isWriteable())
358 : 0 : eErrCode = rBIOS.write (0, this, theSize);
359 : : else
360 : 0 : eErrCode = store_E_None;
361 : : }
362 : : }
363 : : else
364 : : {
365 : : // Failure. Replace 2nd copy with 1st copy.
366 : 0 : m_aSuperTwo = m_aSuperOne;
367 : :
368 : : // Write back.
369 [ # # ]: 0 : if (rBIOS.isWriteable())
370 : 0 : eErrCode = rBIOS.write (0, this, theSize);
371 : : else
372 : 0 : eErrCode = store_E_None;
373 : : }
374 : : }
375 : : else
376 : : {
377 : : // Failure. Verify 2nd copy.
378 : 399 : eErrCode = m_aSuperTwo.verify();
379 [ - + ]: 399 : if (eErrCode == store_E_None)
380 : : {
381 : : // Ok. Replace 1st copy with 2nd copy.
382 : 0 : m_aSuperOne = m_aSuperTwo;
383 : :
384 : : // Write back.
385 [ # # ]: 0 : if (rBIOS.isWriteable())
386 : 0 : eErrCode = rBIOS.write (0, this, theSize);
387 : : else
388 : 0 : eErrCode = store_E_None;
389 : : }
390 : : else
391 : : {
392 : : // Double Failure.
393 : : OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.");
394 : : }
395 : : }
396 : :
397 : : // Done.
398 : 160061 : return eErrCode;
399 : : }
400 : :
401 : : /*========================================================================
402 : : *
403 : : * OStorePageBIOS::Ace implementation.
404 : : *
405 : : *======================================================================*/
406 : 17794 : OStorePageBIOS::Ace::Ace()
407 : 17794 : : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
408 : 17794 : {}
409 : :
410 : 17043 : OStorePageBIOS::Ace::~Ace()
411 : : {
412 : 17043 : m_next->m_prev = m_prev, m_prev->m_next = m_next;
413 : 17043 : }
414 : :
415 : : int
416 : 169554 : SAL_CALL OStorePageBIOS::Ace::constructor (
417 : : void * obj, SAL_UNUSED_PARAMETER void * /* arg */)
418 : : {
419 : 169554 : Ace * ace = static_cast<Ace*>(obj);
420 : 169554 : ace->m_next = ace->m_prev = ace;
421 : 169554 : return 1;
422 : : }
423 : :
424 : : OStorePageBIOS::Ace *
425 : 2397970 : OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
426 : : {
427 : : OStorePageBIOS::Ace * entry;
428 [ + + ]: 4885638 : for (entry = head->m_next; entry != head; entry = entry->m_next)
429 : : {
430 [ + + ]: 3686653 : if (entry->m_addr >= addr)
431 : 1198985 : return entry;
432 : : }
433 : 2397970 : return head;
434 : : }
435 : :
436 : : void
437 : 1198985 : OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
438 : : {
439 : : // insert entry at queue tail (before head).
440 : 1198985 : entry->m_next = head;
441 : 1198985 : entry->m_prev = head->m_prev;
442 : 1198985 : head->m_prev = entry;
443 : 1198985 : entry->m_prev->m_next = entry;
444 : 1198985 : }
445 : :
446 : : /*========================================================================
447 : : *
448 : : * OStorePageBIOS::AceCache interface.
449 : : *
450 : : *======================================================================*/
451 : : namespace store
452 : : {
453 : :
454 : : class OStorePageBIOS::AceCache
455 : : {
456 : : rtl_cache_type * m_ace_cache;
457 : :
458 : : public:
459 : : static AceCache & get();
460 : :
461 : : OStorePageBIOS::Ace *
462 : : create (sal_uInt32 addr, sal_uInt32 used = 1);
463 : :
464 : : void
465 : : destroy (OStorePageBIOS::Ace * ace);
466 : :
467 : : protected:
468 : : AceCache();
469 : : ~AceCache();
470 : : };
471 : :
472 : : } // namespace store
473 : :
474 : : /*========================================================================
475 : : *
476 : : * OStorePageBIOS::AceCache implementation.
477 : : *
478 : : *======================================================================*/
479 : : extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*);
480 : :
481 : : OStorePageBIOS::AceCache &
482 : 2397970 : OStorePageBIOS::AceCache::get()
483 : : {
484 [ + + ][ + - ]: 2397970 : static AceCache g_ace_cache;
485 : 2397970 : return g_ace_cache;
486 : : }
487 : :
488 : 960 : OStorePageBIOS::AceCache::AceCache()
489 : : {
490 : : m_ace_cache = rtl_cache_create (
491 : : "store_ace_cache",
492 : : sizeof (OStorePageBIOS::Ace),
493 : : 0, // objalign
494 : : reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor),
495 : : 0, // destructor,
496 : : 0, // reclaim,
497 : : 0, // userarg,
498 : : 0, // default source,
499 : : 0 // flags
500 : 960 : );
501 : 960 : }
502 : :
503 : 960 : OStorePageBIOS::AceCache::~AceCache()
504 : : {
505 : 960 : rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
506 : 960 : }
507 : :
508 : : OStorePageBIOS::Ace *
509 : 1198985 : OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
510 : : {
511 : 1198985 : Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
512 [ + - ]: 1198985 : if (ace != 0)
513 : : {
514 : : // verify invariant state.
515 : : OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
516 : :
517 : : // initialize.
518 : 1198985 : ace->m_addr = addr;
519 : 1198985 : ace->m_used = used;
520 : : }
521 : 1198985 : return ace;
522 : : }
523 : :
524 : : void
525 : 1198985 : OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
526 : : {
527 [ + - ]: 1198985 : if (ace != 0)
528 : : {
529 : : // remove from queue (if any).
530 : 1198985 : ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
531 : :
532 : : // restore invariant state.
533 : 1198985 : ace->m_next = ace->m_prev = ace;
534 : :
535 : : // return to cache.
536 : 1198985 : rtl_cache_free (m_ace_cache, ace);
537 : : }
538 : 1198985 : }
539 : :
540 : : /*========================================================================
541 : : *
542 : : * OStorePageBIOS implementation.
543 : : *
544 : : *======================================================================*/
545 : : /*
546 : : * OStorePageBIOS.
547 : : */
548 : 17794 : OStorePageBIOS::OStorePageBIOS (void)
549 : : : m_xLockBytes (NULL),
550 : : m_pSuper (NULL),
551 [ + - ][ + - ]: 17794 : m_bWriteable (false)
552 : : {
553 : 17794 : }
554 : :
555 : : /*
556 : : * ~OStorePageBIOS.
557 : : */
558 [ + - ][ + - ]: 17043 : OStorePageBIOS::~OStorePageBIOS (void)
[ + - ][ + - ]
559 : : {
560 [ + - ]: 17043 : cleanup_Impl();
561 [ - + ]: 17043 : }
562 : :
563 : : /*
564 : : * initialize.
565 : : * Precond: none.
566 : : */
567 : 17794 : storeError OStorePageBIOS::initialize (
568 : : ILockBytes * pLockBytes,
569 : : storeAccessMode eAccessMode,
570 : : sal_uInt16 & rnPageSize)
571 : : {
572 : : // Acquire exclusive access.
573 [ + - ]: 17794 : osl::MutexGuard aGuard (m_aMutex);
574 : :
575 : : // Initialize.
576 [ + - ]: 17794 : storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
577 [ + + ]: 17794 : if (eErrCode != store_E_None)
578 : : {
579 : : // Cleanup.
580 [ + - ]: 403 : cleanup_Impl();
581 : : }
582 [ + - ]: 17794 : return eErrCode;
583 : : }
584 : :
585 : : /*
586 : : * initialize_Impl.
587 : : * Internal: Precond: exclusive access.
588 : : */
589 : 17794 : storeError OStorePageBIOS::initialize_Impl (
590 : : ILockBytes * pLockBytes,
591 : : storeAccessMode eAccessMode,
592 : : sal_uInt16 & rnPageSize)
593 : : {
594 : : // Cleanup.
595 : 17794 : cleanup_Impl();
596 : :
597 : : // Initialize.
598 : 17794 : m_xLockBytes = pLockBytes;
599 [ - + ]: 17794 : if (!m_xLockBytes.is())
600 : 0 : return store_E_InvalidParameter;
601 : 17794 : m_bWriteable = (eAccessMode != store_AccessReadOnly);
602 : :
603 : : // Check access mode.
604 : 17794 : storeError eErrCode = store_E_None;
605 [ + + ]: 17794 : if (eAccessMode != store_AccessCreate)
606 : : {
607 : : // Load SuperBlock page.
608 [ - + ]: 11543 : if ((m_pSuper = new SuperBlockPage()) == 0)
609 : 0 : return store_E_OutOfMemory;
610 : :
611 : 11543 : eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
612 [ + + ]: 11543 : if (eErrCode == store_E_None)
613 : : {
614 : : // Verify SuperBlock page (with repair).
615 : 11539 : eErrCode = m_pSuper->verify (*this);
616 : : }
617 : : }
618 : : else
619 : : {
620 : : // Truncate to zero length.
621 : 6251 : eErrCode = m_xLockBytes->setSize(0);
622 [ - + ]: 6251 : if (eErrCode != store_E_None)
623 : 0 : return eErrCode;
624 : :
625 : : // Mark as not existing.
626 : 6251 : eErrCode = store_E_NotExists;
627 : : }
628 : :
629 [ + + ]: 17794 : if (eErrCode != store_E_None)
630 : : {
631 : : // Check reason.
632 [ + + ]: 6654 : if (eErrCode != store_E_NotExists)
633 : 399 : return eErrCode;
634 : :
635 : : // Check mode.
636 [ + + ]: 6255 : if (eAccessMode == store_AccessReadOnly)
637 : 4 : return store_E_NotExists;
638 [ - + ]: 6251 : if (eAccessMode == store_AccessReadWrite)
639 : 0 : return store_E_NotExists;
640 : :
641 : : // Check PageSize.
642 [ + - ][ - + ]: 6251 : if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
643 : 0 : return store_E_InvalidParameter;
644 : 6251 : rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
645 : :
646 : : // Create initial page (w/ SuperBlock).
647 [ - + ]: 6251 : if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
648 : 0 : return store_E_OutOfMemory;
649 : 6251 : eErrCode = m_pSuper->save (*this, rnPageSize);
650 : : }
651 [ + - ]: 17391 : if (eErrCode == store_E_None)
652 : : {
653 : : // Obtain page size.
654 : 17391 : rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
655 : :
656 : : // Create page allocator.
657 : 17391 : eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
658 [ - + ]: 17391 : if (eErrCode != store_E_None)
659 : 0 : return eErrCode;
660 : :
661 : : // Create page cache.
662 : 17391 : eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
663 : : }
664 : 17794 : return eErrCode;
665 : : }
666 : :
667 : : /*
668 : : * cleanup_Impl.
669 : : * Internal: Precond: exclusive access.
670 : : */
671 : 51880 : void OStorePageBIOS::cleanup_Impl()
672 : : {
673 : : // Check referer count.
674 [ - + ]: 51880 : if (m_ace_head.m_used > 0)
675 : : {
676 : : // Report remaining referer count.
677 : : OSL_TRACE("store::PageBIOS::cleanup_Impl(): referer count: %d", m_ace_head.m_used);
678 [ # # ]: 0 : for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next)
679 : : {
680 : 0 : m_ace_head.m_used -= ace->m_used;
681 : 0 : AceCache::get().destroy (ace);
682 : : }
683 : : OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::cleanup_Impl(): logic error");
684 : : }
685 : :
686 : : // Release SuperBlock page.
687 : 51880 : delete m_pSuper, m_pSuper = 0;
688 : :
689 : : // Release PageCache.
690 : 51880 : m_xCache.clear();
691 : :
692 : : // Release PageAllocator.
693 : 51880 : m_xAllocator.clear();
694 : :
695 : : // Release LockBytes.
696 : 51880 : m_xLockBytes.clear();
697 : 51880 : }
698 : :
699 : : /*
700 : : * read.
701 : : * Low Level: Precond: initialized, exclusive access.
702 : : */
703 : 35695 : storeError OStorePageBIOS::read (
704 : : sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
705 : : {
706 : : // Check precond.
707 [ - + ]: 35695 : if (!m_xLockBytes.is())
708 : 0 : return store_E_InvalidAccess;
709 : :
710 : : // Read Data.
711 : 35695 : return m_xLockBytes->readAt (nAddr, pData, nSize);
712 : : }
713 : :
714 : : /*
715 : : * write.
716 : : * Low Level: Precond: initialized, writeable, exclusive access.
717 : : */
718 : 42490 : storeError OStorePageBIOS::write (
719 : : sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
720 : : {
721 : : // Check precond.
722 [ - + ]: 42490 : if (!m_xLockBytes.is())
723 : 0 : return store_E_InvalidAccess;
724 [ - + ]: 42490 : if (!m_bWriteable)
725 : 0 : return store_E_AccessViolation;
726 : :
727 : : // Write Data.
728 : 42490 : return m_xLockBytes->writeAt (nAddr, pData, nSize);
729 : : }
730 : :
731 : : /*
732 : : * acquirePage.
733 : : * Precond: initialized.
734 : : */
735 : 1198985 : storeError OStorePageBIOS::acquirePage (
736 : : const OStorePageDescriptor& rDescr, storeAccessMode eMode)
737 : : {
738 : : // Acquire exclusive access.
739 [ + - ]: 1198985 : osl::MutexGuard aGuard (m_aMutex);
740 : :
741 : : // Check precond.
742 [ - + ]: 1198985 : if (!m_xLockBytes.is())
743 : 0 : return store_E_InvalidAccess;
744 : :
745 : : // Check access mode.
746 [ + + ][ - + ]: 1198985 : if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
747 : 0 : return store_E_AccessViolation;
748 : :
749 : : // Find access control list entry.
750 : 1198985 : Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
751 [ - + ]: 1198985 : if (ace->m_addr == rDescr.m_nAddr)
752 : : {
753 : : // Acquire existing entry (with ShareDenyWrite).
754 [ # # ]: 0 : if (eMode == store_AccessReadOnly)
755 : 0 : ace->m_used += 1;
756 : : else
757 : 0 : return store_E_AccessViolation;
758 : : }
759 : : else
760 : : {
761 : : // Insert new entry.
762 [ + - ]: 1198985 : Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1);
763 [ - + ]: 1198985 : if (!entry)
764 : 0 : return store_E_OutOfMemory;
765 : 1198985 : Ace::insert (ace, entry);
766 : : }
767 : :
768 : : // Increment total referer count and finish.
769 : 1198985 : m_ace_head.m_used += 1;
770 [ + - ]: 1198985 : return store_E_None;
771 : : }
772 : :
773 : : /*
774 : : * releasePage.
775 : : * Precond: initialized.
776 : : */
777 : 1198985 : storeError OStorePageBIOS::releasePage (const OStorePageDescriptor& rDescr)
778 : : {
779 : : // Acquire exclusive access.
780 [ + - ]: 1198985 : osl::MutexGuard aGuard (m_aMutex);
781 : :
782 : : // Check precond.
783 [ - + ]: 1198985 : if (!m_xLockBytes.is())
784 : 0 : return store_E_InvalidAccess;
785 : :
786 : : // Find access control list entry.
787 : 1198985 : Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
788 [ - + ]: 1198985 : if (ace->m_addr != rDescr.m_nAddr)
789 : 0 : return store_E_NotExists;
790 : :
791 : : // Release existing entry.
792 [ - + ]: 1198985 : if (ace->m_used > 1)
793 : 0 : ace->m_used -= 1;
794 : : else
795 [ + - ]: 1198985 : AceCache::get().destroy (ace);
796 : :
797 : : // Decrement total referer count and finish.
798 : 1198985 : m_ace_head.m_used -= 1;
799 [ + - ]: 1198985 : return store_E_None;
800 : : }
801 : :
802 : : /*
803 : : * getRefererCount.
804 : : * Precond: none.
805 : : */
806 : 0 : sal_uInt32 OStorePageBIOS::getRefererCount (void)
807 : : {
808 : : // Acquire exclusive access.
809 [ # # ]: 0 : osl::MutexGuard aGuard (m_aMutex);
810 : :
811 : : // Obtain total referer count.
812 [ # # ]: 0 : return m_ace_head.m_used;
813 : : }
814 : :
815 : : /*
816 : : * allocate.
817 : : * Precond: initialized, writeable.
818 : : */
819 : 136435 : storeError OStorePageBIOS::allocate (
820 : : OStorePageObject& rPage, Allocation eAlloc)
821 : : {
822 : : // Acquire exclusive access.
823 [ + - ]: 136435 : osl::MutexGuard aGuard (m_aMutex);
824 : :
825 : : // Check precond.
826 [ - + ]: 136435 : if (!m_xLockBytes.is())
827 : 0 : return store_E_InvalidAccess;
828 [ - + ]: 136435 : if (!m_bWriteable)
829 : 0 : return store_E_AccessViolation;
830 : :
831 : : // Check allocation type.
832 : 136435 : storeError eErrCode = store_E_None;
833 [ + - ]: 136435 : if (eAlloc != ALLOCATE_EOF)
834 : : {
835 : : // Try freelist head.
836 : 136435 : PageData aPageHead;
837 [ + - ]: 136435 : eErrCode = m_pSuper->unusedHead (*this, aPageHead);
838 [ - + ]: 136435 : if (eErrCode != store_E_None)
839 : 0 : return eErrCode;
840 : :
841 : 136435 : sal_uInt32 const nAddr = aPageHead.location();
842 [ + + ]: 136435 : if (nAddr != STORE_PAGE_NULL)
843 : : {
844 : : // Save page.
845 [ + - ]: 12065 : eErrCode = saveObjectAt_Impl (rPage, nAddr);
846 [ - + ]: 12065 : if (eErrCode != store_E_None)
847 : 0 : return eErrCode;
848 : :
849 : : // Pop freelist head and finish.
850 [ + - ]: 136435 : return m_pSuper->unusedPop (*this, aPageHead);
851 : : }
852 : : }
853 : :
854 : : // Allocate from EOF. Determine current size.
855 : 124370 : sal_uInt32 nSize = STORE_PAGE_NULL;
856 [ + - ]: 124370 : eErrCode = m_xLockBytes->getSize (nSize);
857 [ - + ]: 124370 : if (eErrCode != store_E_None)
858 : 0 : return eErrCode;
859 : :
860 : : // Save page at current EOF.
861 [ + - ][ + - ]: 136435 : return saveObjectAt_Impl (rPage, nSize);
862 : : }
863 : :
864 : : /*
865 : : * free.
866 : : * Precond: initialized, writeable.
867 : : */
868 : 12087 : storeError OStorePageBIOS::free (sal_uInt32 nAddr)
869 : : {
870 : : // Acquire exclusive access.
871 [ + - ]: 12087 : osl::MutexGuard aGuard (m_aMutex);
872 : :
873 : : // Check precond.
874 [ - + ]: 12087 : if (!m_xLockBytes.is())
875 : 0 : return store_E_InvalidAccess;
876 [ - + ]: 12087 : if (!m_bWriteable)
877 : 0 : return store_E_AccessViolation;
878 : :
879 : : // Invalidate cache.
880 [ + - ]: 12087 : (void) m_xCache->removePageAt (nAddr);
881 : :
882 : : // Push onto freelist.
883 [ + - ][ + - ]: 12087 : return m_pSuper->unusedPush (*this, nAddr);
884 : : }
885 : :
886 : : /*
887 : : * loadObjectAt.
888 : : * Precond: initialized, readable.
889 : : */
890 : 5563111 : storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
891 : : {
892 : : // Acquire exclusive access.
893 [ + - ]: 5563111 : osl::MutexGuard aGuard (m_aMutex);
894 : :
895 : : // Check precond.
896 [ - + ]: 5563111 : if (!m_xLockBytes.is())
897 : 0 : return store_E_InvalidAccess;
898 : :
899 [ + - ][ + - ]: 5563111 : return loadObjectAt_Impl (rPage, nAddr);
900 : : }
901 : :
902 : : /*
903 : : * loadObjectAt_Impl.
904 : : * Internal: Precond: initialized, readable, exclusive access.
905 : : */
906 : 5563111 : storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
907 : : {
908 : 5563111 : storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
909 [ + + ]: 5563111 : if (eErrCode != store_E_NotExists)
910 : 4899045 : return eErrCode;
911 : :
912 : : // Read page.
913 : 664066 : eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
914 [ + + ]: 664066 : if (eErrCode != store_E_None)
915 : 6251 : return eErrCode;
916 : :
917 : : // Verify page.
918 : 657815 : eErrCode = rPage.verify (nAddr);
919 [ - + ]: 657815 : if (eErrCode != store_E_None)
920 : 0 : return eErrCode;
921 : :
922 : : // Mark page as clean.
923 : 657815 : rPage.clean();
924 : :
925 : : // Cache page.
926 : 5563111 : return m_xCache->insertPageAt (rPage.get(), nAddr);
927 : : }
928 : :
929 : : /*
930 : : * saveObjectAt.
931 : : * Precond: initialized, writeable.
932 : : */
933 : 240114 : storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
934 : : {
935 : : // Acquire exclusive access.
936 [ + - ]: 240114 : osl::MutexGuard aGuard (m_aMutex);
937 : :
938 : : // Check precond.
939 [ - + ]: 240114 : if (!m_xLockBytes.is())
940 : 0 : return store_E_InvalidAccess;
941 [ - + ]: 240114 : if (!m_bWriteable)
942 : 0 : return store_E_AccessViolation;
943 : :
944 : : // Save Page.
945 [ + - ][ + - ]: 240114 : return saveObjectAt_Impl (rPage, nAddr);
946 : : }
947 : :
948 : : /*
949 : : * saveObjectAt_Impl.
950 : : * Internal: Precond: initialized, writeable, exclusive access.
951 : : */
952 : 376549 : storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
953 : : {
954 : : // Guard page (incl. set location).
955 : 376549 : storeError eErrCode = rPage.guard (nAddr);
956 [ - + ]: 376549 : if (eErrCode != store_E_None)
957 : 0 : return eErrCode;
958 : :
959 : : // Write page.
960 : 376549 : eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
961 [ - + ]: 376549 : if (eErrCode != store_E_None)
962 : 0 : return eErrCode;
963 : :
964 : : // Mark page as clean.
965 : 376549 : rPage.clean();
966 : :
967 : : // Cache page.
968 : 376549 : return m_xCache->updatePageAt (rPage.get(), nAddr);
969 : : }
970 : :
971 : : /*
972 : : * close.
973 : : * Precond: none.
974 : : */
975 : 16640 : storeError OStorePageBIOS::close()
976 : : {
977 : : // Acquire exclusive access.
978 [ + - ]: 16640 : osl::MutexGuard aGuard (m_aMutex);
979 : :
980 : : // Cleanup.
981 [ + - ]: 16640 : cleanup_Impl();
982 : :
983 : : // Done.
984 [ + - ]: 16640 : return store_E_None;
985 : : }
986 : :
987 : : /*
988 : : * flush.
989 : : * Precond: initialized.
990 : : */
991 : 66 : storeError OStorePageBIOS::flush (void)
992 : : {
993 : : // Acquire exclusive access.
994 [ + - ]: 66 : osl::MutexGuard aGuard (m_aMutex);
995 : :
996 : : // Check precond.
997 [ - + ]: 66 : if (!m_xLockBytes.is())
998 : 0 : return store_E_InvalidAccess;
999 : :
1000 : : // Flush LockBytes and finish.
1001 [ + - ][ + - ]: 66 : return m_xLockBytes->flush();
1002 : : }
1003 : :
1004 : : /*
1005 : : * size.
1006 : : * Precond: initialized.
1007 : : */
1008 : 0 : storeError OStorePageBIOS::size (sal_uInt32 &rnSize)
1009 : : {
1010 : : // Acquire exclusive access.
1011 [ # # ]: 0 : osl::MutexGuard aGuard (m_aMutex);
1012 : :
1013 : : // Initialize [out] param.
1014 : 0 : rnSize = 0;
1015 : :
1016 : : // Check precond.
1017 [ # # ]: 0 : if (!m_xLockBytes.is())
1018 : 0 : return store_E_InvalidAccess;
1019 : :
1020 : : // Obtain LockBytes size.
1021 [ # # ][ # # ]: 0 : return m_xLockBytes->getSize (rnSize);
1022 : : }
1023 : :
1024 : : /*
1025 : : * scanBegin.
1026 : : * Precond: initialized.
1027 : : */
1028 : 0 : storeError OStorePageBIOS::scanBegin (
1029 : : ScanContext &rCtx, sal_uInt32 nMagic)
1030 : : {
1031 : : // Acquire exclusive access.
1032 [ # # ]: 0 : osl::MutexGuard aGuard (m_aMutex);
1033 : :
1034 : : // Initialize [out] param.
1035 : 0 : rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0);
1036 : 0 : rCtx.m_nSize = 0;
1037 : 0 : rCtx.m_nMagic = nMagic;
1038 : :
1039 : : // Check precond.
1040 [ # # ]: 0 : if (!m_xLockBytes.is())
1041 : 0 : return store_E_InvalidAccess;
1042 : :
1043 : : // Check SuperBlock page.
1044 [ # # ]: 0 : storeError eErrCode = m_pSuper->verify (*this);
1045 [ # # ]: 0 : if (eErrCode != store_E_None)
1046 : : {
1047 : : // Damaged. Determine page size (NYI).
1048 : : OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n");
1049 : 0 : return eErrCode;
1050 : : }
1051 : :
1052 : : // Setup Context descriptor.
1053 : 0 : rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr;
1054 : 0 : rCtx.m_aDescr.m_nSize = store::ntohs(rCtx.m_aDescr.m_nSize);
1055 : 0 : rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize;
1056 : :
1057 : : // Setup Context size.
1058 [ # # ]: 0 : eErrCode = size (rCtx.m_nSize);
1059 [ # # ]: 0 : if (eErrCode != store_E_None)
1060 : 0 : rCtx.m_nSize = ((sal_uInt32)(~0));
1061 : :
1062 : : // Done.
1063 [ # # ]: 0 : return store_E_None;
1064 : : }
1065 : :
1066 : : /*
1067 : : * scanNext.
1068 : : * Precond: initialized.
1069 : : */
1070 : 0 : storeError OStorePageBIOS::scanNext (
1071 : : ScanContext &rCtx, OStorePageObject &rPage)
1072 : : {
1073 : : // Acquire exclusive access.
1074 [ # # ]: 0 : osl::MutexGuard aGuard (m_aMutex);
1075 : :
1076 : : // Check precond.
1077 [ # # ]: 0 : if (!m_xLockBytes.is())
1078 : 0 : return store_E_InvalidAccess;
1079 : :
1080 : : // Setup PageHead.
1081 : 0 : PageData aPageHead;
1082 : :
1083 : : // Check context.
1084 [ # # ]: 0 : while (rCtx.isValid())
1085 : : {
1086 : : // Assign next location.
1087 : 0 : sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr;
1088 : 0 : rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
1089 : :
1090 : : // Read PageHead.
1091 [ # # ]: 0 : storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize);
1092 [ # # ]: 0 : if (eErrCode != store_E_None)
1093 : 0 : continue;
1094 : :
1095 : : // Verify PageHead.
1096 : 0 : eErrCode = aPageHead.verify (nAddr);
1097 [ # # ]: 0 : if (eErrCode != store_E_None)
1098 : 0 : continue;
1099 : :
1100 : : // Check PageHead Magic number.
1101 [ # # ]: 0 : if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic)
1102 : 0 : continue;
1103 : :
1104 : : // Check PageHead Unused link.
1105 [ # # ]: 0 : if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL)
1106 : 0 : continue;
1107 : :
1108 : : // Load page.
1109 [ # # ]: 0 : eErrCode = loadObjectAt_Impl (rPage, nAddr);
1110 [ # # ]: 0 : if (eErrCode != store_E_None)
1111 : 0 : continue;
1112 : :
1113 : : // Deliver page.
1114 : 0 : return store_E_None;
1115 : : }
1116 : :
1117 : : // Done.
1118 [ # # ]: 0 : return store_E_CantSeek;
1119 : : }
1120 : :
1121 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|