update credits
[LibreOffice.git] / store / source / storbios.cxx
blobb773c5d2039747ea4c13fa80bd493ee8fc09f1fa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "sal/config.h"
22 #include "boost/static_assert.hpp"
24 #include "storbios.hxx"
26 #include "sal/types.h"
27 #include "sal/macros.h"
29 #include "rtl/alloc.h"
30 #include "rtl/ref.hxx"
32 #include "osl/diagnose.h"
33 #include "osl/mutex.hxx"
35 #include "store/types.h"
36 #include "object.hxx"
37 #include "lockbyte.hxx"
38 #include "storcach.hxx"
40 using namespace store;
42 /*========================================================================
44 * OStoreSuperBlock.
46 *======================================================================*/
47 #define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
49 struct OStoreSuperBlock
51 typedef OStorePageGuard G;
52 typedef OStorePageDescriptor D;
53 typedef OStorePageLink L;
55 /** Representation.
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;
64 /** theSize.
66 static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32));
68 /** Construction.
70 explicit OStoreSuperBlock (sal_uInt16 nPageSize)
71 : m_aGuard (STORE_MAGIC_SUPERBLOCK),
72 m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
73 m_nMarked (store::htonl(0)),
74 m_aMarked (0),
75 m_nUnused (store::htonl(0)),
76 m_aUnused (0)
79 OStoreSuperBlock (const OStoreSuperBlock & rhs)
80 : m_aGuard (rhs.m_aGuard),
81 m_aDescr (rhs.m_aDescr),
82 m_nMarked (rhs.m_nMarked),
83 m_aMarked (rhs.m_aMarked),
84 m_nUnused (rhs.m_nUnused),
85 m_aUnused (rhs.m_aUnused)
88 OStoreSuperBlock& operator= (const OStoreSuperBlock & rhs)
90 m_aGuard = rhs.m_aGuard;
91 m_aDescr = rhs.m_aDescr;
92 m_nMarked = rhs.m_nMarked;
93 m_aMarked = rhs.m_aMarked;
94 m_nUnused = rhs.m_nUnused;
95 m_aUnused = rhs.m_aUnused;
96 return *this;
99 /** Comparison.
101 sal_Bool operator== (const OStoreSuperBlock & rhs) const
103 return ((m_aGuard == rhs.m_aGuard ) &&
104 (m_aDescr == rhs.m_aDescr ) &&
105 (m_nMarked == rhs.m_nMarked) &&
106 (m_aMarked == rhs.m_aMarked) &&
107 (m_nUnused == rhs.m_nUnused) &&
108 (m_aUnused == rhs.m_aUnused) );
111 /** unused(Count|Head|Insert|Remove|Reset).
113 sal_uInt32 unusedCount (void) const
115 return store::ntohl(m_nUnused);
117 const L& unusedHead (void) const
119 return m_aUnused;
121 void unusedInsert (const L& rLink)
123 sal_uInt32 nUnused = unusedCount();
124 m_nUnused = store::htonl(nUnused + 1);
125 m_aUnused = rLink;
127 void unusedRemove (const L& rLink)
129 sal_uInt32 nUnused = unusedCount();
130 m_nUnused = store::htonl(nUnused - 1);
131 m_aUnused = rLink;
133 void unusedReset (void)
135 m_nUnused = store::htonl(0);
136 m_aUnused = L(0);
139 /** guard (external representation).
141 void guard()
143 sal_uInt32 nCRC32 = 0;
144 nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
145 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
146 m_aGuard.m_nCRC32 = store::htonl(nCRC32);
149 /** verify (external representation).
151 storeError verify() const
153 sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
154 if (nMagic != STORE_MAGIC_SUPERBLOCK)
155 return store_E_WrongFormat;
157 sal_uInt32 nCRC32 = 0;
158 nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
159 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
160 if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
161 return store_E_InvalidChecksum;
162 else
163 return store_E_None;
167 /*========================================================================
169 * SuperBlockPage interface.
171 *======================================================================*/
172 namespace store
175 struct SuperBlockPage
177 typedef OStoreSuperBlock SuperBlock;
179 /** Representation.
181 SuperBlock m_aSuperOne;
182 SuperBlock m_aSuperTwo;
184 /** theSize.
186 static const size_t theSize = 2 * SuperBlock::theSize;
187 static const sal_uInt16 thePageSize = theSize;
188 BOOST_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize);
190 /** Allocation.
192 static void * operator new (size_t n) SAL_THROW(())
194 return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
196 static void operator delete (void * p) SAL_THROW(())
198 rtl_freeMemory (p);
201 static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize) SAL_THROW(())
203 return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
205 static void operator delete (void * p, SAL_UNUSED_PARAMETER sal_uInt16) SAL_THROW(())
207 rtl_freeMemory (p);
210 /** Construction.
212 explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
213 : m_aSuperOne(nPageSize),
214 m_aSuperTwo(nPageSize)
217 /** save.
219 storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
221 m_aSuperOne.guard();
222 m_aSuperTwo = m_aSuperOne;
223 return rBIOS.write (0, this, nSize);
226 /** Page allocation.
228 storeError unusedHead (
229 OStorePageBIOS & rBIOS,
230 PageData & rPageHead);
232 storeError unusedPop (
233 OStorePageBIOS & rBIOS,
234 PageData const & rPageHead);
236 storeError unusedPush (
237 OStorePageBIOS & rBIOS,
238 sal_uInt32 nAddr);
240 /** verify (with repair).
242 storeError verify (OStorePageBIOS & rBIOS);
245 } // namespace store
247 /*========================================================================
249 * SuperBlockPage implementation.
251 *======================================================================*/
253 * unusedHead(): get freelist head (alloc page, step 1).
255 storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
257 storeError eErrCode = verify (rBIOS);
258 if (eErrCode != store_E_None)
259 return eErrCode;
261 // Check freelist head.
262 OStorePageLink const aListHead (m_aSuperOne.unusedHead());
263 if (aListHead.location() == 0)
265 // Freelist empty, see SuperBlock::ctor().
266 rPageHead.location (STORE_PAGE_NULL);
267 return store_E_None;
270 // Load PageHead.
271 eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
272 if (eErrCode != store_E_None)
273 return eErrCode;
275 eErrCode = rPageHead.verify (aListHead.location());
276 if (eErrCode != store_E_None)
277 return eErrCode;
279 // Verify page is unused.
280 sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
281 OSL_POSTCOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedHead(): page not free");
282 if (nAddr == STORE_PAGE_NULL)
284 // Page in use.
285 rPageHead.location (STORE_PAGE_NULL);
287 // Recovery: Reset freelist to empty.
288 m_aSuperOne.unusedReset();
289 eErrCode = save (rBIOS);
291 return eErrCode;
295 * unusedPop(): pop freelist head (alloc page, step 2).
297 storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
299 sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
300 OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
301 if (nAddr == STORE_PAGE_NULL)
302 return store_E_CantSeek;
304 // Pop from FreeList.
305 OStorePageLink const aListHead (nAddr);
306 m_aSuperOne.unusedRemove (aListHead);
307 return save (rBIOS);
311 * unusedPush(): push new freelist head.
313 storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
315 storeError eErrCode = verify (rBIOS);
316 if (eErrCode != store_E_None)
317 return eErrCode;
319 PageData aPageHead;
320 eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
321 if (eErrCode != store_E_None)
322 return eErrCode;
324 eErrCode = aPageHead.verify (nAddr);
325 if (eErrCode != store_E_None)
326 return eErrCode;
328 aPageHead.m_aUnused = m_aSuperOne.unusedHead();
329 aPageHead.guard (nAddr);
331 eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
332 if (eErrCode != store_E_None)
333 return eErrCode;
335 OStorePageLink const aListHead (nAddr);
336 m_aSuperOne.unusedInsert(aListHead);
337 return save (rBIOS);
341 * verify (with repair).
343 storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS)
345 // Verify 1st copy.
346 storeError eErrCode = m_aSuperOne.verify();
347 if (eErrCode == store_E_None)
349 // Ok. Verify 2nd copy.
350 eErrCode = m_aSuperTwo.verify();
351 if (eErrCode == store_E_None)
353 // Ok. Ensure identical copies (1st copy wins).
354 if (!(m_aSuperOne == m_aSuperTwo))
356 // Different. Replace 2nd copy with 1st copy.
357 m_aSuperTwo = m_aSuperOne;
359 // Write back.
360 if (rBIOS.isWriteable())
361 eErrCode = rBIOS.write (0, this, theSize);
362 else
363 eErrCode = store_E_None;
366 else
368 // Failure. Replace 2nd copy with 1st copy.
369 m_aSuperTwo = m_aSuperOne;
371 // Write back.
372 if (rBIOS.isWriteable())
373 eErrCode = rBIOS.write (0, this, theSize);
374 else
375 eErrCode = store_E_None;
378 else
380 // Failure. Verify 2nd copy.
381 eErrCode = m_aSuperTwo.verify();
382 if (eErrCode == store_E_None)
384 // Ok. Replace 1st copy with 2nd copy.
385 m_aSuperOne = m_aSuperTwo;
387 // Write back.
388 if (rBIOS.isWriteable())
389 eErrCode = rBIOS.write (0, this, theSize);
390 else
391 eErrCode = store_E_None;
393 else
395 // Double Failure.
396 OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.");
400 // Done.
401 return eErrCode;
404 /*========================================================================
406 * OStorePageBIOS::Ace implementation.
408 *======================================================================*/
409 OStorePageBIOS::Ace::Ace()
410 : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
413 OStorePageBIOS::Ace::~Ace()
415 m_next->m_prev = m_prev, m_prev->m_next = m_next;
419 SAL_CALL OStorePageBIOS::Ace::constructor (
420 void * obj, SAL_UNUSED_PARAMETER void * /* arg */)
422 Ace * ace = static_cast<Ace*>(obj);
423 ace->m_next = ace->m_prev = ace;
424 return 1;
427 OStorePageBIOS::Ace *
428 OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
430 OStorePageBIOS::Ace * entry;
431 for (entry = head->m_next; entry != head; entry = entry->m_next)
433 if (entry->m_addr >= addr)
434 return entry;
436 return head;
439 void
440 OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
442 // insert entry at queue tail (before head).
443 entry->m_next = head;
444 entry->m_prev = head->m_prev;
445 head->m_prev = entry;
446 entry->m_prev->m_next = entry;
449 /*========================================================================
451 * OStorePageBIOS::AceCache interface.
453 *======================================================================*/
454 namespace store
457 class OStorePageBIOS::AceCache
459 rtl_cache_type * m_ace_cache;
461 public:
462 static AceCache & get();
464 OStorePageBIOS::Ace *
465 create (sal_uInt32 addr, sal_uInt32 used = 1);
467 void
468 destroy (OStorePageBIOS::Ace * ace);
470 protected:
471 AceCache();
472 ~AceCache();
475 } // namespace store
477 /*========================================================================
479 * OStorePageBIOS::AceCache implementation.
481 *======================================================================*/
482 extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*);
484 OStorePageBIOS::AceCache &
485 OStorePageBIOS::AceCache::get()
487 static AceCache g_ace_cache;
488 return g_ace_cache;
491 OStorePageBIOS::AceCache::AceCache()
493 m_ace_cache = rtl_cache_create (
494 "store_ace_cache",
495 sizeof (OStorePageBIOS::Ace),
496 0, // objalign
497 reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor),
498 0, // destructor,
499 0, // reclaim,
500 0, // userarg,
501 0, // default source,
502 0 // flags
506 OStorePageBIOS::AceCache::~AceCache()
508 rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
511 OStorePageBIOS::Ace *
512 OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
514 Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
515 if (ace != 0)
517 // verify invariant state.
518 OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
520 // initialize.
521 ace->m_addr = addr;
522 ace->m_used = used;
524 return ace;
527 void
528 OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
530 if (ace != 0)
532 // remove from queue (if any).
533 ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
535 // restore invariant state.
536 ace->m_next = ace->m_prev = ace;
538 // return to cache.
539 rtl_cache_free (m_ace_cache, ace);
543 /*========================================================================
545 * OStorePageBIOS implementation.
547 *======================================================================*/
549 * OStorePageBIOS.
551 OStorePageBIOS::OStorePageBIOS (void)
552 : m_xLockBytes (NULL),
553 m_pSuper (NULL),
554 m_bWriteable (false)
559 * ~OStorePageBIOS.
561 OStorePageBIOS::~OStorePageBIOS (void)
563 cleanup_Impl();
567 * initialize.
568 * Precond: none.
570 storeError OStorePageBIOS::initialize (
571 ILockBytes * pLockBytes,
572 storeAccessMode eAccessMode,
573 sal_uInt16 & rnPageSize)
575 // Acquire exclusive access.
576 osl::MutexGuard aGuard (m_aMutex);
578 // Initialize.
579 storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
580 if (eErrCode != store_E_None)
582 // Cleanup.
583 cleanup_Impl();
585 return eErrCode;
589 * initialize_Impl.
590 * Internal: Precond: exclusive access.
592 storeError OStorePageBIOS::initialize_Impl (
593 ILockBytes * pLockBytes,
594 storeAccessMode eAccessMode,
595 sal_uInt16 & rnPageSize)
597 // Cleanup.
598 cleanup_Impl();
600 // Initialize.
601 m_xLockBytes = pLockBytes;
602 if (!m_xLockBytes.is())
603 return store_E_InvalidParameter;
604 m_bWriteable = (eAccessMode != store_AccessReadOnly);
606 // Check access mode.
607 storeError eErrCode = store_E_None;
608 if (eAccessMode != store_AccessCreate)
610 // Load SuperBlock page.
611 if ((m_pSuper = new SuperBlockPage()) == 0)
612 return store_E_OutOfMemory;
614 eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
615 if (eErrCode == store_E_None)
617 // Verify SuperBlock page (with repair).
618 eErrCode = m_pSuper->verify (*this);
621 else
623 // Truncate to zero length.
624 eErrCode = m_xLockBytes->setSize(0);
625 if (eErrCode != store_E_None)
626 return eErrCode;
628 // Mark as not existing.
629 eErrCode = store_E_NotExists;
632 if (eErrCode != store_E_None)
634 // Check reason.
635 if (eErrCode != store_E_NotExists)
636 return eErrCode;
638 // Check mode.
639 if (eAccessMode == store_AccessReadOnly)
640 return store_E_NotExists;
641 if (eAccessMode == store_AccessReadWrite)
642 return store_E_NotExists;
644 // Check PageSize.
645 if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
646 return store_E_InvalidParameter;
647 rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
649 // Create initial page (w/ SuperBlock).
650 if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
651 return store_E_OutOfMemory;
652 eErrCode = m_pSuper->save (*this, rnPageSize);
654 if (eErrCode == store_E_None)
656 // Obtain page size.
657 rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
659 // Create page allocator.
660 eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
661 if (eErrCode != store_E_None)
662 return eErrCode;
664 // Create page cache.
665 eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
667 return eErrCode;
671 * cleanup_Impl.
672 * Internal: Precond: exclusive access.
674 void OStorePageBIOS::cleanup_Impl()
676 // Check referer count.
677 if (m_ace_head.m_used > 0)
679 // Report remaining referer count.
680 OSL_TRACE("store::PageBIOS::cleanup_Impl(): referer count: %d", m_ace_head.m_used);
681 for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next)
683 m_ace_head.m_used -= ace->m_used;
684 AceCache::get().destroy (ace);
686 OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::cleanup_Impl(): logic error");
689 // Release SuperBlock page.
690 delete m_pSuper, m_pSuper = 0;
692 // Release PageCache.
693 m_xCache.clear();
695 // Release PageAllocator.
696 m_xAllocator.clear();
698 // Release LockBytes.
699 m_xLockBytes.clear();
703 * read.
704 * Low Level: Precond: initialized, exclusive access.
706 storeError OStorePageBIOS::read (
707 sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
709 // Check precond.
710 if (!m_xLockBytes.is())
711 return store_E_InvalidAccess;
713 // Read Data.
714 return m_xLockBytes->readAt (nAddr, pData, nSize);
718 * write.
719 * Low Level: Precond: initialized, writeable, exclusive access.
721 storeError OStorePageBIOS::write (
722 sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
724 // Check precond.
725 if (!m_xLockBytes.is())
726 return store_E_InvalidAccess;
727 if (!m_bWriteable)
728 return store_E_AccessViolation;
730 // Write Data.
731 return m_xLockBytes->writeAt (nAddr, pData, nSize);
735 * acquirePage.
736 * Precond: initialized.
738 storeError OStorePageBIOS::acquirePage (
739 const OStorePageDescriptor& rDescr, storeAccessMode eMode)
741 // Acquire exclusive access.
742 osl::MutexGuard aGuard (m_aMutex);
744 // Check precond.
745 if (!m_xLockBytes.is())
746 return store_E_InvalidAccess;
748 // Check access mode.
749 if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
750 return store_E_AccessViolation;
752 // Find access control list entry.
753 Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
754 if (ace->m_addr == rDescr.m_nAddr)
756 // Acquire existing entry (with ShareDenyWrite).
757 if (eMode == store_AccessReadOnly)
758 ace->m_used += 1;
759 else
760 return store_E_AccessViolation;
762 else
764 // Insert new entry.
765 Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1);
766 if (!entry)
767 return store_E_OutOfMemory;
768 Ace::insert (ace, entry);
771 // Increment total referer count and finish.
772 m_ace_head.m_used += 1;
773 return store_E_None;
777 * releasePage.
778 * Precond: initialized.
780 storeError OStorePageBIOS::releasePage (const OStorePageDescriptor& rDescr)
782 // Acquire exclusive access.
783 osl::MutexGuard aGuard (m_aMutex);
785 // Check precond.
786 if (!m_xLockBytes.is())
787 return store_E_InvalidAccess;
789 // Find access control list entry.
790 Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
791 if (ace->m_addr != rDescr.m_nAddr)
792 return store_E_NotExists;
794 // Release existing entry.
795 if (ace->m_used > 1)
796 ace->m_used -= 1;
797 else
798 AceCache::get().destroy (ace);
800 // Decrement total referer count and finish.
801 m_ace_head.m_used -= 1;
802 return store_E_None;
806 * getRefererCount.
807 * Precond: none.
809 sal_uInt32 OStorePageBIOS::getRefererCount (void)
811 // Acquire exclusive access.
812 osl::MutexGuard aGuard (m_aMutex);
814 // Obtain total referer count.
815 return m_ace_head.m_used;
819 * allocate.
820 * Precond: initialized, writeable.
822 storeError OStorePageBIOS::allocate (
823 OStorePageObject& rPage, Allocation eAlloc)
825 // Acquire exclusive access.
826 osl::MutexGuard aGuard (m_aMutex);
828 // Check precond.
829 if (!m_xLockBytes.is())
830 return store_E_InvalidAccess;
831 if (!m_bWriteable)
832 return store_E_AccessViolation;
834 // Check allocation type.
835 storeError eErrCode = store_E_None;
836 if (eAlloc != ALLOCATE_EOF)
838 // Try freelist head.
839 PageData aPageHead;
840 eErrCode = m_pSuper->unusedHead (*this, aPageHead);
841 if (eErrCode != store_E_None)
842 return eErrCode;
844 sal_uInt32 const nAddr = aPageHead.location();
845 if (nAddr != STORE_PAGE_NULL)
847 // Save page.
848 eErrCode = saveObjectAt_Impl (rPage, nAddr);
849 if (eErrCode != store_E_None)
850 return eErrCode;
852 // Pop freelist head and finish.
853 return m_pSuper->unusedPop (*this, aPageHead);
857 // Allocate from EOF. Determine current size.
858 sal_uInt32 nSize = STORE_PAGE_NULL;
859 eErrCode = m_xLockBytes->getSize (nSize);
860 if (eErrCode != store_E_None)
861 return eErrCode;
863 // Save page at current EOF.
864 return saveObjectAt_Impl (rPage, nSize);
868 * free.
869 * Precond: initialized, writeable.
871 storeError OStorePageBIOS::free (sal_uInt32 nAddr)
873 // Acquire exclusive access.
874 osl::MutexGuard aGuard (m_aMutex);
876 // Check precond.
877 if (!m_xLockBytes.is())
878 return store_E_InvalidAccess;
879 if (!m_bWriteable)
880 return store_E_AccessViolation;
882 // Invalidate cache.
883 (void) m_xCache->removePageAt (nAddr);
885 // Push onto freelist.
886 return m_pSuper->unusedPush (*this, nAddr);
890 * loadObjectAt.
891 * Precond: initialized, readable.
893 storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
895 // Acquire exclusive access.
896 osl::MutexGuard aGuard (m_aMutex);
898 // Check precond.
899 if (!m_xLockBytes.is())
900 return store_E_InvalidAccess;
902 return loadObjectAt_Impl (rPage, nAddr);
906 * loadObjectAt_Impl.
907 * Internal: Precond: initialized, readable, exclusive access.
909 storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
911 storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
912 if (eErrCode != store_E_NotExists)
913 return eErrCode;
915 // Read page.
916 eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
917 if (eErrCode != store_E_None)
918 return eErrCode;
920 // Verify page.
921 eErrCode = rPage.verify (nAddr);
922 if (eErrCode != store_E_None)
923 return eErrCode;
925 // Mark page as clean.
926 rPage.clean();
928 // Cache page.
929 return m_xCache->insertPageAt (rPage.get(), nAddr);
933 * saveObjectAt.
934 * Precond: initialized, writeable.
936 storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
938 // Acquire exclusive access.
939 osl::MutexGuard aGuard (m_aMutex);
941 // Check precond.
942 if (!m_xLockBytes.is())
943 return store_E_InvalidAccess;
944 if (!m_bWriteable)
945 return store_E_AccessViolation;
947 // Save Page.
948 return saveObjectAt_Impl (rPage, nAddr);
952 * saveObjectAt_Impl.
953 * Internal: Precond: initialized, writeable, exclusive access.
955 storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
957 // Guard page (incl. set location).
958 storeError eErrCode = rPage.guard (nAddr);
959 if (eErrCode != store_E_None)
960 return eErrCode;
962 // Write page.
963 eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
964 if (eErrCode != store_E_None)
965 return eErrCode;
967 // Mark page as clean.
968 rPage.clean();
970 // Cache page.
971 return m_xCache->updatePageAt (rPage.get(), nAddr);
975 * close.
976 * Precond: none.
978 storeError OStorePageBIOS::close()
980 // Acquire exclusive access.
981 osl::MutexGuard aGuard (m_aMutex);
983 // Cleanup.
984 cleanup_Impl();
986 // Done.
987 return store_E_None;
991 * flush.
992 * Precond: initialized.
994 storeError OStorePageBIOS::flush (void)
996 // Acquire exclusive access.
997 osl::MutexGuard aGuard (m_aMutex);
999 // Check precond.
1000 if (!m_xLockBytes.is())
1001 return store_E_InvalidAccess;
1003 // Flush LockBytes and finish.
1004 return m_xLockBytes->flush();
1008 * size.
1009 * Precond: initialized.
1011 storeError OStorePageBIOS::size (sal_uInt32 &rnSize)
1013 // Acquire exclusive access.
1014 osl::MutexGuard aGuard (m_aMutex);
1016 // Initialize [out] param.
1017 rnSize = 0;
1019 // Check precond.
1020 if (!m_xLockBytes.is())
1021 return store_E_InvalidAccess;
1023 // Obtain LockBytes size.
1024 return m_xLockBytes->getSize (rnSize);
1028 * scanBegin.
1029 * Precond: initialized.
1031 storeError OStorePageBIOS::scanBegin (
1032 ScanContext &rCtx, sal_uInt32 nMagic)
1034 // Acquire exclusive access.
1035 osl::MutexGuard aGuard (m_aMutex);
1037 // Initialize [out] param.
1038 rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0);
1039 rCtx.m_nSize = 0;
1040 rCtx.m_nMagic = nMagic;
1042 // Check precond.
1043 if (!m_xLockBytes.is())
1044 return store_E_InvalidAccess;
1046 // Check SuperBlock page.
1047 storeError eErrCode = m_pSuper->verify (*this);
1048 if (eErrCode != store_E_None)
1050 // Damaged. Determine page size (NYI).
1051 OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n");
1052 return eErrCode;
1055 // Setup Context descriptor.
1056 rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr;
1057 rCtx.m_aDescr.m_nSize = store::ntohs(rCtx.m_aDescr.m_nSize);
1058 rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize;
1060 // Setup Context size.
1061 eErrCode = size (rCtx.m_nSize);
1062 if (eErrCode != store_E_None)
1063 rCtx.m_nSize = ((sal_uInt32)(~0));
1065 // Done.
1066 return store_E_None;
1070 * scanNext.
1071 * Precond: initialized.
1073 storeError OStorePageBIOS::scanNext (
1074 ScanContext &rCtx, OStorePageObject &rPage)
1076 // Acquire exclusive access.
1077 osl::MutexGuard aGuard (m_aMutex);
1079 // Check precond.
1080 if (!m_xLockBytes.is())
1081 return store_E_InvalidAccess;
1083 // Setup PageHead.
1084 PageData aPageHead;
1086 // Check context.
1087 while (rCtx.isValid())
1089 // Assign next location.
1090 sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr;
1091 rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
1093 // Read PageHead.
1094 storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize);
1095 if (eErrCode != store_E_None)
1096 continue;
1098 // Verify PageHead.
1099 eErrCode = aPageHead.verify (nAddr);
1100 if (eErrCode != store_E_None)
1101 continue;
1103 // Check PageHead Magic number.
1104 if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic)
1105 continue;
1107 // Check PageHead Unused link.
1108 if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL)
1109 continue;
1111 // Load page.
1112 eErrCode = loadObjectAt_Impl (rPage, nAddr);
1113 if (eErrCode != store_E_None)
1114 continue;
1116 // Deliver page.
1117 return store_E_None;
1120 // Done.
1121 return store_E_CantSeek;
1124 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */