Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / store / source / storbios.cxx
blobfc76cbfb12c19c0a8d4248f3b1f047b456dff7d3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "storbios.hxx"
32 #include "sal/types.h"
33 #include "sal/macros.h"
35 #include "rtl/alloc.h"
36 #include "rtl/ref.hxx"
38 #include "osl/diagnose.h"
39 #include "osl/mutex.hxx"
41 #include "store/types.h"
42 #include "object.hxx"
43 #include "lockbyte.hxx"
44 #include "storcach.hxx"
46 using namespace store;
48 /*========================================================================
50 * OStoreSuperBlock.
52 *======================================================================*/
53 #define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
55 struct OStoreSuperBlock
57 typedef OStorePageGuard G;
58 typedef OStorePageDescriptor D;
59 typedef OStorePageLink L;
61 /** Representation.
63 G m_aGuard;
64 D m_aDescr;
65 sal_uInt32 m_nMarked;
66 L m_aMarked;
67 sal_uInt32 m_nUnused;
68 L m_aUnused;
70 /** theSize.
72 static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32));
74 /** Construction.
76 explicit OStoreSuperBlock (sal_uInt16 nPageSize)
77 : m_aGuard (STORE_MAGIC_SUPERBLOCK),
78 m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
79 m_nMarked (store::htonl(0)),
80 m_aMarked (0),
81 m_nUnused (store::htonl(0)),
82 m_aUnused (0)
85 OStoreSuperBlock (const OStoreSuperBlock & rhs)
86 : m_aGuard (rhs.m_aGuard),
87 m_aDescr (rhs.m_aDescr),
88 m_nMarked (rhs.m_nMarked),
89 m_aMarked (rhs.m_aMarked),
90 m_nUnused (rhs.m_nUnused),
91 m_aUnused (rhs.m_aUnused)
94 OStoreSuperBlock& operator= (const OStoreSuperBlock & rhs)
96 m_aGuard = rhs.m_aGuard;
97 m_aDescr = rhs.m_aDescr;
98 m_nMarked = rhs.m_nMarked;
99 m_aMarked = rhs.m_aMarked;
100 m_nUnused = rhs.m_nUnused;
101 m_aUnused = rhs.m_aUnused;
102 return *this;
105 /** Comparison.
107 sal_Bool operator== (const OStoreSuperBlock & rhs) const
109 return ((m_aGuard == rhs.m_aGuard ) &&
110 (m_aDescr == rhs.m_aDescr ) &&
111 (m_nMarked == rhs.m_nMarked) &&
112 (m_aMarked == rhs.m_aMarked) &&
113 (m_nUnused == rhs.m_nUnused) &&
114 (m_aUnused == rhs.m_aUnused) );
117 /** unused(Count|Head|Insert|Remove|Reset).
119 sal_uInt32 unusedCount (void) const
121 return store::ntohl(m_nUnused);
123 const L& unusedHead (void) const
125 return m_aUnused;
127 void unusedInsert (const L& rLink)
129 sal_uInt32 nUnused = unusedCount();
130 m_nUnused = store::htonl(nUnused + 1);
131 m_aUnused = rLink;
133 void unusedRemove (const L& rLink)
135 sal_uInt32 nUnused = unusedCount();
136 m_nUnused = store::htonl(nUnused - 1);
137 m_aUnused = rLink;
139 void unusedReset (void)
141 m_nUnused = store::htonl(0);
142 m_aUnused = L(0);
145 /** guard (external representation).
147 void guard()
149 sal_uInt32 nCRC32 = 0;
150 nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
151 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
152 m_aGuard.m_nCRC32 = store::htonl(nCRC32);
155 /** verify (external representation).
157 storeError verify() const
159 sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
160 if (nMagic != STORE_MAGIC_SUPERBLOCK)
161 return store_E_WrongFormat;
163 sal_uInt32 nCRC32 = 0;
164 nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
165 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
166 if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
167 return store_E_InvalidChecksum;
168 else
169 return store_E_None;
173 /*========================================================================
175 * SuperBlockPage interface.
177 *======================================================================*/
178 namespace store
181 struct SuperBlockPage
183 typedef OStoreSuperBlock SuperBlock;
185 /** Representation.
187 SuperBlock m_aSuperOne;
188 SuperBlock m_aSuperTwo;
190 /** theSize.
192 static const size_t theSize = 2 * SuperBlock::theSize;
193 static const sal_uInt16 thePageSize = theSize;
194 STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize);
196 /** Allocation.
198 static void * operator new (size_t n) SAL_THROW(())
200 return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
202 static void operator delete (void * p) SAL_THROW(())
204 rtl_freeMemory (p);
207 static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize) SAL_THROW(())
209 return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
211 static void operator delete (void * p, SAL_UNUSED_PARAMETER sal_uInt16) SAL_THROW(())
213 rtl_freeMemory (p);
216 /** Construction.
218 explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
219 : m_aSuperOne(nPageSize),
220 m_aSuperTwo(nPageSize)
223 /** save.
225 storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
227 m_aSuperOne.guard();
228 m_aSuperTwo = m_aSuperOne;
229 return rBIOS.write (0, this, nSize);
232 /** Page allocation.
234 storeError unusedHead (
235 OStorePageBIOS & rBIOS,
236 PageData & rPageHead);
238 storeError unusedPop (
239 OStorePageBIOS & rBIOS,
240 PageData const & rPageHead);
242 storeError unusedPush (
243 OStorePageBIOS & rBIOS,
244 sal_uInt32 nAddr);
246 /** verify (with repair).
248 storeError verify (OStorePageBIOS & rBIOS);
251 } // namespace store
253 /*========================================================================
255 * SuperBlockPage implementation.
257 *======================================================================*/
259 * unusedHead(): get freelist head (alloc page, step 1).
261 storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
263 storeError eErrCode = verify (rBIOS);
264 if (eErrCode != store_E_None)
265 return eErrCode;
267 // Check freelist head.
268 OStorePageLink const aListHead (m_aSuperOne.unusedHead());
269 if (aListHead.location() == 0)
271 // Freelist empty, see SuperBlock::ctor().
272 rPageHead.location (STORE_PAGE_NULL);
273 return store_E_None;
276 // Load PageHead.
277 eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
278 if (eErrCode != store_E_None)
279 return eErrCode;
281 eErrCode = rPageHead.verify (aListHead.location());
282 if (eErrCode != store_E_None)
283 return eErrCode;
285 // Verify page is unused.
286 sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
287 OSL_POSTCOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedHead(): page not free");
288 if (nAddr == STORE_PAGE_NULL)
290 // Page in use.
291 rPageHead.location (STORE_PAGE_NULL);
293 // Recovery: Reset freelist to empty.
294 m_aSuperOne.unusedReset();
295 eErrCode = save (rBIOS);
297 return eErrCode;
301 * unusedPop(): pop freelist head (alloc page, step 2).
303 storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
305 sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
306 OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
307 if (nAddr == STORE_PAGE_NULL)
308 return store_E_CantSeek;
310 // Pop from FreeList.
311 OStorePageLink const aListHead (nAddr);
312 m_aSuperOne.unusedRemove (aListHead);
313 return save (rBIOS);
317 * unusedPush(): push new freelist head.
319 storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
321 storeError eErrCode = verify (rBIOS);
322 if (eErrCode != store_E_None)
323 return eErrCode;
325 PageData aPageHead;
326 eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
327 if (eErrCode != store_E_None)
328 return eErrCode;
330 eErrCode = aPageHead.verify (nAddr);
331 if (eErrCode != store_E_None)
332 return eErrCode;
334 aPageHead.m_aUnused = m_aSuperOne.unusedHead();
335 aPageHead.guard (nAddr);
337 eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
338 if (eErrCode != store_E_None)
339 return eErrCode;
341 OStorePageLink const aListHead (nAddr);
342 m_aSuperOne.unusedInsert(aListHead);
343 return save (rBIOS);
347 * verify (with repair).
349 storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS)
351 // Verify 1st copy.
352 storeError eErrCode = m_aSuperOne.verify();
353 if (eErrCode == store_E_None)
355 // Ok. Verify 2nd copy.
356 eErrCode = m_aSuperTwo.verify();
357 if (eErrCode == store_E_None)
359 // Ok. Ensure identical copies (1st copy wins).
360 if (!(m_aSuperOne == m_aSuperTwo))
362 // Different. Replace 2nd copy with 1st copy.
363 m_aSuperTwo = m_aSuperOne;
365 // Write back.
366 if (rBIOS.isWriteable())
367 eErrCode = rBIOS.write (0, this, theSize);
368 else
369 eErrCode = store_E_None;
372 else
374 // Failure. Replace 2nd copy with 1st copy.
375 m_aSuperTwo = m_aSuperOne;
377 // Write back.
378 if (rBIOS.isWriteable())
379 eErrCode = rBIOS.write (0, this, theSize);
380 else
381 eErrCode = store_E_None;
384 else
386 // Failure. Verify 2nd copy.
387 eErrCode = m_aSuperTwo.verify();
388 if (eErrCode == store_E_None)
390 // Ok. Replace 1st copy with 2nd copy.
391 m_aSuperOne = m_aSuperTwo;
393 // Write back.
394 if (rBIOS.isWriteable())
395 eErrCode = rBIOS.write (0, this, theSize);
396 else
397 eErrCode = store_E_None;
399 else
401 // Double Failure.
402 OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.");
406 // Done.
407 return eErrCode;
410 /*========================================================================
412 * OStorePageBIOS::Ace implementation.
414 *======================================================================*/
415 OStorePageBIOS::Ace::Ace()
416 : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
419 OStorePageBIOS::Ace::~Ace()
421 m_next->m_prev = m_prev, m_prev->m_next = m_next;
425 SAL_CALL OStorePageBIOS::Ace::constructor (
426 void * obj, SAL_UNUSED_PARAMETER void * /* arg */)
428 Ace * ace = static_cast<Ace*>(obj);
429 ace->m_next = ace->m_prev = ace;
430 return 1;
433 OStorePageBIOS::Ace *
434 OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
436 OStorePageBIOS::Ace * entry;
437 for (entry = head->m_next; entry != head; entry = entry->m_next)
439 if (entry->m_addr >= addr)
440 return entry;
442 return head;
445 void
446 OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
448 // insert entry at queue tail (before head).
449 entry->m_next = head;
450 entry->m_prev = head->m_prev;
451 head->m_prev = entry;
452 entry->m_prev->m_next = entry;
455 /*========================================================================
457 * OStorePageBIOS::AceCache interface.
459 *======================================================================*/
460 namespace store
463 class OStorePageBIOS::AceCache
465 rtl_cache_type * m_ace_cache;
467 public:
468 static AceCache & get();
470 OStorePageBIOS::Ace *
471 create (sal_uInt32 addr, sal_uInt32 used = 1);
473 void
474 destroy (OStorePageBIOS::Ace * ace);
476 protected:
477 AceCache();
478 ~AceCache();
481 } // namespace store
483 /*========================================================================
485 * OStorePageBIOS::AceCache implementation.
487 *======================================================================*/
488 extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*);
490 OStorePageBIOS::AceCache &
491 OStorePageBIOS::AceCache::get()
493 static AceCache g_ace_cache;
494 return g_ace_cache;
497 OStorePageBIOS::AceCache::AceCache()
499 m_ace_cache = rtl_cache_create (
500 "store_ace_cache",
501 sizeof (OStorePageBIOS::Ace),
502 0, // objalign
503 reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor),
504 0, // destructor,
505 0, // reclaim,
506 0, // userarg,
507 0, // default source,
508 0 // flags
512 OStorePageBIOS::AceCache::~AceCache()
514 rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
517 OStorePageBIOS::Ace *
518 OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
520 Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
521 if (ace != 0)
523 // verify invariant state.
524 OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
526 // initialize.
527 ace->m_addr = addr;
528 ace->m_used = used;
530 return ace;
533 void
534 OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
536 if (ace != 0)
538 // remove from queue (if any).
539 ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
541 // restore invariant state.
542 ace->m_next = ace->m_prev = ace;
544 // return to cache.
545 rtl_cache_free (m_ace_cache, ace);
549 /*========================================================================
551 * OStorePageBIOS implementation.
553 *======================================================================*/
555 * OStorePageBIOS.
557 OStorePageBIOS::OStorePageBIOS (void)
558 : m_xLockBytes (NULL),
559 m_pSuper (NULL),
560 m_bWriteable (false)
565 * ~OStorePageBIOS.
567 OStorePageBIOS::~OStorePageBIOS (void)
569 cleanup_Impl();
573 * initialize.
574 * Precond: none.
576 storeError OStorePageBIOS::initialize (
577 ILockBytes * pLockBytes,
578 storeAccessMode eAccessMode,
579 sal_uInt16 & rnPageSize)
581 // Acquire exclusive access.
582 osl::MutexGuard aGuard (m_aMutex);
584 // Initialize.
585 storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
586 if (eErrCode != store_E_None)
588 // Cleanup.
589 cleanup_Impl();
591 return eErrCode;
595 * initialize_Impl.
596 * Internal: Precond: exclusive access.
598 storeError OStorePageBIOS::initialize_Impl (
599 ILockBytes * pLockBytes,
600 storeAccessMode eAccessMode,
601 sal_uInt16 & rnPageSize)
603 // Cleanup.
604 cleanup_Impl();
606 // Initialize.
607 m_xLockBytes = pLockBytes;
608 if (!m_xLockBytes.is())
609 return store_E_InvalidParameter;
610 m_bWriteable = (eAccessMode != store_AccessReadOnly);
612 // Check access mode.
613 storeError eErrCode = store_E_None;
614 if (eAccessMode != store_AccessCreate)
616 // Load SuperBlock page.
617 if ((m_pSuper = new SuperBlockPage()) == 0)
618 return store_E_OutOfMemory;
620 eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
621 if (eErrCode == store_E_None)
623 // Verify SuperBlock page (with repair).
624 eErrCode = m_pSuper->verify (*this);
627 else
629 // Truncate to zero length.
630 eErrCode = m_xLockBytes->setSize(0);
631 if (eErrCode != store_E_None)
632 return eErrCode;
634 // Mark as not existing.
635 eErrCode = store_E_NotExists;
638 if (eErrCode != store_E_None)
640 // Check reason.
641 if (eErrCode != store_E_NotExists)
642 return eErrCode;
644 // Check mode.
645 if (eAccessMode == store_AccessReadOnly)
646 return store_E_NotExists;
647 if (eAccessMode == store_AccessReadWrite)
648 return store_E_NotExists;
650 // Check PageSize.
651 if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
652 return store_E_InvalidParameter;
653 rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
655 // Create initial page (w/ SuperBlock).
656 if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
657 return store_E_OutOfMemory;
658 eErrCode = m_pSuper->save (*this, rnPageSize);
660 if (eErrCode == store_E_None)
662 // Obtain page size.
663 rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
665 // Create page allocator.
666 eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
667 if (eErrCode != store_E_None)
668 return eErrCode;
670 // Create page cache.
671 eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
673 return eErrCode;
677 * cleanup_Impl.
678 * Internal: Precond: exclusive access.
680 void OStorePageBIOS::cleanup_Impl()
682 // Check referer count.
683 if (m_ace_head.m_used > 0)
685 // Report remaining referer count.
686 OSL_TRACE("store::PageBIOS::cleanup_Impl(): referer count: %d", m_ace_head.m_used);
687 for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next)
689 m_ace_head.m_used -= ace->m_used;
690 AceCache::get().destroy (ace);
692 OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::cleanup_Impl(): logic error");
695 // Release SuperBlock page.
696 delete m_pSuper, m_pSuper = 0;
698 // Release PageCache.
699 m_xCache.clear();
701 // Release PageAllocator.
702 m_xAllocator.clear();
704 // Release LockBytes.
705 m_xLockBytes.clear();
709 * read.
710 * Low Level: Precond: initialized, exclusive access.
712 storeError OStorePageBIOS::read (
713 sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
715 // Check precond.
716 if (!m_xLockBytes.is())
717 return store_E_InvalidAccess;
719 // Read Data.
720 return m_xLockBytes->readAt (nAddr, pData, nSize);
724 * write.
725 * Low Level: Precond: initialized, writeable, exclusive access.
727 storeError OStorePageBIOS::write (
728 sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
730 // Check precond.
731 if (!m_xLockBytes.is())
732 return store_E_InvalidAccess;
733 if (!m_bWriteable)
734 return store_E_AccessViolation;
736 // Write Data.
737 return m_xLockBytes->writeAt (nAddr, pData, nSize);
741 * acquirePage.
742 * Precond: initialized.
744 storeError OStorePageBIOS::acquirePage (
745 const OStorePageDescriptor& rDescr, storeAccessMode eMode)
747 // Acquire exclusive access.
748 osl::MutexGuard aGuard (m_aMutex);
750 // Check precond.
751 if (!m_xLockBytes.is())
752 return store_E_InvalidAccess;
754 // Check access mode.
755 if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
756 return store_E_AccessViolation;
758 // Find access control list entry.
759 Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
760 if (ace->m_addr == rDescr.m_nAddr)
762 // Acquire existing entry (with ShareDenyWrite).
763 if (eMode == store_AccessReadOnly)
764 ace->m_used += 1;
765 else
766 return store_E_AccessViolation;
768 else
770 // Insert new entry.
771 Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1);
772 if (!entry)
773 return store_E_OutOfMemory;
774 Ace::insert (ace, entry);
777 // Increment total referer count and finish.
778 m_ace_head.m_used += 1;
779 return store_E_None;
783 * releasePage.
784 * Precond: initialized.
786 storeError OStorePageBIOS::releasePage (const OStorePageDescriptor& rDescr)
788 // Acquire exclusive access.
789 osl::MutexGuard aGuard (m_aMutex);
791 // Check precond.
792 if (!m_xLockBytes.is())
793 return store_E_InvalidAccess;
795 // Find access control list entry.
796 Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
797 if (ace->m_addr != rDescr.m_nAddr)
798 return store_E_NotExists;
800 // Release existing entry.
801 if (ace->m_used > 1)
802 ace->m_used -= 1;
803 else
804 AceCache::get().destroy (ace);
806 // Decrement total referer count and finish.
807 m_ace_head.m_used -= 1;
808 return store_E_None;
812 * getRefererCount.
813 * Precond: none.
815 sal_uInt32 OStorePageBIOS::getRefererCount (void)
817 // Acquire exclusive access.
818 osl::MutexGuard aGuard (m_aMutex);
820 // Obtain total referer count.
821 return m_ace_head.m_used;
825 * allocate.
826 * Precond: initialized, writeable.
828 storeError OStorePageBIOS::allocate (
829 OStorePageObject& rPage, Allocation eAlloc)
831 // Acquire exclusive access.
832 osl::MutexGuard aGuard (m_aMutex);
834 // Check precond.
835 if (!m_xLockBytes.is())
836 return store_E_InvalidAccess;
837 if (!m_bWriteable)
838 return store_E_AccessViolation;
840 // Check allocation type.
841 storeError eErrCode = store_E_None;
842 if (eAlloc != ALLOCATE_EOF)
844 // Try freelist head.
845 PageData aPageHead;
846 eErrCode = m_pSuper->unusedHead (*this, aPageHead);
847 if (eErrCode != store_E_None)
848 return eErrCode;
850 sal_uInt32 const nAddr = aPageHead.location();
851 if (nAddr != STORE_PAGE_NULL)
853 // Save page.
854 eErrCode = saveObjectAt_Impl (rPage, nAddr);
855 if (eErrCode != store_E_None)
856 return eErrCode;
858 // Pop freelist head and finish.
859 return m_pSuper->unusedPop (*this, aPageHead);
863 // Allocate from EOF. Determine current size.
864 sal_uInt32 nSize = STORE_PAGE_NULL;
865 eErrCode = m_xLockBytes->getSize (nSize);
866 if (eErrCode != store_E_None)
867 return eErrCode;
869 // Save page at current EOF.
870 return saveObjectAt_Impl (rPage, nSize);
874 * free.
875 * Precond: initialized, writeable.
877 storeError OStorePageBIOS::free (sal_uInt32 nAddr)
879 // Acquire exclusive access.
880 osl::MutexGuard aGuard (m_aMutex);
882 // Check precond.
883 if (!m_xLockBytes.is())
884 return store_E_InvalidAccess;
885 if (!m_bWriteable)
886 return store_E_AccessViolation;
888 // Invalidate cache.
889 (void) m_xCache->removePageAt (nAddr);
891 // Push onto freelist.
892 return m_pSuper->unusedPush (*this, nAddr);
896 * loadObjectAt.
897 * Precond: initialized, readable.
899 storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
901 // Acquire exclusive access.
902 osl::MutexGuard aGuard (m_aMutex);
904 // Check precond.
905 if (!m_xLockBytes.is())
906 return store_E_InvalidAccess;
908 return loadObjectAt_Impl (rPage, nAddr);
912 * loadObjectAt_Impl.
913 * Internal: Precond: initialized, readable, exclusive access.
915 storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
917 storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
918 if (eErrCode != store_E_NotExists)
919 return eErrCode;
921 // Read page.
922 eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
923 if (eErrCode != store_E_None)
924 return eErrCode;
926 // Verify page.
927 eErrCode = rPage.verify (nAddr);
928 if (eErrCode != store_E_None)
929 return eErrCode;
931 // Mark page as clean.
932 rPage.clean();
934 // Cache page.
935 return m_xCache->insertPageAt (rPage.get(), nAddr);
939 * saveObjectAt.
940 * Precond: initialized, writeable.
942 storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
944 // Acquire exclusive access.
945 osl::MutexGuard aGuard (m_aMutex);
947 // Check precond.
948 if (!m_xLockBytes.is())
949 return store_E_InvalidAccess;
950 if (!m_bWriteable)
951 return store_E_AccessViolation;
953 // Save Page.
954 return saveObjectAt_Impl (rPage, nAddr);
958 * saveObjectAt_Impl.
959 * Internal: Precond: initialized, writeable, exclusive access.
961 storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
963 // Guard page (incl. set location).
964 storeError eErrCode = rPage.guard (nAddr);
965 if (eErrCode != store_E_None)
966 return eErrCode;
968 // Write page.
969 eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
970 if (eErrCode != store_E_None)
971 return eErrCode;
973 // Mark page as clean.
974 rPage.clean();
976 // Cache page.
977 return m_xCache->updatePageAt (rPage.get(), nAddr);
981 * close.
982 * Precond: none.
984 storeError OStorePageBIOS::close()
986 // Acquire exclusive access.
987 osl::MutexGuard aGuard (m_aMutex);
989 // Cleanup.
990 cleanup_Impl();
992 // Done.
993 return store_E_None;
997 * flush.
998 * Precond: initialized.
1000 storeError OStorePageBIOS::flush (void)
1002 // Acquire exclusive access.
1003 osl::MutexGuard aGuard (m_aMutex);
1005 // Check precond.
1006 if (!m_xLockBytes.is())
1007 return store_E_InvalidAccess;
1009 // Flush LockBytes and finish.
1010 return m_xLockBytes->flush();
1014 * size.
1015 * Precond: initialized.
1017 storeError OStorePageBIOS::size (sal_uInt32 &rnSize)
1019 // Acquire exclusive access.
1020 osl::MutexGuard aGuard (m_aMutex);
1022 // Initialize [out] param.
1023 rnSize = 0;
1025 // Check precond.
1026 if (!m_xLockBytes.is())
1027 return store_E_InvalidAccess;
1029 // Obtain LockBytes size.
1030 return m_xLockBytes->getSize (rnSize);
1034 * scanBegin.
1035 * Precond: initialized.
1037 storeError OStorePageBIOS::scanBegin (
1038 ScanContext &rCtx, sal_uInt32 nMagic)
1040 // Acquire exclusive access.
1041 osl::MutexGuard aGuard (m_aMutex);
1043 // Initialize [out] param.
1044 rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0);
1045 rCtx.m_nSize = 0;
1046 rCtx.m_nMagic = nMagic;
1048 // Check precond.
1049 if (!m_xLockBytes.is())
1050 return store_E_InvalidAccess;
1052 // Check SuperBlock page.
1053 storeError eErrCode = m_pSuper->verify (*this);
1054 if (eErrCode != store_E_None)
1056 // Damaged. Determine page size (NYI).
1057 OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n");
1058 return eErrCode;
1061 // Setup Context descriptor.
1062 rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr;
1063 rCtx.m_aDescr.m_nSize = store::ntohs(rCtx.m_aDescr.m_nSize);
1064 rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize;
1066 // Setup Context size.
1067 eErrCode = size (rCtx.m_nSize);
1068 if (eErrCode != store_E_None)
1069 rCtx.m_nSize = ((sal_uInt32)(~0));
1071 // Done.
1072 return store_E_None;
1076 * scanNext.
1077 * Precond: initialized.
1079 storeError OStorePageBIOS::scanNext (
1080 ScanContext &rCtx, OStorePageObject &rPage)
1082 // Acquire exclusive access.
1083 osl::MutexGuard aGuard (m_aMutex);
1085 // Check precond.
1086 if (!m_xLockBytes.is())
1087 return store_E_InvalidAccess;
1089 // Setup PageHead.
1090 PageData aPageHead;
1092 // Check context.
1093 while (rCtx.isValid())
1095 // Assign next location.
1096 sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr;
1097 rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
1099 // Read PageHead.
1100 storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize);
1101 if (eErrCode != store_E_None)
1102 continue;
1104 // Verify PageHead.
1105 eErrCode = aPageHead.verify (nAddr);
1106 if (eErrCode != store_E_None)
1107 continue;
1109 // Check PageHead Magic number.
1110 if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic)
1111 continue;
1113 // Check PageHead Unused link.
1114 if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL)
1115 continue;
1117 // Load page.
1118 eErrCode = loadObjectAt_Impl (rPage, nAddr);
1119 if (eErrCode != store_E_None)
1120 continue;
1122 // Deliver page.
1123 return store_E_None;
1126 // Done.
1127 return store_E_CantSeek;
1130 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */