summaryrefslogtreecommitdiff
path: root/store/source/storbios.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'store/source/storbios.cxx')
-rw-r--r--store/source/storbios.cxx1570
1 files changed, 1570 insertions, 0 deletions
diff --git a/store/source/storbios.cxx b/store/source/storbios.cxx
new file mode 100644
index 000000000000..d1f15dcda247
--- /dev/null
+++ b/store/source/storbios.cxx
@@ -0,0 +1,1570 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: storbios.cxx,v $
+ *
+ * $Revision: 1.1.2.3 $
+ *
+ * last change: $Author: mhu $ $Date: 2008/10/31 18:28:18 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_store.hxx"
+
+#include "storbios.hxx"
+
+#include "sal/types.h"
+#include "sal/macros.h"
+
+#include "rtl/alloc.h"
+#include "rtl/ref.hxx"
+
+#include "osl/diagnose.h"
+#include "osl/mutex.hxx"
+
+#include "store/types.h"
+#include "object.hxx"
+#include "lockbyte.hxx"
+#include "storcach.hxx"
+
+using namespace store;
+
+/*========================================================================
+ *
+ * OStoreSuperBlock.
+ *
+ *======================================================================*/
+#define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
+
+struct OStoreSuperBlock
+{
+ typedef OStorePageGuard G;
+ typedef OStorePageDescriptor D;
+ typedef OStorePageLink L;
+
+ /** Representation.
+ */
+ G m_aGuard;
+ D m_aDescr;
+ sal_uInt32 m_nMarked;
+ L m_aMarked;
+ sal_uInt32 m_nUnused;
+ L m_aUnused;
+
+ /** theSize.
+ */
+ static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32));
+
+ /** Construction.
+ */
+ explicit OStoreSuperBlock (sal_uInt16 nPageSize)
+ : m_aGuard (STORE_MAGIC_SUPERBLOCK),
+ m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
+ m_nMarked (store::htonl(0)),
+ m_aMarked (0),
+ m_nUnused (store::htonl(0)),
+ m_aUnused (0)
+ {}
+
+ OStoreSuperBlock (const OStoreSuperBlock& rOther)
+ : m_aGuard (rOther.m_aGuard),
+ m_aDescr (rOther.m_aDescr),
+ m_nMarked (rOther.m_nMarked),
+ m_aMarked (rOther.m_aMarked),
+ m_nUnused (rOther.m_nUnused),
+ m_aUnused (rOther.m_aUnused)
+ {}
+
+ OStoreSuperBlock& operator= (const OStoreSuperBlock& rOther)
+ {
+ m_aGuard = rOther.m_aGuard;
+ m_aDescr = rOther.m_aDescr;
+ m_nMarked = rOther.m_nMarked;
+ m_aMarked = rOther.m_aMarked;
+ m_nUnused = rOther.m_nUnused;
+ m_aUnused = rOther.m_aUnused;
+ return *this;
+ }
+
+ /** Comparison.
+ */
+ sal_Bool operator== (const OStoreSuperBlock& rOther) const
+ {
+ return ((m_aGuard == rOther.m_aGuard ) &&
+ (m_aDescr == rOther.m_aDescr ) &&
+ (m_nMarked == rOther.m_nMarked) &&
+ (m_aMarked == rOther.m_aMarked) &&
+ (m_nUnused == rOther.m_nUnused) &&
+ (m_aUnused == rOther.m_aUnused) );
+ }
+
+ /** unused(Count|Head|Insert|Remove|Reset).
+ */
+ sal_uInt32 unusedCount (void) const
+ {
+ return store::ntohl(m_nUnused);
+ }
+ const L& unusedHead (void) const
+ {
+ return m_aUnused;
+ }
+ void unusedInsert (const L& rLink)
+ {
+ sal_uInt32 nUnused = unusedCount();
+ m_nUnused = store::htonl(nUnused + 1);
+ m_aUnused = rLink;
+ }
+ void unusedRemove (const L& rLink)
+ {
+ sal_uInt32 nUnused = unusedCount();
+ m_nUnused = store::htonl(nUnused - 1);
+ m_aUnused = rLink;
+ }
+ void unusedReset (void)
+ {
+ m_nUnused = store::htonl(0);
+ m_aUnused = L(0);
+ }
+
+ /** guard (external representation).
+ */
+ void guard()
+ {
+ sal_uInt32 nCRC32 = 0;
+ nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
+ nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
+ m_aGuard.m_nCRC32 = store::htonl(nCRC32);
+ }
+
+ /** verify (external representation).
+ */
+ storeError verify() const
+ {
+ sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
+ if (nMagic != STORE_MAGIC_SUPERBLOCK)
+ return store_E_WrongFormat;
+
+ sal_uInt32 nCRC32 = 0;
+ nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
+ nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
+ if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
+ return store_E_InvalidChecksum;
+ else
+ return store_E_None;
+ }
+};
+
+/*========================================================================
+ *
+ * OStoreStateBlock.
+ *
+ *======================================================================*/
+struct OStoreStateBlock
+{
+ enum StateBits
+ {
+ STATE_CLEAN = 0,
+ STATE_CLOSE_WAIT = 1,
+ STATE_FLUSH_WAIT = 2
+ };
+
+ /** Representation.
+ */
+ sal_uInt32 m_nState;
+
+ /** theSize.
+ */
+ static const size_t theSize = sizeof(sal_uInt32);
+
+ /** Construction.
+ */
+ OStoreStateBlock()
+ : m_nState (store::htonl(STATE_CLEAN))
+ {}
+
+ /** Operation.
+ */
+ bool closePending (void) const
+ {
+ sal_uInt32 nState = store::ntohl(m_nState);
+ return ((nState & STATE_CLOSE_WAIT) == STATE_CLOSE_WAIT);
+ }
+ void closed (void)
+ {
+ sal_uInt32 nState = store::ntohl(m_nState);
+ nState &= ~STATE_CLOSE_WAIT;
+ m_nState = store::htonl(nState);
+ }
+
+ bool flushPending (void) const
+ {
+ sal_uInt32 nState = store::ntohl(m_nState);
+ return ((nState & STATE_FLUSH_WAIT) == STATE_FLUSH_WAIT);
+ }
+ void flushed (void)
+ {
+ sal_uInt32 nState = store::ntohl(m_nState);
+ nState &= ~STATE_FLUSH_WAIT;
+ m_nState = store::htonl(nState);
+ }
+
+ void modified (void)
+ {
+ sal_uInt32 nState = store::ntohl(m_nState);
+ nState |= (STATE_CLOSE_WAIT | STATE_FLUSH_WAIT);
+ m_nState = store::htonl(nState);
+ }
+ void clean (void)
+ {
+ sal_uInt32 nState = store::ntohl(m_nState);
+ nState &= ~(STATE_CLOSE_WAIT | STATE_FLUSH_WAIT);
+ m_nState = store::htonl(nState);
+ }
+};
+
+/*========================================================================
+ *
+ * OStoreSuperBlockPage interface.
+ *
+ *======================================================================*/
+namespace store
+{
+
+struct OStoreSuperBlockPage
+{
+ typedef OStoreSuperBlock SuperBlock;
+ typedef OStoreStateBlock StateBlock;
+
+ /** Representation.
+ */
+ SuperBlock m_aSuperOne;
+ SuperBlock m_aSuperTwo;
+ StateBlock m_aState;
+
+ /** theSize.
+ */
+ static const size_t theSize = 2 * SuperBlock::theSize + StateBlock::theSize;
+ static const sal_uInt16 thePageSize = theSize;
+ STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize);
+
+ /** Allocation.
+ */
+ static void * operator new (size_t n) SAL_THROW(())
+ {
+ return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
+ }
+ static void operator delete (void * p, size_t) SAL_THROW(())
+ {
+ rtl_freeMemory (p);
+ }
+
+ static void * operator new (size_t, sal_uInt16 nPageSize) SAL_THROW(())
+ {
+ return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
+ }
+ static void operator delete (void * p, sal_uInt16) SAL_THROW(())
+ {
+ rtl_freeMemory (p);
+ }
+
+ /** Construction.
+ */
+ explicit OStoreSuperBlockPage (sal_uInt16 nPageSize = thePageSize)
+ : m_aSuperOne(nPageSize),
+ m_aSuperTwo(nPageSize),
+ m_aState()
+ {}
+
+ /** guard (external representation).
+ */
+ void guard()
+ {
+ m_aSuperOne.guard();
+ m_aSuperTwo.guard();
+ }
+
+ /** save.
+ */
+ storeError save (OStorePageBIOS &rBIOS)
+ {
+ // Guard.
+ guard();
+
+ // Write.
+ return rBIOS.write (0, this, theSize);
+ }
+
+ /** close.
+ */
+ storeError close (
+ OStorePageBIOS &rBIOS);
+
+ /** flush.
+ */
+ storeError flush (
+ OStorePageBIOS &rBIOS);
+
+ /** modified.
+ */
+ storeError modified (
+ OStorePageBIOS &rBIOS);
+
+ /** verify (with repair).
+ */
+ storeError verify (
+ OStorePageBIOS &rBIOS);
+};
+
+} // namespace store
+
+/*========================================================================
+ *
+ * OStoreSuperBlockPage implementation.
+ *
+ *======================================================================*/
+/*
+ * close.
+ */
+storeError OStoreSuperBlockPage::close (OStorePageBIOS &rBIOS)
+{
+ storeError eErrCode = store_E_None;
+ if (m_aState.closePending())
+ {
+ // Mark as modified.
+ m_aState.modified();
+
+ // Check access mode.
+ if (rBIOS.isWriteable())
+ {
+ // Save StateBlock.
+ StateBlock aState (m_aState);
+
+ // Mark as clean.
+ aState.clean();
+
+ // Write behind SuperBlock.
+ sal_uInt32 nAddr = 2 * SuperBlock::theSize;
+ eErrCode = rBIOS.write (nAddr, &aState, StateBlock::theSize);
+ }
+
+ // Mark as clean.
+ m_aState.clean();
+ }
+ return eErrCode;
+}
+
+/*
+ * flush.
+ */
+storeError OStoreSuperBlockPage::flush (OStorePageBIOS &rBIOS)
+{
+ storeError eErrCode = store_E_None;
+ if (m_aState.flushPending())
+ {
+ // Check access mode.
+ if (rBIOS.isWriteable())
+ {
+ // Save StateBlock.
+ StateBlock aState (m_aState);
+
+ // Mark as flushed.
+ aState.flushed();
+
+ // Write behind SuperBlock.
+ sal_uInt32 nAddr = 2 * SuperBlock::theSize;
+ eErrCode = rBIOS.write (nAddr, &aState, StateBlock::theSize);
+ }
+
+ // Mark as flushed.
+ m_aState.flushed();
+ }
+ return eErrCode;
+}
+
+/*
+ * modified.
+ */
+storeError OStoreSuperBlockPage::modified (OStorePageBIOS &rBIOS)
+{
+ storeError eErrCode = store_E_None;
+ if (!m_aState.flushPending())
+ {
+ // Mark as modified.
+ m_aState.modified();
+
+ // Check access mode.
+ if (rBIOS.isWriteable())
+ {
+ // Save StateBlock.
+ StateBlock aState (m_aState);
+
+ // Write behind SuperBlock.
+ sal_uInt32 nAddr = 2 * SuperBlock::theSize;
+ eErrCode = rBIOS.write (nAddr, &aState, StateBlock::theSize);
+ }
+ }
+ return eErrCode;
+}
+
+/*
+ * verify (with repair).
+ */
+storeError OStoreSuperBlockPage::verify (OStorePageBIOS &rBIOS)
+{
+ // Verify 1st copy.
+ storeError eErrCode = m_aSuperOne.verify();
+ if (eErrCode == store_E_None)
+ {
+ // Ok. Verify 2nd copy.
+ eErrCode = m_aSuperTwo.verify();
+ if (eErrCode == store_E_None)
+ {
+ // Ok. Ensure identical copies (1st copy wins).
+ if (!(m_aSuperOne == m_aSuperTwo))
+ {
+ // Different. Replace 2nd copy with 1st copy.
+ m_aSuperTwo = m_aSuperOne;
+
+ // Write back.
+ if (rBIOS.isWriteable())
+ eErrCode = rBIOS.write (0, this, theSize);
+ else
+ eErrCode = store_E_None;
+ }
+ }
+ else
+ {
+ // Failure. Replace 2nd copy with 1st copy.
+ m_aSuperTwo = m_aSuperOne;
+
+ // Write back.
+ if (rBIOS.isWriteable())
+ eErrCode = rBIOS.write (0, this, theSize);
+ else
+ eErrCode = store_E_None;
+ }
+ }
+ else
+ {
+ // Failure. Verify 2nd copy.
+ eErrCode = m_aSuperTwo.verify();
+ if (eErrCode == store_E_None)
+ {
+ // Ok. Replace 1st copy with 2nd copy.
+ m_aSuperOne = m_aSuperTwo;
+
+ // Write back.
+ if (rBIOS.isWriteable())
+ eErrCode = rBIOS.write (0, this, theSize);
+ else
+ eErrCode = store_E_None;
+ }
+ else
+ {
+ // Double Failure.
+ OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.\n");
+ }
+ }
+
+ // Done.
+ return eErrCode;
+}
+
+/*========================================================================
+ *
+ * OStorePageBIOS::Ace implementation.
+ *
+ *======================================================================*/
+OStorePageBIOS::Ace::Ace()
+ : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
+{}
+
+OStorePageBIOS::Ace::~Ace()
+{
+ m_next->m_prev = m_prev, m_prev->m_next = m_next;
+}
+
+int
+SAL_CALL OStorePageBIOS::Ace::constructor (void * obj, void * /* arg */)
+{
+ Ace * ace = static_cast<Ace*>(obj);
+ ace->m_next = ace->m_prev = ace;
+ return 1;
+}
+
+OStorePageBIOS::Ace *
+OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
+{
+ OStorePageBIOS::Ace * entry;
+ for (entry = head->m_next; entry != head; entry = entry->m_next)
+ {
+ if (entry->m_addr >= addr)
+ return entry;
+ }
+ return head;
+}
+
+void
+OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
+{
+ // insert entry at queue tail (before head).
+ entry->m_next = head;
+ entry->m_prev = head->m_prev;
+ head->m_prev = entry;
+ entry->m_prev->m_next = entry;
+}
+
+/*========================================================================
+ *
+ * OStorePageBIOS::AceCache interface.
+ *
+ *======================================================================*/
+namespace store
+{
+
+class OStorePageBIOS::AceCache
+{
+ rtl_cache_type * m_ace_cache;
+
+public:
+ static AceCache & get();
+
+ OStorePageBIOS::Ace *
+ create (sal_uInt32 addr, sal_uInt32 used = 1);
+
+ void
+ destroy (OStorePageBIOS::Ace * ace);
+
+protected:
+ AceCache();
+ ~AceCache();
+};
+
+} // namespace store
+
+/*========================================================================
+ *
+ * OStorePageBIOS::AceCache implementation.
+ *
+ *======================================================================*/
+extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*);
+
+OStorePageBIOS::AceCache &
+OStorePageBIOS::AceCache::get()
+{
+ static AceCache g_ace_cache;
+ return g_ace_cache;
+}
+
+OStorePageBIOS::AceCache::AceCache()
+{
+ m_ace_cache = rtl_cache_create (
+ "store_ace_cache",
+ sizeof (OStorePageBIOS::Ace),
+ 0, // objalign
+ reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor),
+ 0, // destructor,
+ 0, // reclaim,
+ 0, // userarg,
+ 0, // default source,
+ 0 // flags
+ );
+}
+
+OStorePageBIOS::AceCache::~AceCache()
+{
+ rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
+}
+
+OStorePageBIOS::Ace *
+OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
+{
+ Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
+ if (ace != 0)
+ {
+ // verify invariant state.
+ OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
+
+ // initialize.
+ ace->m_addr = addr;
+ ace->m_used = used;
+ }
+ return ace;
+}
+
+void
+OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
+{
+ if (ace != 0)
+ {
+ // remove from queue (if any).
+ ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
+
+ // restore invariant state.
+ ace->m_next = ace->m_prev = ace;
+
+ // return to cache.
+ rtl_cache_free (m_ace_cache, ace);
+ }
+}
+
+/*========================================================================
+ *
+ * OStorePageBIOS implementation.
+ *
+ *======================================================================*/
+/*
+ * OStorePageBIOS.
+ */
+OStorePageBIOS::OStorePageBIOS (void)
+ : m_xLockBytes (NULL),
+ m_pSuper (NULL),
+ m_bModified (sal_False),
+ m_bWriteable (sal_False)
+{
+}
+
+/*
+ * ~OStorePageBIOS.
+ */
+OStorePageBIOS::~OStorePageBIOS (void)
+{
+ OStorePageBIOS::close();
+}
+
+/*
+ * verify (SuperBlock with repair).
+ * Internal: Precond: initialized, exclusive access.
+ */
+storeError OStorePageBIOS::verify (SuperPage *&rpSuper)
+{
+ // Check SuperBlock page allocation.
+ if (rpSuper == 0)
+ {
+ // Allocate.
+ if ((rpSuper = new SuperPage()) == 0)
+ return store_E_OutOfMemory;
+
+ // Load (w/o verification).
+ storeError eErrCode = read (0, rpSuper, SuperPage::theSize);
+ if (eErrCode != store_E_None)
+ {
+ // Cleanup and fail.
+ delete rpSuper, rpSuper = 0;
+ return eErrCode;
+ }
+
+ // Check SuperBlock state.
+ if (rpSuper->m_aState.closePending())
+ OSL_TRACE("OStorePageBIOS::verify(): close pending.\n");
+
+ if (rpSuper->m_aState.flushPending())
+ OSL_TRACE("OStorePageBIOS::verify(): flush pending.\n");
+ }
+
+ // Verify SuperBlock page (with repair).
+ return rpSuper->verify (*this);
+}
+
+/*
+ * repair (SuperBlock).
+ * Internal: Precond: initialized, exclusive access.
+ */
+storeError OStorePageBIOS::repair (SuperPage *&rpSuper)
+{
+ // Acquire Lock.
+ storeError eErrCode = acquireLock (0, SuperPage::theSize);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Verify SuperBlock page (with repair).
+ eErrCode = verify (rpSuper);
+ if (eErrCode != store_E_None)
+ {
+ // Failure.
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // ReleaseLock.
+ return releaseLock (0, SuperPage::theSize);
+}
+
+/*
+ * create (SuperBlock).
+ * Internal: Precond: initialized, exclusive access.
+ */
+storeError OStorePageBIOS::create (sal_uInt16 nPageSize)
+{
+ // Check (internal) precond.
+ OSL_PRECOND(m_xLockBytes.is(), "store::PageBIOS::create(): contract violation");
+
+ // Check PageSize.
+ if ((STORE_MINIMUM_PAGESIZE > nPageSize) || (nPageSize > STORE_MAXIMUM_PAGESIZE))
+ return store_E_InvalidParameter;
+ nPageSize = ((nPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
+
+ // Acquire Lock.
+ storeError eErrCode = acquireLock (0, nPageSize);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Allocate SuperBlock page.
+ delete m_pSuper, m_pSuper = 0;
+ if ((m_pSuper = new(nPageSize) SuperPage(nPageSize)) == 0)
+ {
+ // Cleanup and fail.
+ releaseLock (0, nPageSize);
+ return store_E_OutOfMemory;
+ }
+ m_pSuper->guard();
+
+ // Create initial page (w/ SuperBlock).
+ eErrCode = m_xLockBytes->writeAt (0, m_pSuper, nPageSize);
+ if (eErrCode != store_E_None)
+ {
+ // Cleanup and fail.
+ releaseLock (0, nPageSize);
+ return eErrCode;
+ }
+
+#ifdef STORE_FEATURE_COMMIT
+ // Commit.
+ eErrCode = m_xLockBytes->flush();
+ OSL_POSTCOND(
+ eErrCode == store_E_None,
+ "OStorePageBIOS::create(): flush failed");
+#endif /* STORE_FEATURE_COMMIT */
+
+ // Adjust modified state.
+ m_bModified = (eErrCode != store_E_None);
+
+ // Release Lock and finish.
+ return releaseLock (0, nPageSize);
+}
+
+/*
+ * initialize.
+ * Precond: none.
+ */
+storeError OStorePageBIOS::initialize (
+ ILockBytes * pLockBytes,
+ storeAccessMode eAccessMode,
+ sal_uInt16 & rnPageSize)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check arguments.
+ storeError eErrCode = store_E_InvalidParameter;
+ if (!pLockBytes)
+ return eErrCode;
+
+ // Cleanup.
+#if 0 /* OLD */
+ __STORE_DELETEZ (m_pAcl); /* @@@ */
+#endif /* OLD */
+ delete m_pSuper, m_pSuper = 0;
+
+ // Initialize.
+ m_xLockBytes = pLockBytes;
+ m_bModified = sal_False;
+ m_bWriteable = (!(eAccessMode == store_AccessReadOnly));
+
+ // Check access mode.
+ if (eAccessMode == store_AccessReadOnly)
+ {
+ // Verify SuperBlock page.
+ eErrCode = verify (m_pSuper);
+ }
+ else if (eAccessMode != store_AccessCreate)
+ {
+ // Verify (w/ repair) SuperBlock page.
+ eErrCode = repair (m_pSuper);
+ }
+ else
+ {
+ // Truncate to zero length.
+ eErrCode = m_xLockBytes->setSize(0);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+#ifdef STORE_FEATURE_COMMIT
+ // Commit.
+ eErrCode = m_xLockBytes->flush();
+ if (eErrCode != store_E_None)
+ return eErrCode;
+#endif /* STORE_FEATURE_COMMIT */
+
+ // Mark as not existing.
+ eErrCode = store_E_NotExists;
+ }
+
+ if (eErrCode != store_E_None)
+ {
+ // Check reason.
+ if (eErrCode != store_E_NotExists)
+ return eErrCode;
+
+ // Check mode.
+ if (eAccessMode == store_AccessReadOnly)
+ return store_E_NotExists;
+ if (eAccessMode == store_AccessReadWrite)
+ return store_E_NotExists;
+
+ // Create SuperBlock page.
+ eErrCode = create (rnPageSize);
+ }
+ if (eErrCode == store_E_None)
+ {
+ // Obtain modified state.
+ m_bModified = m_pSuper->m_aState.flushPending();
+
+ // Obtain page size.
+ rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
+
+ // Create page allocator.
+ eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Create page cache.
+ eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
+ }
+ return eErrCode;
+}
+
+/*
+ * acquireLock.
+ * Low Level: Precond: initialized, exclusive access.
+ */
+storeError OStorePageBIOS::acquireLock (
+ sal_uInt32 nAddr, sal_uInt32 nSize)
+{
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Acquire Lock.
+ return m_xLockBytes->lockRange (nAddr, nSize);
+}
+
+/*
+ * releaseLock.
+ * Low Level: Precond: initialized, exclusive access.
+ */
+storeError OStorePageBIOS::releaseLock (
+ sal_uInt32 nAddr, sal_uInt32 nSize)
+{
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Release Lock.
+ return m_xLockBytes->unlockRange (nAddr, nSize);
+}
+
+/*
+ * read.
+ * Low Level: Precond: initialized, exclusive access.
+ */
+storeError OStorePageBIOS::read (
+ sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
+{
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Read Page.
+ return m_xLockBytes->readAt (nAddr, pData, nSize);
+}
+
+/*
+ * write.
+ * Low Level: Precond: initialized, writeable, exclusive access.
+ */
+storeError OStorePageBIOS::write (
+ sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
+{
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+ if (!m_bWriteable)
+ return store_E_AccessViolation;
+
+ // Check modified state.
+ if (!m_bModified)
+ {
+ // Mark as modified.
+ m_bModified = sal_True;
+
+ // Mark SuperBlock modified.
+ storeError eErrCode = m_pSuper->modified (*this);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+ }
+
+ // Write Data.
+ return m_xLockBytes->writeAt (nAddr, pData, nSize);
+}
+
+/*
+ * acquirePage.
+ * Precond: initialized.
+ */
+storeError OStorePageBIOS::acquirePage (
+ const OStorePageDescriptor& rDescr, storeAccessMode eMode)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Check access mode.
+ if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
+ return store_E_AccessViolation;
+
+ // Find access control list entry.
+ Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
+ if (ace->m_addr == rDescr.m_nAddr)
+ {
+ // Acquire existing entry (with ShareDenyWrite).
+ if (eMode == store_AccessReadOnly)
+ ace->m_used += 1;
+ else
+ return store_E_AccessViolation;
+ }
+ else
+ {
+ // Insert new entry.
+ Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1);
+ if (!entry)
+ return store_E_OutOfMemory;
+ Ace::insert (ace, entry);
+ }
+
+ // Increment total referer count and finish.
+ m_ace_head.m_used += 1;
+ return store_E_None;
+}
+
+/*
+ * releasePage.
+ * Precond: initialized.
+ */
+storeError OStorePageBIOS::releasePage (
+ const OStorePageDescriptor& rDescr, storeAccessMode /* eMode */)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Find access control list entry.
+ Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
+ if (ace->m_addr != rDescr.m_nAddr)
+ return store_E_NotExists;
+
+ // Release existing entry.
+ if (ace->m_used > 1)
+ ace->m_used -= 1;
+ else
+ AceCache::get().destroy (ace);
+
+ // Decrement total referer count and finish.
+ m_ace_head.m_used -= 1;
+ return store_E_None;
+}
+
+/*
+ * getRefererCount.
+ * Precond: none.
+ */
+sal_uInt32 OStorePageBIOS::getRefererCount (void)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Obtain total referer count.
+ return m_ace_head.m_used;
+}
+
+/*
+ * allocate.
+ * Precond: initialized, writeable.
+ */
+storeError OStorePageBIOS::allocate (
+ OStorePageObject& rPage, Allocation eAlloc)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+ if (!m_bWriteable)
+ return store_E_AccessViolation;
+
+ // Acquire SuperBlock Lock.
+ storeError eErrCode = acquireLock (0, SuperPage::theSize);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Load SuperBlock and require good health.
+ eErrCode = verify (m_pSuper);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // Check allocation.
+ if (eAlloc != ALLOCATE_EOF)
+ {
+ // Check FreeList.
+ OStorePageLink aListHead (m_pSuper->m_aSuperTwo.unusedHead());
+ if (aListHead.location())
+ {
+ // Allocate from FreeList.
+ OStorePageData aPageHead (OStorePageData::theSize);
+ aPageHead.location (aListHead.location());
+
+ // Load PageHead.
+ eErrCode = peek (aPageHead);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // Verify FreeList head.
+ OSL_PRECOND(
+ aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL,
+ "OStorePageBIOS::allocate(): page not free");
+ if (aPageHead.m_aUnused.location() == STORE_PAGE_NULL)
+ {
+ // Recovery: Reset FreeList.
+ m_pSuper->m_aSuperTwo.unusedReset();
+ m_pSuper->m_aSuperOne = m_pSuper->m_aSuperTwo;
+
+ // Save SuperBlock page.
+ eErrCode = m_pSuper->save (*this);
+
+ // Release SuperBlock Lock.
+ releaseLock (0, SuperPage::theSize);
+
+ // Recovery: Allocate from EOF.
+ if (eErrCode == store_E_None)
+ return allocate (rPage, ALLOCATE_EOF);
+ else
+ return store_E_Unknown;
+ }
+
+ // Pop from FreeList.
+ aListHead = aPageHead.m_aUnused.location();
+ rPage.get()->m_aUnused = STORE_PAGE_NULL;
+
+ // Save page at PageHead location.
+ eErrCode = saveObjectAt_Impl (rPage, aPageHead.location());
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // Save SuperBlock page.
+ m_pSuper->m_aSuperTwo.unusedRemove (aListHead);
+ m_pSuper->m_aSuperOne = m_pSuper->m_aSuperTwo;
+
+ eErrCode = m_pSuper->save (*this);
+ OSL_POSTCOND(
+ eErrCode == store_E_None,
+ "OStorePageBIOS::allocate(): SuperBlock save failed");
+
+ // Release SuperBlock Lock and finish.
+ return releaseLock (0, SuperPage::theSize);
+ }
+ }
+
+ // Allocate from logical EOF. Determine physical EOF.
+ sal_uInt32 nPhysLen = STORE_PAGE_NULL;
+ eErrCode = m_xLockBytes->getSize (nPhysLen);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // Obtain logical EOF.
+ OStorePageDescriptor aDescr (m_pSuper->m_aSuperTwo.m_aDescr);
+ sal_uInt32 nLogLen = store::ntohl(aDescr.m_nAddr);
+ if (nLogLen == 0)
+ nLogLen = nPhysLen; /* backward compatibility */
+
+ if (!(nLogLen < nPhysLen))
+ {
+ // Check modified state.
+ if (!m_bModified)
+ {
+ // Mark modified.
+ m_bModified = sal_True;
+
+ // Mark SuperBlock modified.
+ eErrCode = m_pSuper->modified (*this);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+ }
+
+ // Resize.
+ sal_uInt32 nAlign = SAL_MIN (nPhysLen, STORE_MAXIMUM_PAGESIZE);
+ nPhysLen = ((nPhysLen + nAlign) / nAlign) * nAlign;
+
+ eErrCode = m_xLockBytes->setSize (nPhysLen);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+ }
+
+ // Save page at logical EOF.
+ eErrCode = saveObjectAt_Impl (rPage, nLogLen);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // Save SuperBlock page.
+ nLogLen += store::ntohs(aDescr.m_nSize);
+ aDescr.m_nAddr = store::htonl(nLogLen);
+
+ m_pSuper->m_aSuperTwo.m_aDescr = aDescr;
+ m_pSuper->m_aSuperOne = m_pSuper->m_aSuperTwo;
+
+ eErrCode = m_pSuper->save (*this);
+ OSL_POSTCOND(
+ eErrCode == store_E_None,
+ "OStorePageBIOS::allocate(): SuperBlock save failed");
+
+ // Release SuperBlock Lock and finish.
+ return releaseLock (0, SuperPage::theSize);
+}
+
+/*
+ * free.
+ * Precond: initialized, writeable.
+ */
+storeError OStorePageBIOS::free (OStorePageData & /* rData */, sal_uInt32 nAddr)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+ if (!m_bWriteable)
+ return store_E_AccessViolation;
+
+ // Acquire SuperBlock Lock.
+ storeError eErrCode = acquireLock (0, SuperPage::theSize);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Load SuperBlock and require good health.
+ eErrCode = verify (m_pSuper);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // Load PageHead.
+ OStorePageData aPageHead(OStorePageData::theSize);
+ aPageHead.location (nAddr);
+
+ eErrCode = peek (aPageHead);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // Invalidate cache.
+ (void) m_xCache->removePageAt (nAddr);
+
+ // Push onto FreeList.
+ OStorePageLink aListHead (m_pSuper->m_aSuperTwo.unusedHead());
+
+ aPageHead.m_aUnused.m_nAddr = aListHead.m_nAddr;
+ aListHead.m_nAddr = aPageHead.m_aDescr.m_nAddr;
+
+ // Save PageHead.
+ eErrCode = poke (aPageHead);
+ if (eErrCode != store_E_None)
+ {
+ releaseLock (0, SuperPage::theSize);
+ return eErrCode;
+ }
+
+ // Save SuperBlock page.
+ m_pSuper->m_aSuperTwo.unusedInsert (aListHead);
+ m_pSuper->m_aSuperOne = m_pSuper->m_aSuperTwo;
+
+ eErrCode = m_pSuper->save (*this);
+ OSL_POSTCOND(
+ eErrCode == store_E_None,
+ "OStorePageBIOS::free(): SuperBlock save failed");
+
+ // Release SuperBlock Lock and finish.
+ return releaseLock (0, SuperPage::theSize);
+}
+
+/*
+ * loadObjectAt.
+ * Precond: initialized, readable.
+ */
+storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ return loadObjectAt_Impl (rPage, nAddr);
+}
+
+/*
+ * loadObjectAt_Impl.
+ * Internal: Precond: initialized, readable, exclusive access.
+ */
+storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
+{
+ storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
+ if (eErrCode != store_E_NotExists)
+ return eErrCode;
+
+ // Read page.
+ eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Verify page.
+ eErrCode = rPage.verify (nAddr);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Mark page as clean.
+ rPage.clean();
+
+ // Cache page.
+ return m_xCache->insertPageAt (rPage.get(), nAddr);
+}
+
+/*
+ * saveObjectAt.
+ * Precond: initialized, writeable.
+ */
+storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+ if (!m_bWriteable)
+ return store_E_AccessViolation;
+
+ // Save Page.
+ return saveObjectAt_Impl (rPage, nAddr);
+}
+
+/*
+ * saveObjectAt_Impl.
+ * Internal: Precond: initialized, writeable, exclusive access.
+ */
+storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
+{
+ // Guard page (incl. set location).
+ storeError eErrCode = rPage.guard (nAddr);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Write page.
+ eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Mark page as clean.
+ rPage.clean();
+
+ // Cache page.
+ return m_xCache->updatePageAt (rPage.get(), nAddr);
+}
+
+/*
+ * close.
+ * Precond: none.
+ */
+storeError OStorePageBIOS::close (void)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check referer count.
+ if (m_ace_head.m_used > 0)
+ {
+ // Report remaining referer count.
+ OSL_TRACE("store::PageBIOS::close(): referer count: %d\n", m_ace_head.m_used);
+#if 1 /* NEW */
+ for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next)
+ {
+ m_ace_head.m_used -= ace->m_used;
+ AceCache::get().destroy (ace);
+ }
+ OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::close(): logic error");
+#endif /* NEW */
+ }
+
+ // Check SuperBlock page.
+ storeError eErrCode = store_E_None;
+ if (m_pSuper)
+ {
+ // Release SuperBlock page.
+ eErrCode = m_pSuper->close (*this);
+ delete m_pSuper, m_pSuper = 0;
+ }
+
+ // Release PageCache.
+ m_xCache.clear();
+
+ // Check LockBytes.
+ if (m_xLockBytes.is())
+ {
+#ifdef STORE_FEATURE_COMMIT
+ // Commit.
+ storeError result = m_xLockBytes->flush();
+ if (eErrCode == store_E_None)
+ {
+ // Previous result(s) okay. Propagate next result.
+ eErrCode = result;
+ }
+#endif /* STORE_FEATURE_COMMIT */
+
+ // Release LockBytes.
+ m_xLockBytes.clear();
+ }
+
+ // Done.
+ return eErrCode;
+}
+
+/*
+ * flush.
+ * Precond: initialized.
+ */
+storeError OStorePageBIOS::flush (void)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Check mode and state.
+ storeError eErrCode = store_E_None;
+ if (!(m_bWriteable && m_bModified))
+ return eErrCode;
+
+ // Flush SuperBlock page.
+ eErrCode = m_pSuper->flush (*this);
+
+ // Flush LockBytes.
+ storeError result = m_xLockBytes->flush();
+ if (eErrCode == store_E_None)
+ {
+ // Previous result(s) okay. Propagate next result.
+ eErrCode = result;
+ }
+
+ // Adjust modified state.
+ m_bModified = (eErrCode != store_E_None);
+
+ // Done.
+ return eErrCode;
+}
+
+/*
+ * size.
+ * Precond: initialized.
+ */
+storeError OStorePageBIOS::size (sal_uInt32 &rnSize)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Initialize [out] param.
+ rnSize = 0;
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Obtain LockBytes size.
+ return m_xLockBytes->getSize (rnSize);
+}
+
+/*
+ * scanBegin.
+ * Precond: initialized.
+ */
+storeError OStorePageBIOS::scanBegin (
+ ScanContext &rCtx, sal_uInt32 nMagic)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Initialize [out] param.
+ rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0);
+ rCtx.m_nSize = 0;
+ rCtx.m_nMagic = nMagic;
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Check SuperBlock page.
+ storeError eErrCode = verify (m_pSuper);
+ if (eErrCode != store_E_None)
+ {
+ // Damaged. Determine page size (NYI).
+ OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n");
+ return eErrCode;
+ }
+
+ // Setup Context descriptor.
+ rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr;
+ rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize; // @@@ ntoh @@@
+
+ // Setup Context size.
+ eErrCode = size (rCtx.m_nSize);
+ if (eErrCode != store_E_None)
+ rCtx.m_nSize = ((sal_uInt32)(~0));
+
+ // Done.
+ return store_E_None;
+}
+
+/*
+ * scanNext.
+ * Precond: initialized.
+ */
+storeError OStorePageBIOS::scanNext (
+ ScanContext &rCtx, OStorePageObject &rPage)
+{
+ // Acquire exclusive access.
+ osl::MutexGuard aGuard (m_aMutex);
+
+ // Check precond.
+ if (!m_xLockBytes.is())
+ return store_E_InvalidAccess;
+
+ // Setup PageHead.
+ OStorePageData aPageHead (OStorePageData::theSize);
+
+ // Check context.
+ while (rCtx.isValid())
+ {
+ // Assign next location.
+ aPageHead.location (rCtx.m_aDescr.m_nAddr);
+ rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
+
+ // Load PageHead.
+ storeError eErrCode = peek (aPageHead);
+ if (eErrCode != store_E_None)
+ continue;
+
+ // Check PageHead Magic number.
+ if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic)
+ continue;
+
+ // Check PageHead Unused link.
+ if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL)
+ continue;
+
+ // Load page.
+ eErrCode = loadObjectAt_Impl (rPage, aPageHead.location());
+ if (eErrCode != store_E_None)
+ continue;
+
+ // Deliver page.
+ return store_E_None;
+ }
+
+ // Done.
+ return store_E_CantSeek;
+}
+
+/*
+ * peek (PageHead).
+ * Internal: Precond: initialized, readable, exclusive access.
+ */
+storeError OStorePageBIOS::peek (OStorePageData &rData)
+{
+ // Read PageHead.
+ storeError eErrCode = read (rData.location(), &rData, OStorePageData::theSize);
+ if (eErrCode != store_E_None)
+ return eErrCode;
+
+ // Verify PageHead.
+ return rData.verify();
+}
+
+/*
+ * poke (PageHead).
+ * Internal: Precond: initialized, writeable, exclusive access.
+ */
+storeError OStorePageBIOS::poke (OStorePageData &rData)
+{
+ // Guard PageHead.
+ rData.guard();
+
+ // Write PageHead.
+ return write (rData.location(), &rData, OStorePageData::theSize);
+}