office-gobmx/store/source/storbios.cxx
2012-06-27 19:30:33 +01:00

1121 lines
28 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#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 & rhs)
: m_aGuard (rhs.m_aGuard),
m_aDescr (rhs.m_aDescr),
m_nMarked (rhs.m_nMarked),
m_aMarked (rhs.m_aMarked),
m_nUnused (rhs.m_nUnused),
m_aUnused (rhs.m_aUnused)
{}
OStoreSuperBlock& operator= (const OStoreSuperBlock & rhs)
{
m_aGuard = rhs.m_aGuard;
m_aDescr = rhs.m_aDescr;
m_nMarked = rhs.m_nMarked;
m_aMarked = rhs.m_aMarked;
m_nUnused = rhs.m_nUnused;
m_aUnused = rhs.m_aUnused;
return *this;
}
/** Comparison.
*/
sal_Bool operator== (const OStoreSuperBlock & rhs) const
{
return ((m_aGuard == rhs.m_aGuard ) &&
(m_aDescr == rhs.m_aDescr ) &&
(m_nMarked == rhs.m_nMarked) &&
(m_aMarked == rhs.m_aMarked) &&
(m_nUnused == rhs.m_nUnused) &&
(m_aUnused == rhs.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;
}
};
/*========================================================================
*
* SuperBlockPage interface.
*
*======================================================================*/
namespace store
{
struct SuperBlockPage
{
typedef OStoreSuperBlock SuperBlock;
/** Representation.
*/
SuperBlock m_aSuperOne;
SuperBlock m_aSuperTwo;
/** theSize.
*/
static const size_t theSize = 2 * SuperBlock::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) SAL_THROW(())
{
rtl_freeMemory (p);
}
static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize) SAL_THROW(())
{
return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
}
static void operator delete (void * p, SAL_UNUSED_PARAMETER sal_uInt16) SAL_THROW(())
{
rtl_freeMemory (p);
}
/** Construction.
*/
explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
: m_aSuperOne(nPageSize),
m_aSuperTwo(nPageSize)
{}
/** save.
*/
storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
{
m_aSuperOne.guard();
m_aSuperTwo = m_aSuperOne;
return rBIOS.write (0, this, nSize);
}
/** Page allocation.
*/
storeError unusedHead (
OStorePageBIOS & rBIOS,
PageData & rPageHead);
storeError unusedPop (
OStorePageBIOS & rBIOS,
PageData const & rPageHead);
storeError unusedPush (
OStorePageBIOS & rBIOS,
sal_uInt32 nAddr);
/** verify (with repair).
*/
storeError verify (OStorePageBIOS & rBIOS);
};
} // namespace store
/*========================================================================
*
* SuperBlockPage implementation.
*
*======================================================================*/
/*
* unusedHead(): get freelist head (alloc page, step 1).
*/
storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
{
storeError eErrCode = verify (rBIOS);
if (eErrCode != store_E_None)
return eErrCode;
// Check freelist head.
OStorePageLink const aListHead (m_aSuperOne.unusedHead());
if (aListHead.location() == 0)
{
// Freelist empty, see SuperBlock::ctor().
rPageHead.location (STORE_PAGE_NULL);
return store_E_None;
}
// Load PageHead.
eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
if (eErrCode != store_E_None)
return eErrCode;
eErrCode = rPageHead.verify (aListHead.location());
if (eErrCode != store_E_None)
return eErrCode;
// Verify page is unused.
sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
OSL_POSTCOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedHead(): page not free");
if (nAddr == STORE_PAGE_NULL)
{
// Page in use.
rPageHead.location (STORE_PAGE_NULL);
// Recovery: Reset freelist to empty.
m_aSuperOne.unusedReset();
eErrCode = save (rBIOS);
}
return eErrCode;
}
/*
* unusedPop(): pop freelist head (alloc page, step 2).
*/
storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
{
sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
if (nAddr == STORE_PAGE_NULL)
return store_E_CantSeek;
// Pop from FreeList.
OStorePageLink const aListHead (nAddr);
m_aSuperOne.unusedRemove (aListHead);
return save (rBIOS);
}
/*
* unusedPush(): push new freelist head.
*/
storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
{
storeError eErrCode = verify (rBIOS);
if (eErrCode != store_E_None)
return eErrCode;
PageData aPageHead;
eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
if (eErrCode != store_E_None)
return eErrCode;
eErrCode = aPageHead.verify (nAddr);
if (eErrCode != store_E_None)
return eErrCode;
aPageHead.m_aUnused = m_aSuperOne.unusedHead();
aPageHead.guard (nAddr);
eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
if (eErrCode != store_E_None)
return eErrCode;
OStorePageLink const aListHead (nAddr);
m_aSuperOne.unusedInsert(aListHead);
return save (rBIOS);
}
/*
* verify (with repair).
*/
storeError SuperBlockPage::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.");
}
}
// 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, SAL_UNUSED_PARAMETER 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_bWriteable (false)
{
}
/*
* ~OStorePageBIOS.
*/
OStorePageBIOS::~OStorePageBIOS (void)
{
cleanup_Impl();
}
/*
* initialize.
* Precond: none.
*/
storeError OStorePageBIOS::initialize (
ILockBytes * pLockBytes,
storeAccessMode eAccessMode,
sal_uInt16 & rnPageSize)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Initialize.
storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
if (eErrCode != store_E_None)
{
// Cleanup.
cleanup_Impl();
}
return eErrCode;
}
/*
* initialize_Impl.
* Internal: Precond: exclusive access.
*/
storeError OStorePageBIOS::initialize_Impl (
ILockBytes * pLockBytes,
storeAccessMode eAccessMode,
sal_uInt16 & rnPageSize)
{
// Cleanup.
cleanup_Impl();
// Initialize.
m_xLockBytes = pLockBytes;
if (!m_xLockBytes.is())
return store_E_InvalidParameter;
m_bWriteable = (eAccessMode != store_AccessReadOnly);
// Check access mode.
storeError eErrCode = store_E_None;
if (eAccessMode != store_AccessCreate)
{
// Load SuperBlock page.
if ((m_pSuper = new SuperBlockPage()) == 0)
return store_E_OutOfMemory;
eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
if (eErrCode == store_E_None)
{
// Verify SuperBlock page (with repair).
eErrCode = m_pSuper->verify (*this);
}
}
else
{
// Truncate to zero length.
eErrCode = m_xLockBytes->setSize(0);
if (eErrCode != store_E_None)
return eErrCode;
// 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;
// Check PageSize.
if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
return store_E_InvalidParameter;
rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
// Create initial page (w/ SuperBlock).
if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
return store_E_OutOfMemory;
eErrCode = m_pSuper->save (*this, rnPageSize);
}
if (eErrCode == store_E_None)
{
// 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;
}
/*
* cleanup_Impl.
* Internal: Precond: exclusive access.
*/
void OStorePageBIOS::cleanup_Impl()
{
// Check referer count.
if (m_ace_head.m_used > 0)
{
// Report remaining referer count.
OSL_TRACE("store::PageBIOS::cleanup_Impl(): referer count: %d", m_ace_head.m_used);
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::cleanup_Impl(): logic error");
}
// Release SuperBlock page.
delete m_pSuper, m_pSuper = 0;
// Release PageCache.
m_xCache.clear();
// Release PageAllocator.
m_xAllocator.clear();
// Release LockBytes.
m_xLockBytes.clear();
}
/*
* 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 Data.
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;
// 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)
{
// 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;
// Check allocation type.
storeError eErrCode = store_E_None;
if (eAlloc != ALLOCATE_EOF)
{
// Try freelist head.
PageData aPageHead;
eErrCode = m_pSuper->unusedHead (*this, aPageHead);
if (eErrCode != store_E_None)
return eErrCode;
sal_uInt32 const nAddr = aPageHead.location();
if (nAddr != STORE_PAGE_NULL)
{
// Save page.
eErrCode = saveObjectAt_Impl (rPage, nAddr);
if (eErrCode != store_E_None)
return eErrCode;
// Pop freelist head and finish.
return m_pSuper->unusedPop (*this, aPageHead);
}
}
// Allocate from EOF. Determine current size.
sal_uInt32 nSize = STORE_PAGE_NULL;
eErrCode = m_xLockBytes->getSize (nSize);
if (eErrCode != store_E_None)
return eErrCode;
// Save page at current EOF.
return saveObjectAt_Impl (rPage, nSize);
}
/*
* free.
* Precond: initialized, writeable.
*/
storeError OStorePageBIOS::free (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;
// Invalidate cache.
(void) m_xCache->removePageAt (nAddr);
// Push onto freelist.
return m_pSuper->unusedPush (*this, nAddr);
}
/*
* 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()
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Cleanup.
cleanup_Impl();
// Done.
return store_E_None;
}
/*
* 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;
// Flush LockBytes and finish.
return m_xLockBytes->flush();
}
/*
* 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 = m_pSuper->verify (*this);
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_nSize = store::ntohs(rCtx.m_aDescr.m_nSize);
rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize;
// 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.
PageData aPageHead;
// Check context.
while (rCtx.isValid())
{
// Assign next location.
sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr;
rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
// Read PageHead.
storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize);
if (eErrCode != store_E_None)
continue;
// Verify PageHead.
eErrCode = aPageHead.verify (nAddr);
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, nAddr);
if (eErrCode != store_E_None)
continue;
// Deliver page.
return store_E_None;
}
// Done.
return store_E_CantSeek;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */