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