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 21448 : explicit OStoreSuperBlock (sal_uInt16 nPageSize)
68 : : m_aGuard (STORE_MAGIC_SUPERBLOCK),
69 : m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
70 21448 : m_nMarked (store::htonl(0)),
71 : m_aMarked (0),
72 21448 : m_nUnused (store::htonl(0)),
73 64344 : m_aUnused (0)
74 21448 : {}
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 5214 : OStoreSuperBlock& operator= (const OStoreSuperBlock & rhs)
86 : {
87 5214 : m_aGuard = rhs.m_aGuard;
88 5214 : m_aDescr = rhs.m_aDescr;
89 5214 : m_nMarked = rhs.m_nMarked;
90 5214 : m_aMarked = rhs.m_aMarked;
91 5214 : m_nUnused = rhs.m_nUnused;
92 5214 : m_aUnused = rhs.m_aUnused;
93 5214 : return *this;
94 : }
95 :
96 : /** Comparison.
97 : */
98 113256 : sal_Bool operator== (const OStoreSuperBlock & rhs) const
99 : {
100 113256 : return ((m_aGuard == rhs.m_aGuard ) &&
101 113256 : (m_aDescr == rhs.m_aDescr ) &&
102 : (m_nMarked == rhs.m_nMarked) &&
103 113256 : (m_aMarked == rhs.m_aMarked) &&
104 : (m_nUnused == rhs.m_nUnused) &&
105 339768 : (m_aUnused == rhs.m_aUnused) );
106 : }
107 :
108 : /** unused(Count|Head|Insert|Remove|Reset).
109 : */
110 16 : sal_uInt32 unusedCount (void) const
111 : {
112 16 : return store::ntohl(m_nUnused);
113 : }
114 107730 : const L& unusedHead (void) const
115 : {
116 107730 : return m_aUnused;
117 : }
118 8 : void unusedInsert (const L& rLink)
119 : {
120 8 : sal_uInt32 nUnused = unusedCount();
121 8 : m_nUnused = store::htonl(nUnused + 1);
122 8 : m_aUnused = rLink;
123 8 : }
124 8 : void unusedRemove (const L& rLink)
125 : {
126 8 : sal_uInt32 nUnused = unusedCount();
127 8 : m_nUnused = store::htonl(nUnused - 1);
128 8 : m_aUnused = rLink;
129 8 : }
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 5214 : void guard()
139 : {
140 5214 : sal_uInt32 nCRC32 = 0;
141 5214 : nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
142 5214 : nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
143 5214 : m_aGuard.m_nCRC32 = store::htonl(nCRC32);
144 5214 : }
145 :
146 : /** verify (external representation).
147 : */
148 226512 : storeError verify() const
149 : {
150 226512 : sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
151 226512 : if (nMagic != STORE_MAGIC_SUPERBLOCK)
152 0 : return store_E_WrongFormat;
153 :
154 226512 : sal_uInt32 nCRC32 = 0;
155 226512 : nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
156 226512 : nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
157 226512 : if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
158 0 : return store_E_InvalidChecksum;
159 : else
160 226512 : 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 5526 : static void * operator new (size_t n) SAL_THROW(())
190 : {
191 5526 : return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
192 : }
193 31646 : static void operator delete (void * p) SAL_THROW(())
194 : {
195 31646 : rtl_freeMemory (p);
196 31646 : }
197 :
198 5198 : static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize) SAL_THROW(())
199 : {
200 5198 : 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 10724 : explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
210 : : m_aSuperOne(nPageSize),
211 10724 : m_aSuperTwo(nPageSize)
212 10724 : {}
213 :
214 : /** save.
215 : */
216 5214 : storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
217 : {
218 5214 : m_aSuperOne.guard();
219 5214 : m_aSuperTwo = m_aSuperOne;
220 5214 : 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 107722 : storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
253 : {
254 107722 : storeError eErrCode = verify (rBIOS);
255 107722 : if (eErrCode != store_E_None)
256 0 : return eErrCode;
257 :
258 : // Check freelist head.
259 107722 : OStorePageLink const aListHead (m_aSuperOne.unusedHead());
260 107722 : if (aListHead.location() == 0)
261 : {
262 : // Freelist empty, see SuperBlock::ctor().
263 107714 : rPageHead.location (STORE_PAGE_NULL);
264 107714 : return store_E_None;
265 : }
266 :
267 : // Load PageHead.
268 8 : eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
269 8 : if (eErrCode != store_E_None)
270 0 : return eErrCode;
271 :
272 8 : eErrCode = rPageHead.verify (aListHead.location());
273 8 : if (eErrCode != store_E_None)
274 0 : return eErrCode;
275 :
276 : // Verify page is unused.
277 8 : sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
278 : OSL_POSTCOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedHead(): page not free");
279 8 : 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 8 : return eErrCode;
289 : }
290 :
291 : /*
292 : * unusedPop(): pop freelist head (alloc page, step 2).
293 : */
294 8 : storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
295 : {
296 8 : sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
297 : OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
298 8 : if (nAddr == STORE_PAGE_NULL)
299 0 : return store_E_CantSeek;
300 :
301 : // Pop from FreeList.
302 8 : OStorePageLink const aListHead (nAddr);
303 8 : m_aSuperOne.unusedRemove (aListHead);
304 8 : return save (rBIOS);
305 : }
306 :
307 : /*
308 : * unusedPush(): push new freelist head.
309 : */
310 8 : storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
311 : {
312 8 : storeError eErrCode = verify (rBIOS);
313 8 : if (eErrCode != store_E_None)
314 0 : return eErrCode;
315 :
316 8 : PageData aPageHead;
317 8 : eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
318 8 : if (eErrCode != store_E_None)
319 0 : return eErrCode;
320 :
321 8 : eErrCode = aPageHead.verify (nAddr);
322 8 : if (eErrCode != store_E_None)
323 0 : return eErrCode;
324 :
325 8 : aPageHead.m_aUnused = m_aSuperOne.unusedHead();
326 8 : aPageHead.guard (nAddr);
327 :
328 8 : eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
329 8 : if (eErrCode != store_E_None)
330 0 : return eErrCode;
331 :
332 8 : OStorePageLink const aListHead (nAddr);
333 8 : m_aSuperOne.unusedInsert(aListHead);
334 8 : return save (rBIOS);
335 : }
336 :
337 : /*
338 : * verify (with repair).
339 : */
340 113256 : storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS)
341 : {
342 : // Verify 1st copy.
343 113256 : storeError eErrCode = m_aSuperOne.verify();
344 113256 : if (eErrCode == store_E_None)
345 : {
346 : // Ok. Verify 2nd copy.
347 113256 : eErrCode = m_aSuperTwo.verify();
348 113256 : if (eErrCode == store_E_None)
349 : {
350 : // Ok. Ensure identical copies (1st copy wins).
351 113256 : 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 0 : eErrCode = m_aSuperTwo.verify();
379 0 : 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 113256 : return eErrCode;
399 : }
400 :
401 : /*========================================================================
402 : *
403 : * OStorePageBIOS::Ace implementation.
404 : *
405 : *======================================================================*/
406 10724 : OStorePageBIOS::Ace::Ace()
407 10724 : : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
408 10724 : {}
409 :
410 10461 : OStorePageBIOS::Ace::~Ace()
411 : {
412 10461 : m_next->m_prev = m_prev, m_prev->m_next = m_next;
413 10461 : }
414 :
415 : int
416 592 : SAL_CALL OStorePageBIOS::Ace::constructor (
417 : void * obj, SAL_UNUSED_PARAMETER void * /* arg */)
418 : {
419 592 : Ace * ace = static_cast<Ace*>(obj);
420 592 : ace->m_next = ace->m_prev = ace;
421 592 : return 1;
422 : }
423 :
424 : OStorePageBIOS::Ace *
425 1038594 : OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
426 : {
427 : OStorePageBIOS::Ace * entry;
428 2271860 : for (entry = head->m_next; entry != head; entry = entry->m_next)
429 : {
430 1752563 : if (entry->m_addr >= addr)
431 519297 : return entry;
432 : }
433 519297 : return head;
434 : }
435 :
436 : void
437 519297 : OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
438 : {
439 : // insert entry at queue tail (before head).
440 519297 : entry->m_next = head;
441 519297 : entry->m_prev = head->m_prev;
442 519297 : head->m_prev = entry;
443 519297 : entry->m_prev->m_next = entry;
444 519297 : }
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 1038594 : OStorePageBIOS::AceCache::get()
483 : {
484 1038594 : static AceCache g_ace_cache;
485 1038594 : return g_ace_cache;
486 : }
487 :
488 422 : 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 422 : );
501 422 : }
502 :
503 422 : OStorePageBIOS::AceCache::~AceCache()
504 : {
505 422 : rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
506 422 : }
507 :
508 : OStorePageBIOS::Ace *
509 519297 : OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
510 : {
511 519297 : Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
512 519297 : if (ace != 0)
513 : {
514 : // verify invariant state.
515 : OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
516 :
517 : // initialize.
518 519297 : ace->m_addr = addr;
519 519297 : ace->m_used = used;
520 : }
521 519297 : return ace;
522 : }
523 :
524 : void
525 519297 : OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
526 : {
527 519297 : if (ace != 0)
528 : {
529 : // remove from queue (if any).
530 519297 : ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
531 :
532 : // restore invariant state.
533 519297 : ace->m_next = ace->m_prev = ace;
534 :
535 : // return to cache.
536 519297 : rtl_cache_free (m_ace_cache, ace);
537 : }
538 519297 : }
539 :
540 : /*========================================================================
541 : *
542 : * OStorePageBIOS implementation.
543 : *
544 : *======================================================================*/
545 : /*
546 : * OStorePageBIOS.
547 : */
548 10724 : OStorePageBIOS::OStorePageBIOS (void)
549 : : m_xLockBytes (NULL),
550 : m_pSuper (NULL),
551 10724 : m_bWriteable (false)
552 : {
553 10724 : }
554 :
555 : /*
556 : * ~OStorePageBIOS.
557 : */
558 20922 : OStorePageBIOS::~OStorePageBIOS (void)
559 : {
560 10461 : cleanup_Impl();
561 10461 : }
562 :
563 : /*
564 : * initialize.
565 : * Precond: none.
566 : */
567 10724 : storeError OStorePageBIOS::initialize (
568 : ILockBytes * pLockBytes,
569 : storeAccessMode eAccessMode,
570 : sal_uInt16 & rnPageSize)
571 : {
572 : // Acquire exclusive access.
573 10724 : osl::MutexGuard aGuard (m_aMutex);
574 :
575 : // Initialize.
576 10724 : storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
577 10724 : if (eErrCode != store_E_None)
578 : {
579 : // Cleanup.
580 0 : cleanup_Impl();
581 : }
582 10724 : return eErrCode;
583 : }
584 :
585 : /*
586 : * initialize_Impl.
587 : * Internal: Precond: exclusive access.
588 : */
589 10724 : storeError OStorePageBIOS::initialize_Impl (
590 : ILockBytes * pLockBytes,
591 : storeAccessMode eAccessMode,
592 : sal_uInt16 & rnPageSize)
593 : {
594 : // Cleanup.
595 10724 : cleanup_Impl();
596 :
597 : // Initialize.
598 10724 : m_xLockBytes = pLockBytes;
599 10724 : if (!m_xLockBytes.is())
600 0 : return store_E_InvalidParameter;
601 10724 : m_bWriteable = (eAccessMode != store_AccessReadOnly);
602 :
603 : // Check access mode.
604 10724 : storeError eErrCode = store_E_None;
605 10724 : if (eAccessMode != store_AccessCreate)
606 : {
607 : // Load SuperBlock page.
608 5526 : if ((m_pSuper = new SuperBlockPage()) == 0)
609 0 : return store_E_OutOfMemory;
610 :
611 5526 : eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
612 5526 : if (eErrCode == store_E_None)
613 : {
614 : // Verify SuperBlock page (with repair).
615 5526 : eErrCode = m_pSuper->verify (*this);
616 : }
617 : }
618 : else
619 : {
620 : // Truncate to zero length.
621 5198 : eErrCode = m_xLockBytes->setSize(0);
622 5198 : if (eErrCode != store_E_None)
623 0 : return eErrCode;
624 :
625 : // Mark as not existing.
626 5198 : eErrCode = store_E_NotExists;
627 : }
628 :
629 10724 : if (eErrCode != store_E_None)
630 : {
631 : // Check reason.
632 5198 : if (eErrCode != store_E_NotExists)
633 0 : return eErrCode;
634 :
635 : // Check mode.
636 5198 : if (eAccessMode == store_AccessReadOnly)
637 0 : return store_E_NotExists;
638 5198 : if (eAccessMode == store_AccessReadWrite)
639 0 : return store_E_NotExists;
640 :
641 : // Check PageSize.
642 5198 : if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
643 0 : return store_E_InvalidParameter;
644 5198 : rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
645 :
646 : // Create initial page (w/ SuperBlock).
647 5198 : if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
648 0 : return store_E_OutOfMemory;
649 5198 : eErrCode = m_pSuper->save (*this, rnPageSize);
650 : }
651 10724 : if (eErrCode == store_E_None)
652 : {
653 : // Obtain page size.
654 10724 : rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
655 :
656 : // Create page allocator.
657 10724 : eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
658 10724 : if (eErrCode != store_E_None)
659 0 : return eErrCode;
660 :
661 : // Create page cache.
662 10724 : eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
663 : }
664 10724 : return eErrCode;
665 : }
666 :
667 : /*
668 : * cleanup_Impl.
669 : * Internal: Precond: exclusive access.
670 : */
671 31646 : void OStorePageBIOS::cleanup_Impl()
672 : {
673 : // Check referer count.
674 31646 : 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 31646 : delete m_pSuper, m_pSuper = 0;
688 :
689 : // Release PageCache.
690 31646 : m_xCache.clear();
691 :
692 : // Release PageAllocator.
693 31646 : m_xAllocator.clear();
694 :
695 : // Release LockBytes.
696 31646 : m_xLockBytes.clear();
697 31646 : }
698 :
699 : /*
700 : * read.
701 : * Low Level: Precond: initialized, exclusive access.
702 : */
703 5542 : storeError OStorePageBIOS::read (
704 : sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
705 : {
706 : // Check precond.
707 5542 : if (!m_xLockBytes.is())
708 0 : return store_E_InvalidAccess;
709 :
710 : // Read Data.
711 5542 : return m_xLockBytes->readAt (nAddr, pData, nSize);
712 : }
713 :
714 : /*
715 : * write.
716 : * Low Level: Precond: initialized, writeable, exclusive access.
717 : */
718 5222 : storeError OStorePageBIOS::write (
719 : sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
720 : {
721 : // Check precond.
722 5222 : if (!m_xLockBytes.is())
723 0 : return store_E_InvalidAccess;
724 5222 : if (!m_bWriteable)
725 0 : return store_E_AccessViolation;
726 :
727 : // Write Data.
728 5222 : return m_xLockBytes->writeAt (nAddr, pData, nSize);
729 : }
730 :
731 : /*
732 : * acquirePage.
733 : * Precond: initialized.
734 : */
735 519297 : storeError OStorePageBIOS::acquirePage (
736 : const OStorePageDescriptor& rDescr, storeAccessMode eMode)
737 : {
738 : // Acquire exclusive access.
739 519297 : osl::MutexGuard aGuard (m_aMutex);
740 :
741 : // Check precond.
742 519297 : if (!m_xLockBytes.is())
743 0 : return store_E_InvalidAccess;
744 :
745 : // Check access mode.
746 519297 : if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
747 0 : return store_E_AccessViolation;
748 :
749 : // Find access control list entry.
750 519297 : Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
751 519297 : 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 519297 : Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1);
763 519297 : if (!entry)
764 0 : return store_E_OutOfMemory;
765 519297 : Ace::insert (ace, entry);
766 : }
767 :
768 : // Increment total referer count and finish.
769 519297 : m_ace_head.m_used += 1;
770 519297 : return store_E_None;
771 : }
772 :
773 : /*
774 : * releasePage.
775 : * Precond: initialized.
776 : */
777 519297 : storeError OStorePageBIOS::releasePage (const OStorePageDescriptor& rDescr)
778 : {
779 : // Acquire exclusive access.
780 519297 : osl::MutexGuard aGuard (m_aMutex);
781 :
782 : // Check precond.
783 519297 : if (!m_xLockBytes.is())
784 0 : return store_E_InvalidAccess;
785 :
786 : // Find access control list entry.
787 519297 : Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
788 519297 : if (ace->m_addr != rDescr.m_nAddr)
789 0 : return store_E_NotExists;
790 :
791 : // Release existing entry.
792 519297 : if (ace->m_used > 1)
793 0 : ace->m_used -= 1;
794 : else
795 519297 : AceCache::get().destroy (ace);
796 :
797 : // Decrement total referer count and finish.
798 519297 : m_ace_head.m_used -= 1;
799 519297 : 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 107722 : storeError OStorePageBIOS::allocate (
820 : OStorePageObject& rPage, Allocation eAlloc)
821 : {
822 : // Acquire exclusive access.
823 107722 : osl::MutexGuard aGuard (m_aMutex);
824 :
825 : // Check precond.
826 107722 : if (!m_xLockBytes.is())
827 0 : return store_E_InvalidAccess;
828 107722 : if (!m_bWriteable)
829 0 : return store_E_AccessViolation;
830 :
831 : // Check allocation type.
832 107722 : storeError eErrCode = store_E_None;
833 107722 : if (eAlloc != ALLOCATE_EOF)
834 : {
835 : // Try freelist head.
836 107722 : PageData aPageHead;
837 107722 : eErrCode = m_pSuper->unusedHead (*this, aPageHead);
838 107722 : if (eErrCode != store_E_None)
839 0 : return eErrCode;
840 :
841 107722 : sal_uInt32 const nAddr = aPageHead.location();
842 107722 : if (nAddr != STORE_PAGE_NULL)
843 : {
844 : // Save page.
845 8 : eErrCode = saveObjectAt_Impl (rPage, nAddr);
846 8 : if (eErrCode != store_E_None)
847 0 : return eErrCode;
848 :
849 : // Pop freelist head and finish.
850 8 : return m_pSuper->unusedPop (*this, aPageHead);
851 : }
852 : }
853 :
854 : // Allocate from EOF. Determine current size.
855 107714 : sal_uInt32 nSize = STORE_PAGE_NULL;
856 107714 : eErrCode = m_xLockBytes->getSize (nSize);
857 107714 : if (eErrCode != store_E_None)
858 0 : return eErrCode;
859 :
860 : // Save page at current EOF.
861 107714 : return saveObjectAt_Impl (rPage, nSize);
862 : }
863 :
864 : /*
865 : * free.
866 : * Precond: initialized, writeable.
867 : */
868 8 : storeError OStorePageBIOS::free (sal_uInt32 nAddr)
869 : {
870 : // Acquire exclusive access.
871 8 : osl::MutexGuard aGuard (m_aMutex);
872 :
873 : // Check precond.
874 8 : if (!m_xLockBytes.is())
875 0 : return store_E_InvalidAccess;
876 8 : if (!m_bWriteable)
877 0 : return store_E_AccessViolation;
878 :
879 : // Invalidate cache.
880 8 : (void) m_xCache->removePageAt (nAddr);
881 :
882 : // Push onto freelist.
883 8 : return m_pSuper->unusedPush (*this, nAddr);
884 : }
885 :
886 : /*
887 : * loadObjectAt.
888 : * Precond: initialized, readable.
889 : */
890 2465449 : storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
891 : {
892 : // Acquire exclusive access.
893 2465449 : osl::MutexGuard aGuard (m_aMutex);
894 :
895 : // Check precond.
896 2465449 : if (!m_xLockBytes.is())
897 0 : return store_E_InvalidAccess;
898 :
899 2465449 : return loadObjectAt_Impl (rPage, nAddr);
900 : }
901 :
902 : /*
903 : * loadObjectAt_Impl.
904 : * Internal: Precond: initialized, readable, exclusive access.
905 : */
906 2465449 : storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
907 : {
908 2465449 : storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
909 2465449 : if (eErrCode != store_E_NotExists)
910 2270528 : return eErrCode;
911 :
912 : // Read page.
913 194921 : eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
914 194921 : if (eErrCode != store_E_None)
915 5198 : return eErrCode;
916 :
917 : // Verify page.
918 189723 : eErrCode = rPage.verify (nAddr);
919 189723 : if (eErrCode != store_E_None)
920 0 : return eErrCode;
921 :
922 : // Mark page as clean.
923 189723 : rPage.clean();
924 :
925 : // Cache page.
926 189723 : return m_xCache->insertPageAt (rPage.get(), nAddr);
927 : }
928 :
929 : /*
930 : * saveObjectAt.
931 : * Precond: initialized, writeable.
932 : */
933 165085 : storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
934 : {
935 : // Acquire exclusive access.
936 165085 : osl::MutexGuard aGuard (m_aMutex);
937 :
938 : // Check precond.
939 165085 : if (!m_xLockBytes.is())
940 0 : return store_E_InvalidAccess;
941 165085 : if (!m_bWriteable)
942 0 : return store_E_AccessViolation;
943 :
944 : // Save Page.
945 165085 : return saveObjectAt_Impl (rPage, nAddr);
946 : }
947 :
948 : /*
949 : * saveObjectAt_Impl.
950 : * Internal: Precond: initialized, writeable, exclusive access.
951 : */
952 272807 : storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
953 : {
954 : // Guard page (incl. set location).
955 272807 : storeError eErrCode = rPage.guard (nAddr);
956 272807 : if (eErrCode != store_E_None)
957 0 : return eErrCode;
958 :
959 : // Write page.
960 272807 : eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
961 272807 : if (eErrCode != store_E_None)
962 0 : return eErrCode;
963 :
964 : // Mark page as clean.
965 272807 : rPage.clean();
966 :
967 : // Cache page.
968 272807 : return m_xCache->updatePageAt (rPage.get(), nAddr);
969 : }
970 :
971 : /*
972 : * close.
973 : * Precond: none.
974 : */
975 10461 : storeError OStorePageBIOS::close()
976 : {
977 : // Acquire exclusive access.
978 10461 : osl::MutexGuard aGuard (m_aMutex);
979 :
980 : // Cleanup.
981 10461 : cleanup_Impl();
982 :
983 : // Done.
984 10461 : return store_E_None;
985 : }
986 :
987 : /*
988 : * flush.
989 : * Precond: initialized.
990 : */
991 0 : storeError OStorePageBIOS::flush (void)
992 : {
993 : // Acquire exclusive access.
994 0 : osl::MutexGuard aGuard (m_aMutex);
995 :
996 : // Check precond.
997 0 : if (!m_xLockBytes.is())
998 0 : return store_E_InvalidAccess;
999 :
1000 : // Flush LockBytes and finish.
1001 0 : 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: */
|