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