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