diff options
Diffstat (limited to 'store/source')
-rw-r--r-- | store/source/lockbyte.cxx | 947 | ||||
-rw-r--r-- | store/source/lockbyte.hxx | 184 | ||||
-rw-r--r-- | store/source/makefile.mk | 71 | ||||
-rw-r--r-- | store/source/object.cxx | 112 | ||||
-rw-r--r-- | store/source/object.hxx | 138 | ||||
-rw-r--r-- | store/source/storbase.cxx | 197 | ||||
-rw-r--r-- | store/source/storbase.hxx | 954 | ||||
-rw-r--r-- | store/source/storbios.cxx | 1129 | ||||
-rw-r--r-- | store/source/storbios.hxx | 267 | ||||
-rw-r--r-- | store/source/storcach.cxx | 561 | ||||
-rw-r--r-- | store/source/storcach.hxx | 112 | ||||
-rw-r--r-- | store/source/stordata.cxx | 1130 | ||||
-rw-r--r-- | store/source/stordata.hxx | 870 | ||||
-rw-r--r-- | store/source/stordir.cxx | 241 | ||||
-rw-r--r-- | store/source/stordir.hxx | 149 | ||||
-rw-r--r-- | store/source/store.cxx | 765 | ||||
-rw-r--r-- | store/source/storlckb.cxx | 451 | ||||
-rw-r--r-- | store/source/storlckb.hxx | 171 | ||||
-rw-r--r-- | store/source/storpage.cxx | 1057 | ||||
-rw-r--r-- | store/source/storpage.hxx | 226 | ||||
-rw-r--r-- | store/source/stortree.cxx | 582 | ||||
-rw-r--r-- | store/source/stortree.hxx | 345 |
22 files changed, 10659 insertions, 0 deletions
diff --git a/store/source/lockbyte.cxx b/store/source/lockbyte.cxx new file mode 100644 index 000000000000..f1145a029c29 --- /dev/null +++ b/store/source/lockbyte.cxx @@ -0,0 +1,947 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "lockbyte.hxx" + +#include "sal/types.h" +#include "osl/diagnose.h" +#include "osl/file.h" +#include "osl/process.h" +#include "rtl/alloc.h" +#include "rtl/ustring.hxx" + +#include "object.hxx" +#include "storbase.hxx" + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif + +using namespace store; + +/*======================================================================== + * + * ILockBytes (non-virtual interface) implementation. + * + *======================================================================*/ + +storeError ILockBytes::initialize (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + OSL_PRECOND((STORE_MINIMUM_PAGESIZE <= nPageSize) && (nPageSize <= STORE_MAXIMUM_PAGESIZE), "invalid PageSize"); + return initialize_Impl (rxAllocator, nPageSize); +} + +storeError ILockBytes::readPageAt (PageHolder & rPage, sal_uInt32 nOffset) +{ + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readPageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return readPageAt_Impl (rPage, nOffset); +} + +storeError ILockBytes::writePageAt (PageHolder const & rPage, sal_uInt32 nOffset) +{ + // [SECURITY:ValInput] + PageData const * pagedata = rPage.get(); + OSL_PRECOND(!(pagedata == 0), "store::ILockBytes::writePageAt(): invalid Page"); + if (pagedata == 0) + return store_E_InvalidParameter; + + sal_uInt32 const offset = pagedata->location(); + OSL_PRECOND(!(nOffset != offset), "store::ILockBytes::writePageAt(): inconsistent Offset"); + if (nOffset != offset) + return store_E_InvalidParameter; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writePageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return writePageAt_Impl (rPage, nOffset); +} + +storeError ILockBytes::readAt (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + // [SECURITY:ValInput] + sal_uInt8 * dst_lo = static_cast<sal_uInt8*>(pBuffer); + if (!(dst_lo != 0)) + return store_E_InvalidParameter; + + sal_uInt8 * dst_hi = dst_lo + nBytes; + if (!(dst_lo < dst_hi)) + return (dst_lo > dst_hi) ? store_E_InvalidParameter : store_E_None; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + sal_uInt64 const src_size = nOffset + nBytes; + if (src_size > SAL_MAX_UINT32) + return store_E_CantSeek; + + return readAt_Impl (nOffset, dst_lo, (dst_hi - dst_lo)); +} + +storeError ILockBytes::writeAt (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) +{ + // [SECURITY:ValInput] + sal_uInt8 const * src_lo = static_cast<sal_uInt8 const*>(pBuffer); + if (!(src_lo != 0)) + return store_E_InvalidParameter; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if (!(src_lo < src_hi)) + return (src_lo > src_hi) ? store_E_InvalidParameter : store_E_None; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writeAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + sal_uInt64 const dst_size = nOffset + nBytes; + if (dst_size > SAL_MAX_UINT32) + return store_E_CantSeek; + + return writeAt_Impl (nOffset, src_lo, (src_hi - src_lo)); +} + +storeError ILockBytes::getSize (sal_uInt32 & rnSize) +{ + rnSize = 0; + return getSize_Impl (rnSize); +} + +storeError ILockBytes::setSize (sal_uInt32 nSize) +{ + return setSize_Impl (nSize); +} + +storeError ILockBytes::flush() +{ + return flush_Impl(); +} + +/*======================================================================== + * + * FileLockBytes implementation. + * + *======================================================================*/ +namespace store +{ + +struct FileHandle +{ + oslFileHandle m_handle; + + FileHandle() : m_handle(0) {} + + bool operator != (FileHandle const & rhs) + { + return (m_handle != rhs.m_handle); + } + + static storeError errorFromNative (oslFileError eErrno) + { + switch (eErrno) + { + case osl_File_E_None: + return store_E_None; + + case osl_File_E_NOENT: + return store_E_NotExists; + + case osl_File_E_ACCES: + case osl_File_E_PERM: + return store_E_AccessViolation; + + case osl_File_E_AGAIN: + case osl_File_E_DEADLK: + return store_E_LockingViolation; + + case osl_File_E_BADF: + return store_E_InvalidHandle; + + case osl_File_E_INVAL: + return store_E_InvalidParameter; + + case osl_File_E_NOMEM: + return store_E_OutOfMemory; + + case osl_File_E_NOSPC: + return store_E_OutOfSpace; + + case osl_File_E_OVERFLOW: + return store_E_CantSeek; + + default: + return store_E_Unknown; + } + } + + static sal_uInt32 modeToNative (storeAccessMode eAccessMode) + { + sal_uInt32 nFlags = 0; + switch (eAccessMode) + { + case store_AccessCreate: + case store_AccessReadCreate: + nFlags |= osl_File_OpenFlag_Create; + // fall through + case store_AccessReadWrite: + nFlags |= osl_File_OpenFlag_Write; + // fall through + case store_AccessReadOnly: + nFlags |= osl_File_OpenFlag_Read; + break; + default: + OSL_PRECOND(0, "store::FileHandle: unknown storeAccessMode"); + } + return nFlags; + } + + storeError initialize (rtl_uString * pFilename, storeAccessMode eAccessMode) + { + // Verify arguments. + sal_uInt32 nFlags = modeToNative (eAccessMode); + if (!pFilename || !nFlags) + return store_E_InvalidParameter; + + // Convert into FileUrl. + rtl::OUString aFileUrl; + if (osl_getFileURLFromSystemPath (pFilename, &(aFileUrl.pData)) != osl_File_E_None) + { + // Not system path. Assume file url. + rtl_uString_assign (&(aFileUrl.pData), pFilename); + } + if (aFileUrl.compareToAscii("file://", 7) != 0) + { + // Not file url. Assume relative path. + rtl::OUString aCwdUrl; + (void) osl_getProcessWorkingDir (&(aCwdUrl.pData)); + + // Absolute file url. + (void) osl_getAbsoluteFileURL (aCwdUrl.pData, aFileUrl.pData, &(aFileUrl.pData)); + } + + // Acquire handle. + oslFileError result = osl_openFile (aFileUrl.pData, &m_handle, nFlags); + if (result == osl_File_E_EXIST) + { + // Already existing (O_CREAT | O_EXCL). + result = osl_openFile (aFileUrl.pData, &m_handle, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + if ((result == osl_File_E_None) && (eAccessMode == store_AccessCreate)) + { + // Truncate existing file. + result = osl_setFileSize (m_handle, 0); + } + } + if (result != osl_File_E_None) + return errorFromNative(result); + return store_E_None; + } + + /** @see FileLockBytes destructor + */ + static void closeFile (oslFileHandle hFile) + { + (void) osl_closeFile (hFile); + } + + /** @see ResourceHolder<T>::destructor_type + */ + struct CloseFile + { + void operator()(FileHandle & rFile) const + { + // Release handle. + closeFile (rFile.m_handle); + rFile.m_handle = 0; + } + }; + typedef CloseFile destructor_type; +}; + +class FileLockBytes : + public store::OStoreObject, + public store::ILockBytes +{ + /** Representation. + */ + oslFileHandle m_hFile; + sal_uInt32 m_nSize; + rtl::Reference< PageData::Allocator > m_xAllocator; + + storeError initSize_Impl (sal_uInt32 & rnSize); + + /** ILockBytes implementation. + */ + virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); + + virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); + virtual storeError writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); + + virtual storeError getSize_Impl (sal_uInt32 & rnSize); + virtual storeError setSize_Impl (sal_uInt32 nSize); + + virtual storeError flush_Impl(); + + /** Not implemented. + */ + FileLockBytes (FileLockBytes const &); + FileLockBytes & operator= (FileLockBytes const &); + +public: + /** Construction. + */ + explicit FileLockBytes (FileHandle & rFile); + + /** Delegate multiple inherited IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + +protected: + /** Destruction. + */ + virtual ~FileLockBytes(); +}; + +} // namespace store + +FileLockBytes::FileLockBytes (FileHandle & rFile) + : m_hFile (rFile.m_handle), m_nSize (SAL_MAX_UINT32), m_xAllocator() +{ +} + +FileLockBytes::~FileLockBytes() +{ + FileHandle::closeFile (m_hFile); +} + +oslInterlockedCount SAL_CALL FileLockBytes::acquire() +{ + return OStoreObject::acquire(); +} + +oslInterlockedCount SAL_CALL FileLockBytes::release() +{ + return OStoreObject::release(); +} + +storeError FileLockBytes::initSize_Impl (sal_uInt32 & rnSize) +{ + /* osl_getFileSize() uses slow 'fstat(h, &size)', + * instead of fast 'size = lseek(h, 0, SEEK_END)'. + * so, init size here, and track changes. + */ + sal_uInt64 uSize = 0; + oslFileError result = osl_getFileSize (m_hFile, &uSize); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + if (uSize > SAL_MAX_UINT32) + return store_E_CantSeek; + + rnSize = sal::static_int_cast<sal_uInt32>(uSize); + return store_E_None; +} + +storeError FileLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + storeError result = initSize_Impl (m_nSize); + if (result != store_E_None) + return (result); + + result = PageData::Allocator::createInstance (rxAllocator, nPageSize); + if (result != store_E_None) + return (result); + + // @see readPageAt_Impl(). + m_xAllocator = rxAllocator; + return store_E_None; +} + +storeError FileLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) +{ + if (m_xAllocator.is()) + { + PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator); + page.swap (rPage); + } + + if (!m_xAllocator.is()) + return store_E_InvalidAccess; + if (!rPage.get()) + return store_E_OutOfMemory; + + PageData * pagedata = rPage.get(); + return readAt_Impl (nOffset, pagedata, pagedata->size()); +} + +storeError FileLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) +{ + PageData const * pagedata = rPage.get(); + OSL_PRECOND(pagedata != 0, "contract violation"); + return writeAt_Impl (nOffset, pagedata, pagedata->size()); +} + +storeError FileLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt64 nDone = 0; + oslFileError result = osl_readFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + if (nDone != nBytes) + return (nDone != 0) ? store_E_CantRead : store_E_NotExists; + return store_E_None; +} + +storeError FileLockBytes::writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt64 nDone = 0; + oslFileError result = osl_writeFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + if (nDone != nBytes) + return store_E_CantWrite; + + sal_uInt64 const uSize = nOffset + nBytes; + OSL_PRECOND(uSize < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation"); + if (uSize > m_nSize) + m_nSize = sal::static_int_cast<sal_uInt32>(uSize); + return store_E_None; +} + +storeError FileLockBytes::getSize_Impl (sal_uInt32 & rnSize) +{ + rnSize = m_nSize; + return store_E_None; +} + +storeError FileLockBytes::setSize_Impl (sal_uInt32 nSize) +{ + oslFileError result = osl_setFileSize (m_hFile, nSize); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + + m_nSize = nSize; + return store_E_None; +} + +storeError FileLockBytes::flush_Impl() +{ + oslFileError result = osl_syncFile (m_hFile); + if (result != osl_File_E_None) + return FileHandle::errorFromNative(result); + return store_E_None; +} + +/*======================================================================== + * + * MappedLockBytes implementation. + * + *======================================================================*/ +namespace store +{ + +struct FileMapping +{ + sal_uInt8 * m_pAddr; + sal_uInt32 m_nSize; + + FileMapping() : m_pAddr(0), m_nSize(0) {} + + bool operator != (FileMapping const & rhs) const + { + return ((m_pAddr != rhs.m_pAddr) || (m_nSize != rhs.m_nSize)); + } + + oslFileError initialize (oslFileHandle hFile) + { + // Determine mapping size. + sal_uInt64 uSize = 0; + oslFileError result = osl_getFileSize (hFile, &uSize); + if (result != osl_File_E_None) + return result; + + // [SECURITY:IntOver] + if (uSize > SAL_MAX_UINT32) + return osl_File_E_OVERFLOW; + m_nSize = sal::static_int_cast<sal_uInt32>(uSize); + + // Acquire mapping. + return osl_mapFile (hFile, reinterpret_cast<void**>(&m_pAddr), m_nSize, 0, osl_File_MapFlag_RandomAccess); + } + + /** @see MappedLockBytes::destructor. + */ + static void unmapFile (sal_uInt8 * pAddr, sal_uInt32 nSize) + { + (void) osl_unmapFile (pAddr, nSize); + } + + /** @see ResourceHolder<T>::destructor_type + */ + struct UnmapFile + { + void operator ()(FileMapping & rMapping) const + { + // Release mapping. + unmapFile (rMapping.m_pAddr, rMapping.m_nSize); + rMapping.m_pAddr = 0, rMapping.m_nSize = 0; + } + }; + typedef UnmapFile destructor_type; +}; + +class MappedLockBytes : + public store::OStoreObject, + public store::PageData::Allocator, + public store::ILockBytes +{ + /** Representation. + */ + sal_uInt8 * m_pData; + sal_uInt32 m_nSize; + sal_uInt16 m_nPageSize; + + /** PageData::Allocator implementation. + */ + virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize); + virtual void deallocate_Impl (void * pPage); + + /** ILockBytes implementation. + */ + virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); + + virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); + virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes); + + virtual storeError getSize_Impl (sal_uInt32 & rnSize); + virtual storeError setSize_Impl (sal_uInt32 nSize); + + virtual storeError flush_Impl(); + + /** Not implemented. + */ + MappedLockBytes (MappedLockBytes const &); + MappedLockBytes & operator= (MappedLockBytes const &); + +public: + /** Construction. + */ + explicit MappedLockBytes (FileMapping & rMapping); + + /** Delegate multiple inherited IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + +protected: + /* Destruction. + */ + virtual ~MappedLockBytes(); +}; + +} // namespace store + +MappedLockBytes::MappedLockBytes (FileMapping & rMapping) + : m_pData (rMapping.m_pAddr), m_nSize (rMapping.m_nSize), m_nPageSize(0) +{ +} + +MappedLockBytes::~MappedLockBytes() +{ + FileMapping::unmapFile (m_pData, m_nSize); +} + +oslInterlockedCount SAL_CALL MappedLockBytes::acquire() +{ + return OStoreObject::acquire(); +} + +oslInterlockedCount SAL_CALL MappedLockBytes::release() +{ + return OStoreObject::release(); +} + +void MappedLockBytes::allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) +{ + OSL_PRECOND((ppPage != 0) && (pnSize != 0), "contract violation"); + *ppPage = 0, *pnSize = m_nPageSize; +} + +void MappedLockBytes::deallocate_Impl (void * pPage) +{ + OSL_PRECOND((m_pData <= pPage) && (pPage < m_pData + m_nSize), "contract violation"); + (void)pPage; // UNUSED +} + +storeError MappedLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + rxAllocator = this; + m_nPageSize = nPageSize; + return store_E_None; +} + +storeError MappedLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) +{ + sal_uInt8 * src_lo = m_pData + nOffset; + if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) + return store_E_NotExists; + + sal_uInt8 * src_hi = src_lo + m_nPageSize; + if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) + return store_E_CantRead; + + PageHolder page (reinterpret_cast< PageData* >(src_lo), static_cast< PageData::Allocator* >(this)); + page.swap (rPage); + + return store_E_None; +} + +storeError MappedLockBytes::writePageAt_Impl (PageHolder const & /*rPage*/, sal_uInt32 /*nOffset*/) +{ + return store_E_AccessViolation; +} + +storeError MappedLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt8 const * src_lo = m_pData + nOffset; + if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) + return store_E_NotExists; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) + return store_E_CantRead; + + memcpy (pBuffer, src_lo, (src_hi - src_lo)); + return store_E_None; +} + +storeError MappedLockBytes::writeAt_Impl (sal_uInt32 /*nOffset*/, void const * /*pBuffer*/, sal_uInt32 /*nBytes*/) +{ + return store_E_AccessViolation; +} + +storeError MappedLockBytes::getSize_Impl (sal_uInt32 & rnSize) +{ + rnSize = m_nSize; + return store_E_None; +} + +storeError MappedLockBytes::setSize_Impl (sal_uInt32 /*nSize*/) +{ + return store_E_AccessViolation; +} + +storeError MappedLockBytes::flush_Impl() +{ + return store_E_None; +} + +/*======================================================================== + * + * MemoryLockBytes implementation. + * + *======================================================================*/ +namespace store +{ + +class MemoryLockBytes : + public store::OStoreObject, + public store::ILockBytes +{ + /** Representation. + */ + sal_uInt8 * m_pData; + sal_uInt32 m_nSize; + rtl::Reference< PageData::Allocator > m_xAllocator; + + /** ILockBytes implementation. + */ + virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); + virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); + + virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); + virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes); + + virtual storeError getSize_Impl (sal_uInt32 & rnSize); + virtual storeError setSize_Impl (sal_uInt32 nSize); + + virtual storeError flush_Impl(); + + /** Not implemented. + */ + MemoryLockBytes (MemoryLockBytes const &); + MemoryLockBytes& operator= (MemoryLockBytes const &); + +public: + /** Construction. + */ + MemoryLockBytes(); + + /** Delegate multiple inherited IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + +protected: + /** Destruction. + */ + virtual ~MemoryLockBytes(); +}; + +} // namespace store + +MemoryLockBytes::MemoryLockBytes() + : m_pData (0), m_nSize (0), m_xAllocator() +{} + +MemoryLockBytes::~MemoryLockBytes() +{ + rtl_freeMemory (m_pData); +} + +oslInterlockedCount SAL_CALL MemoryLockBytes::acquire (void) +{ + return OStoreObject::acquire(); +} + +oslInterlockedCount SAL_CALL MemoryLockBytes::release (void) +{ + return OStoreObject::release(); +} + +storeError MemoryLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + storeError result = PageData::Allocator::createInstance (rxAllocator, nPageSize); + if (result == store_E_None) + { + // @see readPageAt_Impl(). + m_xAllocator = rxAllocator; + } + return result; +} + +storeError MemoryLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) +{ + if (m_xAllocator.is()) + { + PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator); + page.swap (rPage); + } + + if (!m_xAllocator.is()) + return store_E_InvalidAccess; + if (!rPage.get()) + return store_E_OutOfMemory; + + PageData * pagedata = rPage.get(); + return readAt_Impl (nOffset, pagedata, pagedata->size()); +} + +storeError MemoryLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) +{ + PageData const * pagedata = rPage.get(); + OSL_PRECOND(!(pagedata == 0), "contract violation"); + return writeAt_Impl (nOffset, pagedata, pagedata->size()); +} + +storeError MemoryLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt8 const * src_lo = m_pData + nOffset; + if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) + return store_E_NotExists; + + sal_uInt8 const * src_hi = src_lo + nBytes; + if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) + return store_E_CantRead; + + memcpy (pBuffer, src_lo, (src_hi - src_lo)); + return store_E_None; +} + +storeError MemoryLockBytes::writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes) +{ + sal_uInt64 const dst_size = nOffset + nBytes; + OSL_PRECOND(dst_size < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation"); + if (dst_size > m_nSize) + { + storeError eErrCode = setSize_Impl (sal::static_int_cast<sal_uInt32>(dst_size)); + if (eErrCode != store_E_None) + return eErrCode; + } + OSL_POSTCOND(dst_size <= m_nSize, "store::MemoryLockBytes::setSize_Impl() contract violation"); + + sal_uInt8 * dst_lo = m_pData + nOffset; + if (dst_lo >= m_pData + m_nSize) + return store_E_CantSeek; + + sal_uInt8 * dst_hi = dst_lo + nBytes; + if (dst_hi > m_pData + m_nSize) + return store_E_CantWrite; + + memcpy (dst_lo, pBuffer, (dst_hi - dst_lo)); + return store_E_None; +} + +storeError MemoryLockBytes::getSize_Impl (sal_uInt32 & rnSize) +{ + rnSize = m_nSize; + return store_E_None; +} + +storeError MemoryLockBytes::setSize_Impl (sal_uInt32 nSize) +{ + if (nSize != m_nSize) + { + sal_uInt8 * pData = reinterpret_cast<sal_uInt8*>(rtl_reallocateMemory (m_pData, nSize)); + if (pData != 0) + { + if (nSize > m_nSize) + memset (pData + m_nSize, 0, sal::static_int_cast<size_t>(nSize - m_nSize)); + } + else + { + if (nSize != 0) + return store_E_OutOfMemory; + } + m_pData = pData, m_nSize = nSize; + } + return store_E_None; +} + +storeError MemoryLockBytes::flush_Impl() +{ + return store_E_None; +} + +/*======================================================================== + * + * ILockBytes factory implementations. + * + *======================================================================*/ +namespace store +{ + +template< class T > struct ResourceHolder +{ + typedef typename T::destructor_type destructor_type; + + T m_value; + + explicit ResourceHolder (T const & value = T()) : m_value (value) {} + ~ResourceHolder() { reset(); } + + T & get() { return m_value; } + T const & get() const { return m_value; } + + void set (T const & value) { m_value = value; } + void reset (T const & value = T()) + { + T tmp (m_value); + if (tmp != value) + destructor_type()(tmp); + set (value); + } + T release() + { + T tmp (m_value); + set (T()); + return tmp; + } + + ResourceHolder (ResourceHolder & rhs) + { + set (rhs.release()); + } + ResourceHolder & operator= (ResourceHolder & rhs) + { + reset (rhs.release()); + return *this; + } +}; + +storeError +FileLockBytes_createInstance ( + rtl::Reference< ILockBytes > & rxLockBytes, + rtl_uString * pFilename, + storeAccessMode eAccessMode +) +{ + // Acquire file handle. + ResourceHolder<FileHandle> xFile; + storeError result = xFile.get().initialize (pFilename, eAccessMode); + if (result != store_E_None) + return (result); + + if (eAccessMode == store_AccessReadOnly) + { + ResourceHolder<FileMapping> xMapping; + if (xMapping.get().initialize (xFile.get().m_handle) == osl_File_E_None) + { + rxLockBytes = new MappedLockBytes (xMapping.get()); + if (!rxLockBytes.is()) + return store_E_OutOfMemory; + (void) xMapping.release(); + } + } + if (!rxLockBytes.is()) + { + rxLockBytes = new FileLockBytes (xFile.get()); + if (!rxLockBytes.is()) + return store_E_OutOfMemory; + (void) xFile.release(); + } + + return store_E_None; +} + +storeError +MemoryLockBytes_createInstance ( + rtl::Reference< ILockBytes > & rxLockBytes +) +{ + rxLockBytes = new MemoryLockBytes(); + if (!rxLockBytes.is()) + return store_E_OutOfMemory; + + return store_E_None; +} + +} // namespace store diff --git a/store/source/lockbyte.hxx b/store/source/lockbyte.hxx new file mode 100644 index 000000000000..ef34b8708f26 --- /dev/null +++ b/store/source/lockbyte.hxx @@ -0,0 +1,184 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_LOCKBYTE_HXX_ +#define _STORE_LOCKBYTE_HXX_ "$Revision: 1.1.2.1 $" + +#ifndef _SAL_TYPES_H_ +#include "sal/types.h" +#endif + +#ifndef _RTL_REF_HXX_ +#include "rtl/ref.hxx" +#endif +#ifndef _RTL_USTRING_H_ +#include "rtl/ustring.h" +#endif + +#ifndef _STORE_TYPES_H_ +#include "store/types.h" +#endif +#ifndef _STORE_STORBASE_HXX_ +#include "storbase.hxx" +#endif + +namespace store +{ + +/*======================================================================== + * + * ILockBytes interface. + * + *======================================================================*/ +class ILockBytes : public rtl::IReference +{ +public: + /** + @param rxAllocator [out] + @param nPageSize [in] + */ + storeError initialize ( + rtl::Reference< PageData::Allocator > & rxAllocator, + sal_uInt16 nPageSize); + + /** + @param rPage [out] + @param nOffset [in] + */ + storeError readPageAt ( + PageHolder & rPage, + sal_uInt32 nOffset); + + /** + @param rPage [in] + @param nOffset [in] + */ + storeError writePageAt ( + PageHolder const & rPage, + sal_uInt32 nOffset); + + /** + @param nOffset [in] + @param pBuffer [out] + @param nBytes [in] + @return store_E_None upon success + */ + storeError readAt ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes); + + /** + @param nOffset [in] + @param pBuffer [in] + @param nBytes [in] + @return store_E_None upon success + */ + storeError writeAt ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes); + + /** + @param rnSize [out] + @return store_E_None upon success + */ + storeError getSize (sal_uInt32 & rnSize); + + /** + @param nSize [in] + @return store_E_None upon success + */ + storeError setSize (sal_uInt32 nSize); + + /** + @return store_E_None upon success + */ + storeError flush(); + +private: + /** Implementation (abstract). + */ + virtual storeError initialize_Impl ( + rtl::Reference< PageData::Allocator > & rxAllocator, + sal_uInt16 nPageSize) = 0; + + virtual storeError readPageAt_Impl ( + PageHolder & rPage, + sal_uInt32 nOffset) = 0; + + virtual storeError writePageAt_Impl ( + PageHolder const & rPage, + sal_uInt32 nOffset) = 0; + + virtual storeError readAt_Impl ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes) = 0; + + virtual storeError writeAt_Impl ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes) = 0; + + virtual storeError getSize_Impl ( + sal_uInt32 & rnSize) = 0; + + virtual storeError setSize_Impl ( + sal_uInt32 nSize) = 0; + + virtual storeError flush_Impl() = 0; +}; + +/*======================================================================== + * + * ILockBytes factories. + * + *======================================================================*/ + +storeError +FileLockBytes_createInstance ( + rtl::Reference< store::ILockBytes > & rxLockBytes, + rtl_uString * pFilename, + storeAccessMode eAccessMode +); + +storeError +MemoryLockBytes_createInstance ( + rtl::Reference< store::ILockBytes > & rxLockBytes +); + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_LOCKBYTE_HXX_ */ + diff --git a/store/source/makefile.mk b/store/source/makefile.mk new file mode 100644 index 000000000000..c7ae53d97da0 --- /dev/null +++ b/store/source/makefile.mk @@ -0,0 +1,71 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=.. + +PRJNAME=store +TARGET=store + +# --- Settings --- + +.INCLUDE : settings.mk + +# --- Files --- + +SLOFILES= \ + $(SLO)$/object.obj \ + $(SLO)$/lockbyte.obj \ + $(SLO)$/storbase.obj \ + $(SLO)$/storbios.obj \ + $(SLO)$/storcach.obj \ + $(SLO)$/stordata.obj \ + $(SLO)$/stordir.obj \ + $(SLO)$/storlckb.obj \ + $(SLO)$/stortree.obj \ + $(SLO)$/storpage.obj \ + $(SLO)$/store.obj + +.IF "$(debug)" != "" +OBJFILES= \ + $(OBJ)$/object.obj \ + $(OBJ)$/lockbyte.obj \ + $(OBJ)$/storbase.obj \ + $(OBJ)$/storbios.obj \ + $(OBJ)$/storcach.obj \ + $(OBJ)$/stordata.obj \ + $(OBJ)$/stordir.obj \ + $(OBJ)$/storlckb.obj \ + $(OBJ)$/stortree.obj \ + $(OBJ)$/storpage.obj \ + $(OBJ)$/store.obj + +.ENDIF # debug + +# --- Targets --- + +.INCLUDE : target.mk + diff --git a/store/source/object.cxx b/store/source/object.cxx new file mode 100644 index 000000000000..40c1cfbbee9c --- /dev/null +++ b/store/source/object.cxx @@ -0,0 +1,112 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "object.hxx" + +#include "sal/types.h" +#include "rtl/alloc.h" +#include "rtl/ref.hxx" +#include "osl/diagnose.h" +#include "osl/interlck.h" + +namespace store +{ + +/*======================================================================== + * + * OStoreObject implementation. + * + *======================================================================*/ +const sal_uInt32 OStoreObject::m_nTypeId = sal_uInt32(0x58190322); + +/* + * OStoreObject. + */ +OStoreObject::OStoreObject (void) + : m_nRefCount (0) +{ +} + +/* + * ~OStoreObject. + */ +OStoreObject::~OStoreObject (void) +{ + OSL_ASSERT(m_nRefCount == 0); +} + +/* + * operator new. + */ +void* OStoreObject::operator new (size_t n) +{ + return rtl_allocateMemory (n); +} + +/* + * operator delete. + */ +void OStoreObject::operator delete (void *p, size_t) +{ + rtl_freeMemory (p); +} + +/* + * isKindOf. + */ +sal_Bool SAL_CALL OStoreObject::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == m_nTypeId); +} + +/* + * acquire. + */ +oslInterlockedCount SAL_CALL OStoreObject::acquire (void) +{ + oslInterlockedCount result = osl_incrementInterlockedCount (&m_nRefCount); + return (result); +} + +/* + * release. + */ +oslInterlockedCount SAL_CALL OStoreObject::release (void) +{ + oslInterlockedCount result = osl_decrementInterlockedCount (&m_nRefCount); + if (result == 0) + { + // Last reference released. + delete this; + } + return (result); +} + +} // namespace store diff --git a/store/source/object.hxx b/store/source/object.hxx new file mode 100644 index 000000000000..1061b9c568a9 --- /dev/null +++ b/store/source/object.hxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_OBJECT_HXX_ +#define _STORE_OBJECT_HXX_ "$Revision: 1.1.2.1 $" + +#ifndef _SAL_TYPES_H_ +#include "sal/types.h" +#endif + +#ifndef _RTL_REF_HXX_ +#include "rtl/ref.hxx" +#endif + +#ifndef _OSL_INTERLCK_H_ +#include "osl/interlck.h" +#endif + +namespace store +{ + +/*======================================================================== + * + * IStoreHandle interface. + * + *======================================================================*/ +class IStoreHandle : public rtl::IReference +{ +public: + /** Replaces dynamic_cast type checking. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId) = 0; +}; + + +/** Template helper function as dynamic_cast replacement. + */ +template<class store_handle_type> +store_handle_type * SAL_CALL query ( + IStoreHandle * pHandle, store_handle_type *); + +/*======================================================================== + * + * OStoreObject interface. + * + *======================================================================*/ +class OStoreObject : public store::IStoreHandle +{ + /** Template function specialization as dynamic_cast replacement. + */ + friend OStoreObject* + SAL_CALL query<> (IStoreHandle *pHandle, OStoreObject*); + +public: + /** Construction. + */ + OStoreObject (void); + + /** Allocation. + */ + static void* operator new (size_t n); + static void operator delete (void *p, size_t); + + /** IStoreHandle. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId); + + /** IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire (void); + virtual oslInterlockedCount SAL_CALL release (void); + +protected: + /** Destruction. + */ + virtual ~OStoreObject (void); + +private: + /** The IStoreHandle TypeId. + */ + static const sal_uInt32 m_nTypeId; + + /** Representation. + */ + oslInterlockedCount m_nRefCount; + + /** Not implemented. + */ + OStoreObject (const OStoreObject&); + OStoreObject& operator= (const OStoreObject&); +}; + +/** Template function specialization as dynamic_cast replacement. + */ +template<> inline OStoreObject* +SAL_CALL query (IStoreHandle *pHandle, OStoreObject*) +{ + if (pHandle && pHandle->isKindOf (OStoreObject::m_nTypeId)) + { + // Handle is kind of OStoreObject. + return static_cast<OStoreObject*>(pHandle); + } + return 0; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_OBJECT_HXX_ */ diff --git a/store/source/storbase.cxx b/store/source/storbase.cxx new file mode 100644 index 000000000000..6eb005e453d8 --- /dev/null +++ b/store/source/storbase.cxx @@ -0,0 +1,197 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storbase.hxx" + +#include "sal/types.h" +#include "rtl/alloc.h" +#include "rtl/ref.hxx" +#include "osl/diagnose.h" + +#include "store/types.h" +#include "object.hxx" + +#ifndef INCLUDED_STDIO_H +#include <stdio.h> +#define INCLUDED_STDIO_H +#endif + +using namespace store; + +/*======================================================================== + * + * SharedCount::Allocator. + * + *======================================================================*/ +SharedCount::Allocator & +SharedCount::Allocator::get() +{ + static Allocator g_aSharedCountAllocator; + return g_aSharedCountAllocator; +} + +SharedCount::Allocator::Allocator() +{ + m_cache = rtl_cache_create ( + "store_shared_count_cache", + sizeof(long), + 0, // objalign + 0, // constructor + 0, // destructor + 0, // reclaim + 0, // userarg + 0, // default source + 0 // flags + ); +} + +SharedCount::Allocator::~Allocator() +{ + rtl_cache_destroy (m_cache), m_cache = 0; +} + +/*======================================================================== + * + * PageData::Allocator_Impl (default allocator). + * + *======================================================================*/ +namespace store +{ + +class PageData::Allocator_Impl : + public store::OStoreObject, + public store::PageData::Allocator +{ +public: + /** Construction (two phase). + */ + Allocator_Impl(); + + storeError initialize (sal_uInt16 nPageSize); + + /** Delegate multiple inherited rtl::IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire() + { + return OStoreObject::acquire(); + } + virtual oslInterlockedCount SAL_CALL release() + { + return OStoreObject::release(); + } + +protected: + /** Destruction. + */ + virtual ~Allocator_Impl(); + +private: + /** Representation. + */ + rtl_cache_type * m_page_cache; + sal_uInt16 m_page_size; + + /** PageData::Allocator implementation. + */ + virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize); + virtual void deallocate_Impl (void * pPage); + + /** Not implemented. + */ + Allocator_Impl (Allocator_Impl const &); + Allocator_Impl & operator= (Allocator_Impl const &); +}; + +} // namespace store + +PageData::Allocator_Impl::Allocator_Impl() + : m_page_cache(0), m_page_size(0) +{} + +storeError +PageData::Allocator_Impl::initialize (sal_uInt16 nPageSize) +{ + char name[RTL_CACHE_NAME_LENGTH + 1]; + sal_Size size = sal::static_int_cast< sal_Size >(nPageSize); + (void) snprintf (name, sizeof(name), "store_page_alloc_%lu", size); + + m_page_cache = rtl_cache_create (name, size, 0, 0, 0, 0, 0, 0, 0); + if (!m_page_cache) + return store_E_OutOfMemory; + + m_page_size = nPageSize; + return store_E_None; +} + +PageData::Allocator_Impl::~Allocator_Impl() +{ + rtl_cache_destroy(m_page_cache), m_page_cache = 0; +} + +void PageData::Allocator_Impl::allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) +{ + OSL_PRECOND((ppPage != 0) && (pnSize != 0), "contract violation"); + *ppPage = rtl_cache_alloc(m_page_cache), *pnSize = m_page_size; +} + +void PageData::Allocator_Impl::deallocate_Impl (void * pPage) +{ + OSL_PRECOND(pPage != 0, "contract violation"); + rtl_cache_free(m_page_cache, pPage); +} + +/*======================================================================== + * + * PageData::Allocator factory. + * + *======================================================================*/ + +storeError +PageData::Allocator::createInstance (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) +{ + rtl::Reference< PageData::Allocator_Impl > xAllocator (new PageData::Allocator_Impl()); + if (!xAllocator.is()) + return store_E_OutOfMemory; + + rxAllocator = &*xAllocator; + return xAllocator->initialize (nPageSize); +} + +/*======================================================================== + * + * OStorePageObject. + * + *======================================================================*/ +/* + * ~OStorePageObject. + */ +OStorePageObject::~OStorePageObject (void) +{ +} diff --git a/store/source/storbase.hxx b/store/source/storbase.hxx new file mode 100644 index 000000000000..9c1e4ea985bf --- /dev/null +++ b/store/source/storbase.hxx @@ -0,0 +1,954 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORBASE_HXX_ +#define _STORE_STORBASE_HXX_ "$Revision: 1.10.8.4 $" + +#include "sal/types.h" + +#include "rtl/alloc.h" +#include "rtl/crc.h" +#include "rtl/ref.hxx" + +#include "osl/diagnose.h" +#include "osl/endian.h" + +#include "store/types.h" + +#ifndef INCLUDED_STDDEF_H +#include <stddef.h> +#define INCLUDED_STDDEF_H +#endif + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif + +/*======================================================================== + * + * store common internals. + * + *======================================================================*/ + +#ifndef STORE_IMPL_ISP2 +#define STORE_IMPL_ISP2(value) (((value) & ((value) - 1)) == 0) +#endif + +#ifndef STORE_IMPL_CONCAT +#define STORE_IMPL_CONCAT(x, y) STORE_IMPL_CONCAT2(x,y) +#define STORE_IMPL_CONCAT2(x, y) x##y +#endif + +#ifndef STORE_STATIC_ASSERT /* Compile time assertion */ +namespace store +{ + template< bool x > struct STATIC_ASSERTION_FAILURE; + template<> struct STATIC_ASSERTION_FAILURE< true > { enum { value = 1 }; }; + + template< int x > struct static_assert_test{}; +} // namespace store + +#define STORE_STATIC_ASSERT(pred) \ +typedef \ +store::static_assert_test< sizeof( store::STATIC_ASSERTION_FAILURE< (bool)(pred) > ) > \ +STORE_IMPL_CONCAT(static_assert_typedef_, __LINE__) + +#endif /* !STORE_STATIC_ASSERT */ + +namespace store +{ + +#ifdef htons +#undef htons +#endif +#ifdef ntohs +#undef ntohs +#endif + +#ifdef htonl +#undef htonl +#endif +#ifdef ntohl +#undef ntohl +#endif + +#ifdef OSL_BIGENDIAN +inline sal_uInt16 htons (sal_uInt16 h) { return OSL_SWAPWORD(h); } +inline sal_uInt16 ntohs (sal_uInt16 n) { return OSL_SWAPWORD(n); } + +inline sal_uInt32 htonl (sal_uInt32 h) { return OSL_SWAPDWORD(h); } +inline sal_uInt32 ntohl (sal_uInt32 n) { return OSL_SWAPDWORD(n); } +#else +inline sal_uInt16 htons (sal_uInt16 h) { return (h); } +inline sal_uInt16 ntohs (sal_uInt16 n) { return (n); } + +inline sal_uInt32 htonl (sal_uInt32 h) { return (h); } +inline sal_uInt32 ntohl (sal_uInt32 n) { return (n); } +#endif /* OSL_BIGENDIAN */ + +/** swap. + */ +template< typename T > void swap (T & lhs, T & rhs) +{ + T tmp = lhs; lhs = rhs; rhs = tmp; +} + +/*======================================================================== + * + * SharedCount. + * + *======================================================================*/ +class SharedCount +{ + long * m_pCount; + + class Allocator + { + rtl_cache_type * m_cache; + + public: + static Allocator & get(); + + long * alloc() + { + return static_cast<long*>(rtl_cache_alloc (m_cache)); + } + void free (long * pCount) + { + rtl_cache_free (m_cache, pCount); + } + + protected: + Allocator(); + ~Allocator(); + }; + +public: + SharedCount() + : m_pCount(Allocator::get().alloc()) + { + if (m_pCount != 0) (*m_pCount) = 1; + } + + ~SharedCount() + { + if (m_pCount != 0) + { + long new_count = --(*m_pCount); + if (new_count == 0) + Allocator::get().free(m_pCount); + } + } + + void swap (SharedCount & rhs) // nothrow + { + store::swap(m_pCount, rhs.m_pCount); + } + + SharedCount (SharedCount const & rhs) // nothrow + : m_pCount (rhs.m_pCount) + { + if (m_pCount != 0) ++(*m_pCount); + } + SharedCount & operator= (SharedCount const & rhs) // nothrow + { + SharedCount tmp(rhs); + swap(tmp); + return *this; + } + + bool operator== (long count) const + { + return (m_pCount != 0) ? *m_pCount == count : false; + } +}; + +/*======================================================================== + * + * OStorePageGuard. + * + *======================================================================*/ +struct OStorePageGuard +{ + /** Representation. + */ + sal_uInt32 m_nMagic; + sal_uInt32 m_nCRC32; + + /** Construction. + */ + explicit OStorePageGuard (sal_uInt32 nMagic = 0, sal_uInt32 nCRC32 = 0) + : m_nMagic (store::htonl(nMagic)), + m_nCRC32 (store::htonl(nCRC32)) + {} + + void swap (OStorePageGuard & rhs) + { + store::swap(m_nMagic, rhs.m_nMagic); + store::swap(m_nCRC32, rhs.m_nCRC32); + } + + OStorePageGuard (OStorePageGuard const & rhs) + : m_nMagic (rhs.m_nMagic), + m_nCRC32 (rhs.m_nCRC32) + {} + + OStorePageGuard& operator= (const OStorePageGuard& rhs) + { + m_nMagic = rhs.m_nMagic; + m_nCRC32 = rhs.m_nCRC32; + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageGuard& rhs) const + { + return ((m_nMagic == rhs.m_nMagic) && + (m_nCRC32 == rhs.m_nCRC32) ); + } +}; + +/*======================================================================== + * + * OStorePageDescriptor. + * + *======================================================================*/ +#define STORE_PAGE_NULL ((sal_uInt32)(~0)) + +struct OStorePageDescriptor +{ + /** Representation. + */ + sal_uInt32 m_nAddr; + sal_uInt16 m_nSize; + sal_uInt16 m_nUsed; + + /** Construction. + */ + explicit OStorePageDescriptor ( + sal_uInt32 nAddr = STORE_PAGE_NULL, + sal_uInt16 nSize = 0, + sal_uInt16 nUsed = 0) + : m_nAddr (store::htonl(nAddr)), + m_nSize (store::htons(nSize)), + m_nUsed (store::htons(nUsed)) + {} + + void swap (OStorePageDescriptor & rhs) + { + store::swap(m_nAddr, rhs.m_nAddr); + store::swap(m_nSize, rhs.m_nSize); + store::swap(m_nUsed, rhs.m_nUsed); + } + + OStorePageDescriptor (const OStorePageDescriptor & rhs) + : m_nAddr (rhs.m_nAddr), + m_nSize (rhs.m_nSize), + m_nUsed (rhs.m_nUsed) + {} + + OStorePageDescriptor & operator= (const OStorePageDescriptor & rhs) + { + m_nAddr = rhs.m_nAddr; + m_nSize = rhs.m_nSize; + m_nUsed = rhs.m_nUsed; + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageDescriptor & rhs) const + { + return ((m_nAddr == rhs.m_nAddr) && + (m_nSize == rhs.m_nSize) ); + } + + bool operator<= (const OStorePageDescriptor & rhs) const + { + return ((m_nAddr == rhs.m_nAddr ) && + (store::ntohs(m_nSize) <= store::ntohs(rhs.m_nSize)) ); + } + + bool operator< (const OStorePageDescriptor & rhs) const + { + if (m_nAddr == rhs.m_nAddr) + return (store::ntohs(m_nSize) < store::ntohs(rhs.m_nSize)); + else + return (store::ntohl(m_nAddr) < store::ntohl(rhs.m_nAddr)); + } +}; + +/*======================================================================== + * + * OStorePageKey. + * + *======================================================================*/ +struct OStorePageKey +{ + /** Representation. + */ + sal_uInt32 m_nLow; + sal_uInt32 m_nHigh; + + /** Construction. + */ + explicit OStorePageKey (sal_uInt32 nLow = 0, sal_uInt32 nHigh = 0) + : m_nLow (store::htonl(nLow)), + m_nHigh (store::htonl(nHigh)) + {} + + void swap (OStorePageKey & rhs) + { + store::swap(m_nLow, rhs.m_nLow); + store::swap(m_nHigh, rhs.m_nHigh); + } + + OStorePageKey (const OStorePageKey & rhs) + : m_nLow (rhs.m_nLow), m_nHigh (rhs.m_nHigh) + {} + + OStorePageKey & operator= (const OStorePageKey & rhs) + { + m_nLow = rhs.m_nLow; + m_nHigh = rhs.m_nHigh; + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageKey & rhs) const + { + return ((m_nLow == rhs.m_nLow ) && + (m_nHigh == rhs.m_nHigh) ); + } + + bool operator< (const OStorePageKey & rhs) const + { + if (m_nHigh == rhs.m_nHigh) + return (store::ntohl(m_nLow) < store::ntohl(rhs.m_nLow)); + else + return (store::ntohl(m_nHigh) < store::ntohl(rhs.m_nHigh)); + } +}; + +/*======================================================================== + * + * OStorePageLink. + * + *======================================================================*/ +struct OStorePageLink +{ + /** Representation. + */ + sal_uInt32 m_nAddr; + + /** Construction. + */ + explicit OStorePageLink (sal_uInt32 nAddr = STORE_PAGE_NULL) + : m_nAddr (store::htonl(nAddr)) + {} + + void swap (OStorePageLink & rhs) + { + store::swap(m_nAddr, rhs.m_nAddr); + } + + OStorePageLink (const OStorePageLink & rhs) + : m_nAddr (rhs.m_nAddr) + {} + + OStorePageLink & operator= (const OStorePageLink & rhs) + { + m_nAddr = rhs.m_nAddr; + return *this; + } + + OStorePageLink & operator= (sal_uInt32 nAddr) + { + m_nAddr = store::htonl(nAddr); + return *this; + } + + /** Comparison. + */ + bool operator== (const OStorePageLink & rhs) const + { + return (m_nAddr == rhs.m_nAddr); + } + + bool operator< (const OStorePageLink& rhs) const + { + return (store::ntohl(m_nAddr) < store::ntohl(rhs.m_nAddr)); + } + + /** Operation. + */ + sal_uInt32 location() const + { + return store::ntohl(m_nAddr); + } + + void link (OStorePageLink & rPred) + { + // @@@ swap (rPred); @@@ + OStorePageLink tmp (rPred); + rPred = *this; + *this = tmp; + } + + void unlink (OStorePageLink& rPred) + { + rPred = *this; + *this = OStorePageLink(); + } +}; + +/*======================================================================== + * + * PageData. + * + *======================================================================*/ +typedef struct PageData OStorePageData; // backward compat. +struct PageData +{ + typedef OStorePageGuard G; + typedef OStorePageDescriptor D; + typedef OStorePageLink L; + + /** Representation. + */ + G m_aGuard; + D m_aDescr; + L m_aMarked; + L m_aUnused; + + /** theSize. + */ + static const size_t theSize = sizeof(G) + sizeof(D) + 2 * sizeof(L); + static const sal_uInt16 thePageSize = theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize); + + /** location. + */ + sal_uInt32 location() const + { + return store::ntohl(m_aDescr.m_nAddr); + } + void location (sal_uInt32 nAddr) + { + m_aDescr.m_nAddr = store::htonl(nAddr); + } + + /** size. + */ + sal_uInt16 size() const + { + return store::ntohs(m_aDescr.m_nSize); + } + + /** type. + */ + sal_uInt32 type() const + { + return store::ntohl(m_aGuard.m_nMagic); + } + + /** Allocation. + */ + class Allocator_Impl; + class Allocator : public rtl::IReference + { + public: + template< class T > T * construct() + { + void * page = 0; sal_uInt16 size = 0; + if (allocate (&page, &size)) + { + return new(page) T(size); + } + return 0; + } + + bool allocate (void ** ppPage, sal_uInt16 * pnSize) + { + allocate_Impl (ppPage, pnSize); + return ((*ppPage != 0) && (*pnSize != 0)); + } + + void deallocate (void * pPage) + { + if (pPage != 0) + deallocate_Impl (pPage); + } + + static storeError createInstance ( + rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); + + private: + /** Implementation (abstract). + */ + virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) = 0; + virtual void deallocate_Impl (void * pPage) = 0; + }; + + static void* operator new (size_t, void * p) { return p; } + static void operator delete (void * , void *) {} + + /** Construction. + */ + explicit PageData (sal_uInt16 nPageSize = thePageSize) + : m_aGuard(), + m_aDescr(STORE_PAGE_NULL, nPageSize, thePageSize), + m_aMarked(), + m_aUnused() + {} + + void swap (PageData & rhs) // nothrow + { + m_aGuard.swap(rhs.m_aGuard); + m_aDescr.swap(rhs.m_aDescr); + m_aMarked.swap(rhs.m_aMarked); + m_aUnused.swap(rhs.m_aUnused); + } + + PageData (PageData const & rhs) // nothrow + : m_aGuard (rhs.m_aGuard), + m_aDescr (rhs.m_aDescr), + m_aMarked(rhs.m_aMarked), + m_aUnused(rhs.m_aUnused) + {} + + PageData & operator= (PageData const & rhs) // nothrow + { + PageData tmp (rhs); + swap (tmp); + return *this; + } + + /** guard (external representation). + */ + void guard (sal_uInt32 nAddr) + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + m_aDescr.m_nAddr = store::htonl(nAddr); + nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify (sal_uInt32 nAddr) const + { + 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; + if (m_aDescr.m_nAddr != store::htonl(nAddr)) + return store_E_InvalidAccess; + return store_E_None; + } + + storeError verifyVersion (sal_uInt32 nMagic) const + { + if (m_aGuard.m_nMagic != store::htonl(nMagic)) + return store_E_WrongVersion; + else + return store_E_None; + } +}; + +/*======================================================================== + * + * PageHolder. + * + *======================================================================*/ +class PageHolder +{ + SharedCount m_refcount; + PageData * m_pagedata; + + typedef rtl::Reference< PageData::Allocator > allocator_type; + allocator_type m_allocator; + +public: + explicit PageHolder (PageData * pagedata = 0, allocator_type const & allocator = allocator_type()) + : m_refcount (), + m_pagedata (pagedata), + m_allocator(allocator) + { + OSL_ENSURE((m_pagedata == 0) || m_allocator.is(), "store::PageHolder::ctor(): pagedata w/o allocator."); + } + + ~PageHolder() + { + if ((m_refcount == 1) && (m_pagedata != 0)) + { + // free pagedata. + OSL_ENSURE(m_allocator.is(), "store::PageHolder::dtor(): pagedata w/o allocator."); + m_allocator->deallocate (m_pagedata); + } + } + + void swap (PageHolder & rhs) // nothrow + { + m_refcount.swap(rhs.m_refcount); + store::swap(m_pagedata, rhs.m_pagedata); + store::swap(m_allocator, rhs.m_allocator); + } + + PageHolder (PageHolder const & rhs) // nothrow + : m_refcount (rhs.m_refcount), + m_pagedata (rhs.m_pagedata), + m_allocator(rhs.m_allocator) + {} + + PageHolder & operator= (PageHolder const & rhs) // nothrow + { + PageHolder tmp (rhs); + swap(tmp); + return *this; + } + + PageData * get() { return m_pagedata; } + PageData const * get() const { return m_pagedata; } + + PageData * operator->() + { + OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator->(): Null pointer"); + return m_pagedata; + } + PageData const * operator->() const + { + OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator->(): Null pointer"); + return m_pagedata; + } + + PageData & operator*() + { + OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator*(): Null pointer"); + return *m_pagedata; + } + PageData const & operator*() const + { + OSL_PRECOND(m_pagedata != 0, "store::PageHolder::operator*(): Null pointer"); + return *m_pagedata; + } +}; + +/*======================================================================== + * + * PageHolderObject. + * + *======================================================================*/ +template< class T > +class PageHolderObject +{ + /** Representation. + */ + PageHolder m_xPage; + + /** Checked cast. + */ + template< class U > + static bool isA (PageData const * p) + { + return ((p != 0) && (p->type() == U::theTypeId)); + } + + template< class U > + static U * dynamic_page_cast (PageData * p) + { + return isA<U>(p) ? static_cast<U*>(p) : 0; + } + + template< class U > + static U const * dynamic_page_cast (PageData const * p) + { + return isA<U>(p) ? static_cast<U const *>(p) : 0; + } + +public: + bool construct (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + if ((m_xPage.get() == 0) && rxAllocator.is()) + { + PageHolder tmp (rxAllocator->construct<T>(), rxAllocator); + m_xPage.swap (tmp); + } + return (m_xPage.get() != 0); + } + + static PageHolderObject<T> createInstance (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + PageHolderObject<T> tmp; + (void) tmp.construct (rxAllocator); + return tmp; + } + + explicit PageHolderObject (PageHolder const & rxPage = PageHolder()) + : m_xPage (rxPage) + {} + + void swap (PageHolderObject<T> & rhs) + { + m_xPage.swap (rhs.m_xPage); + } + + PageHolderObject (PageHolderObject<T> const & rhs) + : m_xPage (rhs.m_xPage) + {} + + PageHolderObject<T> & operator= (PageHolderObject<T> const & rhs) + { + PageHolderObject<T> tmp (rhs); + this->swap (tmp); + return *this; + } + + bool is() const + { + return (m_xPage.get() != 0); + } + +#if 1 /* EXP */ + PageHolder & get() { return m_xPage; } + PageHolder const & get() const { return m_xPage; } +#endif /* EXP */ + + T * operator->() + { + T * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return pImpl; + } + T const * operator->() const + { + T const * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return pImpl; + } + + T & operator*() + { + T * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return (*pImpl); + } + T const & operator*() const + { + T const * pImpl = dynamic_page_cast<T>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer"); + return (*pImpl); + } + + static storeError guard (PageHolder & rxPage, sal_uInt32 nAddr) + { + PageData * pHead = rxPage.get(); + if (!pHead) + return store_E_InvalidAccess; + pHead->guard(nAddr); + + T * pImpl = dynamic_page_cast<T>(pHead); + OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::guard(): Null pointer"); + pImpl->guard(); + + return store_E_None; + } + static storeError verify (PageHolder const & rxPage, sal_uInt32 nAddr) + { + PageData const * pHead = rxPage.get(); + if (!pHead) + return store_E_InvalidAccess; + + storeError eErrCode = pHead->verify(nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + T const * pImpl = dynamic_page_cast<T>(pHead); + if (!pImpl) + return store_E_WrongVersion; + + return pImpl->verify(); + } +}; + +/*======================================================================== + * + * PageObject. + * + *======================================================================*/ +#if 1 /* EXP */ +class PageObject +{ +public: + explicit PageObject (PageHolder const & rxPage = PageHolder()) + : m_xPage (rxPage), m_bDirty (false) + {} + + virtual ~PageObject() + {} + + PageHolder & get() { return m_xPage; } + PageHolder const & get() const { return m_xPage; } + + void clean() { m_bDirty = false; } + void touch() { m_bDirty = true; } + + sal_uInt32 location() const + { + PageData const * pagedata = m_xPage.get(); + return (pagedata != 0) ? pagedata->location() : STORE_PAGE_NULL; + } + void location (sal_uInt32 nAddr) + { + PageData * pagedata = m_xPage.get(); + if (pagedata != 0) + pagedata->location (nAddr); + } + +protected: + PageHolder m_xPage; + bool m_bDirty; + + virtual storeError guard (sal_uInt32 nAddr) = 0; + virtual storeError verify (sal_uInt32 nAddr) const = 0; +}; +#endif /* EXP */ + +class OStorePageBIOS; + +class OStorePageObject +{ + typedef OStorePageData page; + +public: + /** Allocation. + */ + static void * operator new (size_t n) SAL_THROW(()) + { + return rtl_allocateMemory (sal_uInt32(n)); + } + static void operator delete (void * p, size_t) SAL_THROW(()) + { + rtl_freeMemory (p); + } + + /** State. + */ + inline bool dirty (void) const; + inline void clean (void); + inline void touch (void); + + /** Location. + */ + inline sal_uInt32 location (void) const; + inline void location (sal_uInt32 nAddr); + +protected: + /** Representation. + */ + PageHolder m_xPage; + bool m_bDirty; + + /** Construction. + */ + explicit OStorePageObject (PageHolder const & rxPage = PageHolder()) + : m_xPage (rxPage), m_bDirty (false) + {} + + /** Destruction. + */ + virtual ~OStorePageObject (void); + +public: + template< class U > + PageHolderObject<U> makeHolder() const + { + return PageHolderObject<U>(m_xPage); + } + + template< class U > + storeError construct (rtl::Reference< PageData::Allocator > const & rxAllocator) + { + if (!rxAllocator.is()) + return store_E_InvalidAccess; + + PageHolder tmp (rxAllocator->construct<U>(), rxAllocator); + if (!tmp.get()) + return store_E_OutOfMemory; + + m_xPage.swap (tmp); + return store_E_None; + } + + + PageHolder & get() { return m_xPage; } + PageHolder const & get() const { return m_xPage; } + + virtual storeError guard (sal_uInt32 nAddr) = 0; + virtual storeError verify (sal_uInt32 nAddr) const = 0; +}; + +inline bool OStorePageObject::dirty (void) const +{ + return m_bDirty; +} + +inline void OStorePageObject::clean (void) +{ + m_bDirty = false; +} + +inline void OStorePageObject::touch (void) +{ + m_bDirty = true; +} + +inline sal_uInt32 OStorePageObject::location (void) const +{ + return m_xPage->location(); +} + +inline void OStorePageObject::location (sal_uInt32 nAddr) +{ + m_xPage->location(nAddr); + touch(); +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORBASE_HXX_ */ diff --git a/store/source/storbios.cxx b/store/source/storbios.cxx new file mode 100644 index 000000000000..d2612d60b3db --- /dev/null +++ b/store/source/storbios.cxx @@ -0,0 +1,1129 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// 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 & 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, 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 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.\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_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\n", 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, 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; + + // 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; +} diff --git a/store/source/storbios.hxx b/store/source/storbios.hxx new file mode 100644 index 000000000000..439089d41bd6 --- /dev/null +++ b/store/source/storbios.hxx @@ -0,0 +1,267 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORBIOS_HXX_ +#define _STORE_STORBIOS_HXX_ + +#include "sal/types.h" +#include "rtl/ref.hxx" +#include "osl/mutex.hxx" + +#include "store/types.h" +#include "object.hxx" +#include "lockbyte.hxx" +#include "storbase.hxx" +#include "storcach.hxx" + +/*======================================================================== + * + * OStorePageBIOS. + * + *======================================================================*/ +namespace store +{ + +struct SuperBlockPage; + +class OStorePageBIOS : public store::OStoreObject +{ +public: + /** Construction. + */ + OStorePageBIOS (void); + + /** Conversion into Mutex& + */ + inline operator osl::Mutex& (void) const; + + /** Initialization. + * @param pLockBytes [in] + * @param eAccessMode [in] + * @param rnPageSize [inout] + * @return store_E_None upon success + */ + virtual storeError initialize ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize); + + rtl::Reference< PageData::Allocator > & allocator() + { + return m_xAllocator; + } + + /** read. + */ + storeError read ( + sal_uInt32 nAddr, void *pData, sal_uInt32 nSize); + + /** write. + */ + storeError write ( + sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize); + + /** isWriteable. + */ + inline bool isWriteable (void) const; + + /** isValid. + */ + inline sal_Bool isValid (void) const; + + /** Page Access. + */ + storeError acquirePage ( + const OStorePageDescriptor& rDescr, storeAccessMode eMode); + + storeError releasePage ( + const OStorePageDescriptor& rDescr, storeAccessMode eMode); + + sal_uInt32 getRefererCount (void); + + /** Page Allocation. + */ + enum Allocation + { + ALLOCATE_FIRST = 0, + ALLOCATE_BEST = 1, + ALLOCATE_EOF = 2 + }; + + storeError allocate ( + OStorePageObject& rPage, Allocation eAllocation = ALLOCATE_FIRST); + + storeError free (sal_uInt32 nAddr); + + /** Page I/O. + */ + storeError loadObjectAt ( + OStorePageObject& rPage, sal_uInt32 nAddr); + + storeError saveObjectAt ( + OStorePageObject& rPage, sal_uInt32 nAddr); + + /** close. + * @return store_E_None upon success. + */ + storeError close (void); + + /** flush. + * @return store_E_None upon success. + */ + storeError flush (void); + + /** size. + */ + storeError size (sal_uInt32 &rnSize); + + /** ScanContext. + */ + struct ScanContext + { + /** Representation. + */ + OStorePageDescriptor m_aDescr; + sal_uInt32 m_nSize; + sal_uInt32 m_nMagic; + + /** Construction. + */ + inline ScanContext (void); + + /** isValid. + */ + inline bool isValid (void) const; + }; + + /** scanBegin. + */ + storeError scanBegin ( + ScanContext &rCtx, + sal_uInt32 nMagic = 0); + + /** scanNext. + */ + storeError scanNext ( + ScanContext &rCtx, + OStorePageObject &rPage); + +protected: + /** Destruction (OReference). + */ + virtual ~OStorePageBIOS (void); + +private: + /** Representation. + */ + rtl::Reference<ILockBytes> m_xLockBytes; + osl::Mutex m_aMutex; + + SuperBlockPage * m_pSuper; + + bool m_bWriteable; + + rtl::Reference< PageData::Allocator > m_xAllocator; + rtl::Reference< PageCache > m_xCache; + + /** Page Access (control). + */ +public: + struct Ace + { + Ace * m_next; + Ace * m_prev; + + sal_uInt32 m_addr; + sal_uInt32 m_used; + + Ace(); + ~Ace(); + + static int SAL_CALL constructor (void * obj, void * arg); + + static Ace * find (Ace * head, sal_uInt32 addr); + static void insert (Ace * head, Ace * entry); + }; + +private: + Ace m_ace_head; + + class AceCache; + + /** Initialization. + */ + storeError initialize_Impl ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize); + void cleanup_Impl(); + + /** Page Maintenance. + */ + storeError loadObjectAt_Impl ( + OStorePageObject & rPage, sal_uInt32 nAddr); + storeError saveObjectAt_Impl ( + OStorePageObject & rPage, sal_uInt32 nAddr); + + /** Not implemented. + */ + OStorePageBIOS (const OStorePageBIOS&); + OStorePageBIOS& operator= (const OStorePageBIOS&); +}; + +inline OStorePageBIOS::operator osl::Mutex& (void) const +{ + return (osl::Mutex&)m_aMutex; +} +inline bool OStorePageBIOS::isWriteable (void) const +{ + return m_bWriteable; +} +inline sal_Bool OStorePageBIOS::isValid (void) const +{ + return m_xLockBytes.is(); +} + +inline OStorePageBIOS::ScanContext::ScanContext (void) + : m_aDescr (0, 0, 0), m_nSize (0), m_nMagic (0) +{ +} +inline bool OStorePageBIOS::ScanContext::isValid (void) const +{ + return (m_aDescr.m_nAddr < m_nSize); +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORBIOS_HXX_ */ diff --git a/store/source/storcach.cxx b/store/source/storcach.cxx new file mode 100644 index 000000000000..f0e216575277 --- /dev/null +++ b/store/source/storcach.cxx @@ -0,0 +1,561 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storcach.hxx" + +#include "sal/types.h" +#include "rtl/alloc.h" +#include "osl/diagnose.h" + +#include "store/types.h" +#include "object.hxx" +#include "storbase.hxx" + +#ifndef INCLUDED_STDDEF_H +#include <stddef.h> +#define INCLUDED_STDDEF_H +#endif + +using namespace store; + +/*======================================================================== + * + * PageCache (non-virtual interface) implementation. + * + *======================================================================*/ + +storeError PageCache::lookupPageAt (PageHolder & rxPage, sal_uInt32 nOffset) +{ + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::lookupPageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return lookupPageAt_Impl (rxPage, nOffset); +} + +storeError PageCache::insertPageAt (PageHolder const & rxPage, sal_uInt32 nOffset) +{ + // [SECURITY:ValInput] + PageData const * pagedata = rxPage.get(); + OSL_PRECOND(!(pagedata == 0), "store::PageCache::insertPageAt(): invalid Page"); + if (pagedata == 0) + return store_E_InvalidParameter; + + sal_uInt32 const offset = pagedata->location(); + OSL_PRECOND(!(nOffset != offset), "store::PageCache::insertPageAt(): inconsistent Offset"); + if (nOffset != offset) + return store_E_InvalidParameter; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::insertPageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return insertPageAt_Impl (rxPage, nOffset); +} + +storeError PageCache::updatePageAt (PageHolder const & rxPage, sal_uInt32 nOffset) +{ + // [SECURITY:ValInput] + PageData const * pagedata = rxPage.get(); + OSL_PRECOND(!(pagedata == 0), "store::PageCache::updatePageAt(): invalid Page"); + if (pagedata == 0) + return store_E_InvalidParameter; + + sal_uInt32 const offset = pagedata->location(); + OSL_PRECOND(!(nOffset != offset), "store::PageCache::updatePageAt(): inconsistent Offset"); + if (nOffset != offset) + return store_E_InvalidParameter; + + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::updatePageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return updatePageAt_Impl (rxPage, nOffset); +} + +storeError PageCache::removePageAt (sal_uInt32 nOffset) +{ + OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::removePageAt(): invalid Offset"); + if (nOffset == STORE_PAGE_NULL) + return store_E_CantSeek; + + return removePageAt_Impl (nOffset); +} + +/*======================================================================== + * + * Entry. + * + *======================================================================*/ +namespace +{ + +struct Entry +{ + /** Representation. + */ + PageHolder m_xPage; + sal_uInt32 m_nOffset; + Entry * m_pNext; + + /** Allocation. + */ + static void * operator new (size_t, void * p) { return p; } + static void operator delete (void *, void *) {} + + /** Construction. + */ + explicit Entry (PageHolder const & rxPage = PageHolder(), sal_uInt32 nOffset = STORE_PAGE_NULL) + : m_xPage(rxPage), m_nOffset(nOffset), m_pNext(0) + {} + + /** Destruction. + */ + ~Entry() {} +}; + +} // namespace + +/*======================================================================== + * + * EntryCache interface. + * + *======================================================================*/ +namespace +{ + +class EntryCache +{ + rtl_cache_type * m_entry_cache; + +public: + static EntryCache & get(); + + Entry * create (PageHolder const & rxPage, sal_uInt32 nOffset); + + void destroy (Entry * entry); + +protected: + EntryCache(); + ~EntryCache(); +}; + +} // namespace + +/*======================================================================== + * + * EntryCache implementation. + * + *======================================================================*/ + +EntryCache & EntryCache::get() +{ + static EntryCache g_entry_cache; + return g_entry_cache; +} + +EntryCache::EntryCache() +{ + m_entry_cache = rtl_cache_create ( + "store_cache_entry_cache", + sizeof(Entry), + 0, // objalign + 0, // constructor + 0, // destructor + 0, // reclaim + 0, // userarg + 0, // default source + 0 // flags + ); +} + +EntryCache::~EntryCache() +{ + rtl_cache_destroy (m_entry_cache), m_entry_cache = 0; +} + +Entry * EntryCache::create (PageHolder const & rxPage, sal_uInt32 nOffset) +{ + void * pAddr = rtl_cache_alloc (m_entry_cache); + if (pAddr != 0) + { + // construct. + return new(pAddr) Entry (rxPage, nOffset); + } + return 0; +} + +void EntryCache::destroy (Entry * entry) +{ + if (entry != 0) + { + // destruct. + entry->~Entry(); + + // return to cache. + rtl_cache_free (m_entry_cache, entry); + } +} + +/*======================================================================== + * + * highbit():= log2() + 1 (complexity O(1)) + * + *======================================================================*/ +static int highbit(sal_Size n) +{ + register int k = 1; + + if (n == 0) + return (0); +#if SAL_TYPES_SIZEOFLONG == 8 + if (n & 0xffffffff00000000ul) + k |= 32, n >>= 32; +#endif + if (n & 0xffff0000) + k |= 16, n >>= 16; + if (n & 0xff00) + k |= 8, n >>= 8; + if (n & 0xf0) + k |= 4, n >>= 4; + if (n & 0x0c) + k |= 2, n >>= 2; + if (n & 0x02) + k++; + + return (k); +} + +/*======================================================================== + * + * PageCache_Impl implementation. + * + *======================================================================*/ +namespace store +{ + +class PageCache_Impl : + public store::OStoreObject, + public store::PageCache +{ + /** Representation. + */ + static size_t const theTableSize = 32; + STORE_STATIC_ASSERT(STORE_IMPL_ISP2(theTableSize)); + + Entry ** m_hash_table; + Entry * m_hash_table_0[theTableSize]; + size_t m_hash_size; + size_t m_hash_shift; + size_t const m_page_shift; + + size_t m_hash_entries; // total number of entries in table. + size_t m_nHit; + size_t m_nMissed; + + inline int hash_Impl(sal_uInt32 a, size_t s, size_t q, size_t m) + { + return ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m)); + } + inline int hash_index_Impl (sal_uInt32 nOffset) + { + return hash_Impl(nOffset, m_hash_shift, m_page_shift, m_hash_size - 1); + } + + Entry * lookup_Impl (Entry * entry, sal_uInt32 nOffset); + void rescale_Impl (sal_Size new_size); + + /** PageCache Implementation. + */ + virtual storeError lookupPageAt_Impl ( + PageHolder & rxPage, + sal_uInt32 nOffset); + + virtual storeError insertPageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset); + + virtual storeError updatePageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset); + + virtual storeError removePageAt_Impl ( + sal_uInt32 nOffset); + + /** Not implemented. + */ + PageCache_Impl (PageCache_Impl const &); + PageCache_Impl & operator= (PageCache_Impl const &); + +public: + /** Construction. + */ + explicit PageCache_Impl (sal_uInt16 nPageSize); + + /** Delegate multiple inherited IReference. + */ + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + +protected: + /** Destruction. + */ + virtual ~PageCache_Impl (void); +}; + +} // namespace store + +PageCache_Impl::PageCache_Impl (sal_uInt16 nPageSize) + : m_hash_table (m_hash_table_0), + m_hash_size (theTableSize), + m_hash_shift (highbit(m_hash_size) - 1), + m_page_shift (highbit(nPageSize) - 1), + m_hash_entries (0), + m_nHit (0), + m_nMissed (0) +{ + static size_t const theSize = sizeof(m_hash_table_0) / sizeof(m_hash_table_0[0]); + STORE_STATIC_ASSERT(theSize == theTableSize); + memset(m_hash_table_0, 0, sizeof(m_hash_table_0)); +} + +PageCache_Impl::~PageCache_Impl() +{ + double s_x = 0.0, s_xx = 0.0; + sal_Size i, n = m_hash_size; + for (i = 0; i < n; i++) + { + int x = 0; + Entry * entry = m_hash_table[i]; + while (entry != 0) + { + m_hash_table[i] = entry->m_pNext, entry->m_pNext = 0; + EntryCache::get().destroy (entry); + entry = m_hash_table[i]; + x += 1; + } + s_x += double(x); + s_xx += double(x) * double(x); + } + double ave = s_x / double(n); + OSL_TRACE("ave hash chain length: %g", ave); + (void) ave; + + if (m_hash_table != m_hash_table_0) + { + rtl_freeMemory (m_hash_table); + m_hash_table = m_hash_table_0; + m_hash_size = theTableSize; + m_hash_shift = highbit(m_hash_size) - 1; + } + OSL_TRACE("Hits: %u, Misses: %u", m_nHit, m_nMissed); +} + +oslInterlockedCount PageCache_Impl::acquire() +{ + return OStoreObject::acquire(); +} + +oslInterlockedCount PageCache_Impl::release() +{ + return OStoreObject::release(); +} + +void PageCache_Impl::rescale_Impl (sal_Size new_size) +{ + sal_Size new_bytes = new_size * sizeof(Entry*); + Entry ** new_table = (Entry**)(rtl_allocateMemory(new_bytes)); + + if (new_table != 0) + { + Entry ** old_table = m_hash_table; + sal_Size old_size = m_hash_size; + + OSL_TRACE("ave chain length: %u, total entries: %u [old_size: %u, new_size: %u]", + m_hash_entries >> m_hash_shift, m_hash_entries, old_size, new_size); + + memset (new_table, 0, new_bytes); + + m_hash_table = new_table; + m_hash_size = new_size; + m_hash_shift = highbit(m_hash_size) - 1; + + sal_Size i; + for (i = 0; i < old_size; i++) + { + Entry * curr = old_table[i]; + while (curr != 0) + { + Entry * next = curr->m_pNext; + int index = hash_index_Impl(curr->m_nOffset); + curr->m_pNext = m_hash_table[index], m_hash_table[index] = curr; + curr = next; + } + old_table[i] = 0; + } + if (old_table != m_hash_table_0) + { + // + rtl_freeMemory (old_table); + } + } +} + +Entry * PageCache_Impl::lookup_Impl (Entry * entry, sal_uInt32 nOffset) +{ + register int lookups = 0; + while (entry != 0) + { + if (entry->m_nOffset == nOffset) + break; + + lookups += 1; + entry = entry->m_pNext; + } + if (lookups > 2) + { + sal_Size new_size = m_hash_size, ave = m_hash_entries >> m_hash_shift; + for (; ave > 4; new_size *= 2, ave /= 2) + continue; + if (new_size != m_hash_size) + rescale_Impl (new_size); + } + return entry; +} + +storeError PageCache_Impl::lookupPageAt_Impl ( + PageHolder & rxPage, + sal_uInt32 nOffset) +{ + int index = hash_index_Impl(nOffset); + Entry const * entry = lookup_Impl (m_hash_table[index], nOffset); + if (entry != 0) + { + // Existing entry. + rxPage = entry->m_xPage; + + // Update stats and leave. + m_nHit += 1; + return store_E_None; + } + + // Cache miss. Update stats and leave. + m_nMissed += 1; + return store_E_NotExists; +} + +storeError PageCache_Impl::insertPageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset) +{ + Entry * entry = EntryCache::get().create (rxPage, nOffset); + if (entry != 0) + { + // Insert new entry. + int index = hash_index_Impl(nOffset); + entry->m_pNext = m_hash_table[index], m_hash_table[index] = entry; + + // Update stats and leave. + m_hash_entries += 1; + return store_E_None; + } + return store_E_OutOfMemory; +} + +storeError PageCache_Impl::updatePageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset) +{ + int index = hash_index_Impl(nOffset); + Entry * entry = lookup_Impl (m_hash_table[index], nOffset); + if (entry != 0) + { + // Update existing entry. + entry->m_xPage = rxPage; + + // Update stats and leave. // m_nUpdHit += 1; + return store_E_None; + } + return insertPageAt_Impl (rxPage, nOffset); +} + +storeError PageCache_Impl::removePageAt_Impl ( + sal_uInt32 nOffset) +{ + Entry ** ppEntry = &(m_hash_table[hash_index_Impl(nOffset)]); + while (*ppEntry != 0) + { + if ((*ppEntry)->m_nOffset == nOffset) + { + // Existing entry. + Entry * entry = (*ppEntry); + + // Dequeue and destroy entry. + (*ppEntry) = entry->m_pNext, entry->m_pNext = 0; + EntryCache::get().destroy (entry); + + // Update stats and leave. + m_hash_entries -= 1; + return store_E_None; + } + ppEntry = &((*ppEntry)->m_pNext); + } + return store_E_NotExists; +} + +/*======================================================================== + * + * Old OStorePageCache implementation. + * + * (two-way association (sorted address array, LRU chain)). + * (external OStorePageData representation). + * + *======================================================================*/ + +/*======================================================================== + * + * PageCache factory implementation. + * + *======================================================================*/ +namespace store { + +storeError +PageCache_createInstance ( + rtl::Reference< store::PageCache > & rxCache, + sal_uInt16 nPageSize) +{ + rxCache = new PageCache_Impl (nPageSize); + if (!rxCache.is()) + return store_E_OutOfMemory; + + return store_E_None; +} + +} // namespace store diff --git a/store/source/storcach.hxx b/store/source/storcach.hxx new file mode 100644 index 000000000000..7f56a8d83075 --- /dev/null +++ b/store/source/storcach.hxx @@ -0,0 +1,112 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORCACH_HXX +#define _STORE_STORCACH_HXX "$Revision: 1.6.8.2 $" + +#include "sal/types.h" +#include "rtl/ref.hxx" + +#include "store/types.h" +#include "storbase.hxx" + +namespace store +{ + +/*======================================================================== + * + * PageCache interface. + * + *======================================================================*/ + +class PageCache : public rtl::IReference +{ +public: + /** load. + */ + storeError lookupPageAt ( + PageHolder & rxPage, + sal_uInt32 nOffset); + + /** insert. + */ + storeError insertPageAt ( + PageHolder const & rxPage, + sal_uInt32 nOffset); + + /** update, or insert. + */ + storeError updatePageAt ( + PageHolder const & rxPage, + sal_uInt32 nOffset); + + /** remove (invalidate). + */ + storeError removePageAt ( + sal_uInt32 nOffset); + +private: + /** Implementation (abstract). + */ + virtual storeError lookupPageAt_Impl ( + PageHolder & rxPage, + sal_uInt32 nOffset) = 0; + + virtual storeError insertPageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset) = 0; + + virtual storeError updatePageAt_Impl ( + PageHolder const & rxPage, + sal_uInt32 nOffset) = 0; + + virtual storeError removePageAt_Impl ( + sal_uInt32 nOffset) = 0; +}; + +/*======================================================================== + * + * PageCache factory. + * + *======================================================================*/ + +storeError +PageCache_createInstance ( + rtl::Reference< store::PageCache > & rxCache, + sal_uInt16 nPageSize +); + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORCACH_HXX */ + diff --git a/store/source/stordata.cxx b/store/source/stordata.cxx new file mode 100644 index 000000000000..901da15c8040 --- /dev/null +++ b/store/source/stordata.cxx @@ -0,0 +1,1130 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "stordata.hxx" + +#include "sal/types.h" +#include "osl/diagnose.h" + +#include "store/types.h" +#include "storbase.hxx" +#include "storbios.hxx" + +using namespace store; + +/*======================================================================== + * + * OStoreDataPageObject implementation. + * + *======================================================================*/ +/* + * guard. + */ +storeError OStoreDataPageObject::guard (sal_uInt32 nAddr) +{ + return PageHolderObject< page >::guard (m_xPage, nAddr); +} + +/* + * verify. + */ +storeError OStoreDataPageObject::verify (sal_uInt32 nAddr) const +{ + return PageHolderObject< page >::verify (m_xPage, nAddr); +} + +/*======================================================================== + * + * OStoreIndirectionPageObject implementation. + * + *======================================================================*/ +/* + * store_truncate_Impl (single indirect page). + */ +static storeError store_truncate_Impl ( + sal_uInt32 nAddr, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + if (nAddr != STORE_PAGE_NULL) + { + // Load single indirect page. + OStoreIndirectionPageObject aSingle; + storeError eErrCode = rBIOS.loadObjectAt (aSingle, nAddr); + if (eErrCode == store_E_None) + { + // Truncate to 'nSingle' direct pages. + eErrCode = aSingle.truncate (nSingle, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + } + else + { + if (eErrCode != store_E_InvalidChecksum) + return eErrCode; + } + + // Check for complete truncation. + if (nSingle == 0) + { + // Free single indirect page. + eErrCode = rBIOS.free (nAddr); + if (eErrCode != store_E_None) + return eErrCode; + } + } + return store_E_None; +} + +/* + * store_truncate_Impl (double indirect page). + */ +static storeError store_truncate_Impl ( + sal_uInt32 nAddr, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + if (nAddr != STORE_PAGE_NULL) + { + // Load double indirect page. + OStoreIndirectionPageObject aDouble; + storeError eErrCode = rBIOS.loadObjectAt (aDouble, nAddr); + if (eErrCode == store_E_None) + { + // Truncate to 'nDouble', 'nSingle' pages. + eErrCode = aDouble.truncate (nDouble, nSingle, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + } + else + { + if (eErrCode != store_E_InvalidChecksum) + return eErrCode; + } + + // Check for complete truncation. + if ((nDouble + nSingle) == 0) + { + // Free double indirect page. + eErrCode = rBIOS.free (nAddr); + if (eErrCode != store_E_None) + return eErrCode; + } + } + return store_E_None; +} + +/* + * store_truncate_Impl (triple indirect page). + */ +static storeError store_truncate_Impl ( + sal_uInt32 nAddr, + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + if (nAddr != STORE_PAGE_NULL) + { + // Load triple indirect page. + OStoreIndirectionPageObject aTriple; + storeError eErrCode = rBIOS.loadObjectAt (aTriple, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate to 'nTriple', 'nDouble', 'nSingle' pages. + eErrCode = aTriple.truncate (nTriple, nDouble, nSingle, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if ((nTriple + nDouble + nSingle) == 0) + { + // Free triple indirect page. + eErrCode = rBIOS.free (nAddr); + if (eErrCode != store_E_None) + return eErrCode; + } + } + return store_E_None; +} + +/* + * loadOrCreate. + */ +storeError OStoreIndirectionPageObject::loadOrCreate ( + sal_uInt32 nAddr, + OStorePageBIOS & rBIOS) +{ + if (nAddr == STORE_PAGE_NULL) + { + storeError eErrCode = construct<page>(rBIOS.allocator()); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = rBIOS.allocate (*this); + if (eErrCode != store_E_None) + return eErrCode; + + // Save location pending at caller. + return store_E_Pending; + } + return rBIOS.loadObjectAt (*this, nAddr); +} + +/* + * guard. + */ +storeError OStoreIndirectionPageObject::guard (sal_uInt32 nAddr) +{ + return PageHolderObject< page >::guard (m_xPage, nAddr); +} + +/* + * verify. + */ +storeError OStoreIndirectionPageObject::verify (sal_uInt32 nAddr) const +{ + return PageHolderObject< page >::verify (m_xPage, nAddr); +} + +/* + * read (single indirect). + */ +storeError OStoreIndirectionPageObject::read ( + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page const & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!(nSingle < nLimit)) + return store_E_InvalidAccess; + + // Obtain data page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nSingle]); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + // Load data page and leave. + return rBIOS.loadObjectAt (rData, nAddr); +} + +/* + * read (double indirect). + */ +storeError OStoreIndirectionPageObject::read ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page const & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Check single indirect page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nDouble]); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + // Load single indirect page. + OStoreIndirectionPageObject aSingle; + storeError eErrCode = rBIOS.loadObjectAt (aSingle, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Read single indirect and leave. + return aSingle.read (nSingle, rData, rBIOS); +} + +/* + * read (triple indirect). + */ +storeError OStoreIndirectionPageObject::read ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page const & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Check double indirect page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nTriple]); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + // Load double indirect page. + OStoreIndirectionPageObject aDouble; + storeError eErrCode = rBIOS.loadObjectAt (aDouble, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Read double indirect and leave. + return aDouble.read (nDouble, nSingle, rData, rBIOS); +} + +/* + * write (single indirect). + */ +storeError OStoreIndirectionPageObject::write ( + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!(nSingle < nLimit)) + return store_E_InvalidAccess; + + // Obtain data page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nSingle]); + if (nAddr == STORE_PAGE_NULL) + { + // Allocate data page. + storeError eErrCode = rBIOS.allocate (rData); + if (eErrCode != store_E_None) + return eErrCode; + + // Store data page location. + rPage.m_pData[nSingle] = store::htonl(rData.location()); + + // Save this page. + return rBIOS.saveObjectAt (*this, location()); + } + else + { + // Save data page. + return rBIOS.saveObjectAt (rData, nAddr); + } +} + +/* + * write (double indirect). + */ +storeError OStoreIndirectionPageObject::write ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Load or create single indirect page. + OStoreIndirectionPageObject aSingle; + storeError eErrCode = aSingle.loadOrCreate (store::ntohl(rPage.m_pData[nDouble]), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + rPage.m_pData[nDouble] = store::htonl(aSingle.location()); + + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Write single indirect and leave. + return aSingle.write (nSingle, rData, rBIOS); +} + +/* + * write (triple indirect). + */ +storeError OStoreIndirectionPageObject::write ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Load or create double indirect page. + OStoreIndirectionPageObject aDouble; + storeError eErrCode = aDouble.loadOrCreate (store::ntohl(rPage.m_pData[nTriple]), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + rPage.m_pData[nTriple] = store::htonl(aDouble.location()); + + eErrCode = rBIOS.saveObjectAt (*this, location()); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Write double indirect and leave. + return aDouble.write (nDouble, nSingle, rData, rBIOS); +} + +/* + * truncate (single indirect). + */ +storeError OStoreIndirectionPageObject::truncate ( + sal_uInt16 nSingle, + OStorePageBIOS & rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!(nSingle < nLimit)) + return store_E_InvalidAccess; + + // Truncate. + storeError eErrCode = store_E_None; + for (sal_uInt16 i = nLimit; i > nSingle; i--) + { + // Obtain data page location. + sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[i - 1]); + if (nAddr != STORE_PAGE_NULL) + { + // Free data page. + eErrCode = rBIOS.free (nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Clear pointer to data page. + rPage.m_pData[i - 1] = STORE_PAGE_NULL; + touch(); + } + } + + // Check for modified page. + if (dirty()) + { + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + } + + // Done. + return eErrCode; +} + +/* + * truncate (double indirect). + */ +storeError OStoreIndirectionPageObject::truncate ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Truncate. + storeError eErrCode = store_E_None; + for (sal_uInt16 i = nLimit; i > nDouble + 1; i--) + { + // Truncate single indirect page to zero direct pages. + eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[i - 1]), 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Clear pointer to single indirect page. + rPage.m_pData[i - 1] = STORE_PAGE_NULL; + touch(); + } + + // Truncate last single indirect page to 'nSingle' direct pages. + eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[nDouble]), nSingle, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if (nSingle == 0) + { + // Clear pointer to last single indirect page. + rPage.m_pData[nDouble] = STORE_PAGE_NULL; + touch(); + } + + // Check for modified page. + if (dirty()) + { + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + } + + // Done. + return eErrCode; +} + +/* + * truncate (triple indirect). + */ +storeError OStoreIndirectionPageObject::truncate ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check arguments. + sal_uInt16 const nLimit = rPage.capacityCount(); + if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit))) + return store_E_InvalidAccess; + + // Truncate. + storeError eErrCode = store_E_None; + for (sal_uInt16 i = nLimit; i > nTriple + 1; i--) + { + // Truncate double indirect page to zero single indirect pages. + eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[i - 1]), 0, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Clear pointer to double indirect page. + rPage.m_pData[i - 1] = STORE_PAGE_NULL; + touch(); + } + + // Truncate last double indirect page to 'nDouble', 'nSingle' pages. + eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[nTriple]), nDouble, nSingle, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if ((nDouble + nSingle) == 0) + { + // Clear pointer to last double indirect page. + rPage.m_pData[nTriple] = STORE_PAGE_NULL; + touch(); + } + + // Check for modified page. + if (dirty()) + { + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + } + + // Done. + return eErrCode; +} + +/*======================================================================== + * + * OStoreDirectoryPageObject implementation. + * + *======================================================================*/ +/* + * guard. + */ +storeError OStoreDirectoryPageObject::guard (sal_uInt32 nAddr) +{ + return PageHolderObject< page >::guard (m_xPage, nAddr); +} + +/* + * verify. + */ +storeError OStoreDirectoryPageObject::verify (sal_uInt32 nAddr) const +{ + return PageHolderObject< page >::verify (m_xPage, nAddr); + // OLD: m_rPage.verifyVersion (STORE_MAGIC_DIRECTORYPAGE); +} + +/* + * scope (external data page; private). + */ +OStoreDirectoryPageData::ChunkScope +OStoreDirectoryPageObject::scope ( + sal_uInt32 nPage, + page::DataBlock::LinkDescriptor &rDescr) const +{ + page const & rPage = PAGE(); + OStoreDirectoryDataBlock const & rDataBlock = rPage.m_aDataBlock; + + sal_uInt32 index0, index1, index2, index3; + + // direct. + sal_uInt32 nCount = rDataBlock.directCount(); + sal_uInt32 nLimit = nCount; + if (nPage < nLimit) + { + // Page to index reduction. + index0 = nPage; + + // Setup LinkDescriptor indices. + rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff); + + // Done. + return page::SCOPE_DIRECT; + } + nPage -= nLimit; + + // single indirect. + sal_uInt32 const nCapacity = indirect::capacityCount(rPage.m_aDescr); + nCount = rDataBlock.singleCount(); + nLimit = nCount * nCapacity; + if (nPage < nLimit) + { + // Page to index reduction. + sal_uInt32 n = nPage; + + // Reduce to single indirect i(1), direct n = i(0). + index1 = n / nCapacity; + index0 = n % nCapacity; + + // Verify reduction. + n = index1 * nCapacity + index0; + OSL_POSTCOND(n == nPage, "wrong math on indirect indices"); + if (n != nPage) + return page::SCOPE_UNKNOWN; + + // Setup LinkDescriptor indices. + rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff); + rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff); + + // Done. + return page::SCOPE_SINGLE; + } + nPage -= nLimit; + + // double indirect. + nCount = rDataBlock.doubleCount(); + nLimit = nCount * nCapacity * nCapacity; + if (nPage < nLimit) + { + // Page to index reduction. + sal_uInt32 n = nPage; + + // Reduce to double indirect i(2), single indirect n = i(0). + index2 = n / (nCapacity * nCapacity); + n = n % (nCapacity * nCapacity); + + // Reduce to single indirect i(1), direct n = i(0). + index1 = n / nCapacity; + index0 = n % nCapacity; + + // Verify reduction. + n = index2 * nCapacity * nCapacity + + index1 * nCapacity + index0; + OSL_POSTCOND(n == nPage, "wrong math on double indirect indices"); + if (n != nPage) + return page::SCOPE_UNKNOWN; + + // Setup LinkDescriptor indices. + rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff); + rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff); + rDescr.m_nIndex2 = (sal_uInt16)(index2 & 0xffff); + + // Done. + return page::SCOPE_DOUBLE; + } + nPage -= nLimit; + + // triple indirect. + nCount = rDataBlock.tripleCount(); + nLimit = nCount * nCapacity * nCapacity * nCapacity; + if (nPage < nLimit) + { + // Page to index reduction. + sal_uInt32 n = nPage; + + // Reduce to triple indirect i(3), double indirect n. + index3 = n / (nCapacity * nCapacity * nCapacity); + n = n % (nCapacity * nCapacity * nCapacity); + + // Reduce to double indirect i(2), single indirect n. + index2 = n / (nCapacity * nCapacity); + n = n % (nCapacity * nCapacity); + + // Reduce to single indirect i(1), direct n = i(0). + index1 = n / nCapacity; + index0 = n % nCapacity; + + // Verify reduction. + n = index3 * nCapacity * nCapacity * nCapacity + + index2 * nCapacity * nCapacity + + index1 * nCapacity + index0; + OSL_POSTCOND(n == nPage, "wrong math on triple indirect indices"); + if (n != nPage) + return page::SCOPE_UNKNOWN; + + // Setup LinkDescriptor indices. + rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff); + rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff); + rDescr.m_nIndex2 = (sal_uInt16)(index2 & 0xffff); + rDescr.m_nIndex3 = (sal_uInt16)(index3 & 0xffff); + + // Done. + return page::SCOPE_TRIPLE; + } + + // Unreachable (more than triple indirect). + return page::SCOPE_UNREACHABLE; +} + +#if 0 /* NYI */ +/* + * chunk (external data page). + */ +inode::ChunkDescriptor OStoreDirectoryPageObject::chunk (sal_uInt32 nOffset) +{ + // @@@ INSUFFICIENT: NEED SCOPE AS WELL @@@ + sal_uInt32 nCapacity = m_rPage.capacity(); + if (nOffset < nCapacity) + // Internal scope (inode page). + return inode::ChunkDescriptor (nOffset, nCapacity); + else + // External scope (data page). + return inode::ChunkDescriptor (nOffset - nCapacity, data::capacity(m_rPage.m_aDescr)); + + inode::ChunkScope eScope = m_rPage.scope(nOffset); + if (eScope == inode::SCOPE_INTERNAL) + // Inode page (internal scope). + return inode::ChunkDescriptor (nOffset, m_rPage.capacity()); + else + // Data page (external scope). + return inode::ChunkDescriptor (nOffset - m_rPage.capacity(), data::capacity(m_rPage.m_aDescr)); +} +#endif /* NYI */ + +/* + * read (external data page). + */ +storeError OStoreDirectoryPageObject::read ( + sal_uInt32 nPage, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + // Determine scope and link indices. + page::DataBlock::LinkDescriptor aLink; + page::ChunkScope eScope = scope (nPage, aLink); + + storeError eErrCode = store_E_None; + if (eScope == page::SCOPE_DIRECT) + { + sal_uInt32 const nAddr = directLink (aLink.m_nIndex0); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + eErrCode = rBIOS.loadObjectAt (rData, nAddr); + } + else if (eScope == page::SCOPE_SINGLE) + { + sal_uInt32 const nAddr = singleLink (aLink.m_nIndex1); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + OStoreIndirectionPageObject aSingle; + eErrCode = rBIOS.loadObjectAt (aSingle, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = aSingle.read (aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_DOUBLE) + { + sal_uInt32 const nAddr = doubleLink (aLink.m_nIndex2); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + OStoreIndirectionPageObject aDouble; + eErrCode = rBIOS.loadObjectAt (aDouble, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = aDouble.read (aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_TRIPLE) + { + sal_uInt32 const nAddr = tripleLink (aLink.m_nIndex3); + if (nAddr == STORE_PAGE_NULL) + return store_E_NotExists; + + OStoreIndirectionPageObject aTriple; + eErrCode = rBIOS.loadObjectAt (aTriple, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = aTriple.read (aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_UNREACHABLE) + { + // Out of scope. + eErrCode = store_E_CantSeek; + } + else + { + // Unknown scope. + OSL_TRACE("OStoreDirectoryPageObject::get(): scope failed"); + eErrCode = store_E_Unknown; + } + + // Leave. + return eErrCode; +} + +/* + * write (external data page). + */ +storeError OStoreDirectoryPageObject::write ( + sal_uInt32 nPage, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS) +{ + // Determine scope and link indices. + page::DataBlock::LinkDescriptor aLink; + page::ChunkScope eScope = scope (nPage, aLink); + + storeError eErrCode = store_E_None; + if (eScope == page::SCOPE_DIRECT) + { + sal_uInt32 const nAddr = directLink (aLink.m_nIndex0); + if (nAddr == STORE_PAGE_NULL) + { + // Allocate data page. + eErrCode = rBIOS.allocate (rData); + if (eErrCode != store_E_None) + return eErrCode; + + // Store data page location. + directLink (aLink.m_nIndex0, rData.location()); + } + else + { + // Save data page. + eErrCode = rBIOS.saveObjectAt (rData, nAddr); + } + } + else if (eScope == page::SCOPE_SINGLE) + { + OStoreIndirectionPageObject aSingle; + eErrCode = aSingle.loadOrCreate (singleLink (aLink.m_nIndex1), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + singleLink (aLink.m_nIndex1, aSingle.location()); + } + + eErrCode = aSingle.write (aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_DOUBLE) + { + OStoreIndirectionPageObject aDouble; + eErrCode = aDouble.loadOrCreate (doubleLink (aLink.m_nIndex2), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + doubleLink (aLink.m_nIndex2, aDouble.location()); + } + + eErrCode = aDouble.write (aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_TRIPLE) + { + OStoreIndirectionPageObject aTriple; + eErrCode = aTriple.loadOrCreate (tripleLink (aLink.m_nIndex3), rBIOS); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_Pending) + return eErrCode; + tripleLink (aLink.m_nIndex3, aTriple.location()); + } + + eErrCode = aTriple.write (aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS); + } + else if (eScope == page::SCOPE_UNREACHABLE) + { + // Out of scope. + eErrCode = store_E_CantSeek; + } + else + { + // Unknown scope. + OSL_TRACE("OStoreDirectoryPageObject::put(): scope failed"); + eErrCode = store_E_Unknown; + } + + // Leave. + return eErrCode; +} + +/* + * truncate (external data page). + */ +storeError OStoreDirectoryPageObject::truncate ( + sal_uInt32 nPage, + OStorePageBIOS &rBIOS) +{ + // Determine scope and link indices. + page::DataBlock::LinkDescriptor aLink; + page::ChunkScope eScope = scope (nPage, aLink); + + storeError eErrCode = store_E_None; + if (eScope == page::SCOPE_DIRECT) + { + // Truncate all triple indirect pages. + eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate all double indirect pages. + eErrCode = truncate (page::SCOPE_DOUBLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate all single indirect pages. + eErrCode = truncate (page::SCOPE_SINGLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate direct pages, including 'aLink.m_nIndex0'. + eErrCode = truncate (eScope, aLink.m_nIndex0, rBIOS); + } + else if (eScope == page::SCOPE_SINGLE) + { + // Truncate all triple indirect pages. + eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate all double indirect pages. + eErrCode = truncate (page::SCOPE_DOUBLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate single indirect pages, downto 'aLink.m_nIndex1'. + eErrCode = truncate (eScope, aLink.m_nIndex1 + 1, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate last single indirect page to ... pages. + eErrCode = store_truncate_Impl (singleLink (aLink.m_nIndex1), aLink.m_nIndex0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if (aLink.m_nIndex0 == 0) + { + // Clear pointer to last single indirect page. + singleLink (aLink.m_nIndex1, STORE_PAGE_NULL); + } + } + else if (eScope == page::SCOPE_DOUBLE) + { + // Truncate all triple indirect pages. + eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate double indirect pages, downto 'aLink.m_nIndex2'. + eErrCode = truncate (eScope, aLink.m_nIndex2 + 1, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate last double indirect page to ... pages. + eErrCode = store_truncate_Impl ( + doubleLink (aLink.m_nIndex2), aLink.m_nIndex1, aLink.m_nIndex0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if ((aLink.m_nIndex1 + aLink.m_nIndex0) == 0) + { + // Clear pointer to last double indirect page. + doubleLink (aLink.m_nIndex2, STORE_PAGE_NULL); + } + } + else if (eScope == page::SCOPE_TRIPLE) + { + // Truncate triple indirect pages, downto 'aLink.m_nIndex3'. + eErrCode = truncate (eScope, aLink.m_nIndex3 + 1, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate last triple indirect page to ... pages. + eErrCode = store_truncate_Impl ( + tripleLink (aLink.m_nIndex3), aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for complete truncation. + if ((aLink.m_nIndex2 + aLink.m_nIndex1 + aLink.m_nIndex0) == 0) + { + // Clear pointer to last triple indirect page. + tripleLink (aLink.m_nIndex3, STORE_PAGE_NULL); + } + } + else if (eScope == page::SCOPE_UNREACHABLE) + { + // Out of scope. + eErrCode = store_E_CantSeek; + } + else + { + // Unknown scope. + OSL_TRACE("OStoreDirectoryPageObject::put(): scope failed"); + eErrCode = store_E_Unknown; + } + + // Leave. + return eErrCode; +} + +/* + * truncate (external data page scope; private). + */ +storeError OStoreDirectoryPageObject::truncate ( + page::ChunkScope eScope, + sal_uInt16 nRemain, + OStorePageBIOS &rBIOS) +{ + OStoreDirectoryDataBlock const & rDataBlock = PAGE().m_aDataBlock; + + // Enter. + storeError eErrCode = store_E_None; + if (eScope == page::SCOPE_DIRECT) + { + // Truncate direct data pages. + sal_uInt16 i, n = rDataBlock.directCount(); + for (i = n; i > nRemain; i--) + { + // Obtain data page location. + sal_uInt32 nAddr = directLink (i - 1); + if (nAddr == STORE_PAGE_NULL) continue; + + // Free data page. + eErrCode = rBIOS.free (nAddr); + if (eErrCode != store_E_None) + break; + + // Clear pointer to data page. + directLink (i - 1, STORE_PAGE_NULL); + } + + // Done. + return eErrCode; + } + + if (eScope == page::SCOPE_SINGLE) + { + // Truncate single indirect pages. + sal_uInt16 i, n = rDataBlock.singleCount(); + for (i = n; i > nRemain; i--) + { + // Truncate single indirect page to zero data pages. + eErrCode = store_truncate_Impl (singleLink (i - 1), 0, rBIOS); + if (eErrCode != store_E_None) + break; + + // Clear pointer to single indirect page. + singleLink (i - 1, STORE_PAGE_NULL); + } + + // Done. + return eErrCode; + } + + if (eScope == page::SCOPE_DOUBLE) + { + // Truncate double indirect pages. + sal_uInt16 i, n = rDataBlock.doubleCount(); + for (i = n; i > nRemain; i--) + { + // Truncate double indirect page to zero single indirect pages. + eErrCode = store_truncate_Impl (doubleLink (i - 1), 0, 0, rBIOS); + if (eErrCode != store_E_None) + break; + + // Clear pointer to double indirect page. + doubleLink (i - 1, STORE_PAGE_NULL); + } + + // Done. + return eErrCode; + } + + if (eScope == page::SCOPE_TRIPLE) + { + // Truncate triple indirect pages. + sal_uInt16 i, n = rDataBlock.tripleCount(); + for (i = n; i > nRemain; i--) + { + // Truncate to zero double indirect pages. + eErrCode = store_truncate_Impl (tripleLink (i - 1), 0, 0, 0, rBIOS); + if (eErrCode != store_E_None) + break; + + // Clear pointer to triple indirect page. + tripleLink (i - 1, STORE_PAGE_NULL); + } + + // Done. + return eErrCode; + } + + // Invalid scope. + return store_E_InvalidAccess; +} diff --git a/store/source/stordata.hxx b/store/source/stordata.hxx new file mode 100644 index 000000000000..01ea2c0f86ec --- /dev/null +++ b/store/source/stordata.hxx @@ -0,0 +1,870 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORDATA_HXX_ +#define _STORE_STORDATA_HXX_ + +#include "sal/types.h" +#include "sal/macros.h" + +#include "store/types.h" +#include "storbase.hxx" + +namespace store +{ + +/*======================================================================== + * + * OStoreDataPageData. + * + *======================================================================*/ +#define STORE_MAGIC_DATAPAGE sal_uInt32(0x94190310) + +struct OStoreDataPageData : public store::OStorePageData +{ + typedef OStorePageData base; + typedef OStoreDataPageData self; + + typedef OStorePageDescriptor D; + + /** Representation. + */ + sal_uInt8 m_pData[1]; + + /** type. + */ + static const sal_uInt32 theTypeId = STORE_MAGIC_DATAPAGE; + + /** size. + */ + static const size_t theSize = 0; + static const sal_uInt16 thePageSize = base::theSize + self::theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= self::thePageSize); + + /** capacity. + */ + static sal_uInt16 capacity (const D& rDescr) // @see inode::ChunkDescriptor + { + return (store::ntohs(rDescr.m_nSize) - self::thePageSize); + } + sal_uInt16 capacity() const + { + return self::capacity (base::m_aDescr); + } + + /** usage. + */ + sal_uInt16 usage() const + { + return (store::ntohs(base::m_aDescr.m_nUsed) - self::thePageSize); + } + + /** Construction. + */ + explicit OStoreDataPageData (sal_uInt16 nPageSize = self::thePageSize) + : base (nPageSize) + { + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); + if (capacity()) memset (m_pData, 0, capacity()); + } + + /** guard (external representation). + */ + void guard() {} + + /** verify (external representation). + */ + storeError verify() const { return store_E_None; } +}; + +/*======================================================================== + * + * OStoreDataPageObject. + * + *======================================================================*/ +class OStoreDataPageObject : public store::OStorePageObject +{ + typedef OStorePageObject base; + typedef OStoreDataPageData page; + +public: + /** Construction. + */ + explicit OStoreDataPageObject (PageHolder const & rxPage = PageHolder()) + : OStorePageObject (rxPage) + {} + + /** External representation. + */ + virtual storeError guard (sal_uInt32 nAddr); + virtual storeError verify (sal_uInt32 nAddr) const; +}; + +/*======================================================================== + * + * OStoreIndirectionPageData. + * + *======================================================================*/ +#define STORE_MAGIC_INDIRECTPAGE sal_uInt32(0x89191107) + +struct OStoreIndirectionPageData : public store::OStorePageData +{ + typedef OStorePageData base; + typedef OStoreIndirectionPageData self; + + typedef OStorePageGuard G; + typedef OStorePageDescriptor D; + + /** Representation. + */ + G m_aGuard; + sal_uInt32 m_pData[1]; + + /** type. + */ + static const sal_uInt32 theTypeId = STORE_MAGIC_INDIRECTPAGE; + + /** size. + */ + static const size_t theSize = sizeof(G); + static const sal_uInt16 thePageSize = base::theSize + self::theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= self::thePageSize); + + /** capacity. + */ + static sal_uInt16 capacity (const D& rDescr) + { + return (store::ntohs(rDescr.m_nSize) - self::thePageSize); + } + sal_uInt16 capacity() const + { + return self::capacity (base::m_aDescr); + } + + /** capacityCount. + */ + static sal_uInt16 capacityCount (const D& rDescr) // @see DirectoryPageObject::scope() + { + return sal_uInt16(capacity(rDescr) / sizeof(sal_uInt32)); + } + sal_uInt16 capacityCount() const + { + return sal_uInt16(capacity() / sizeof(sal_uInt32)); + } + + /** Construction. + */ + explicit OStoreIndirectionPageData (sal_uInt16 nPageSize) + : base (nPageSize) + { + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); + self::m_aGuard.m_nMagic = store::htonl(0); + memset (m_pData, STORE_PAGE_NULL, capacity()); + } + + /** 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_pData, capacity()); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, m_pData, capacity()); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } +}; + +/*======================================================================== + * + * OStoreIndirectionPageObject. + * + *======================================================================*/ +class OStoreIndirectionPageObject : public store::OStorePageObject +{ + typedef OStorePageObject base; + typedef OStoreIndirectionPageData page; + +public: + /** Construction. + */ + explicit OStoreIndirectionPageObject (PageHolder const & rxPage = PageHolder()) + : OStorePageObject (rxPage) + {} + + /** External representation. + */ + storeError loadOrCreate ( + sal_uInt32 nAddr, + OStorePageBIOS & rBIOS); + + virtual storeError guard (sal_uInt32 nAddr); + virtual storeError verify (sal_uInt32 nAddr) const; + + /** read (indirect data page). + */ + storeError read ( + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + storeError read ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + storeError read ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + /** write (indirect data page). + */ + storeError write ( + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + storeError write ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + storeError write ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + /** truncate (indirect data page). + */ + storeError truncate ( + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS); + + storeError truncate ( + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS); + + storeError truncate ( + sal_uInt16 nTriple, + sal_uInt16 nDouble, + sal_uInt16 nSingle, + OStorePageBIOS &rBIOS); +}; + +/*======================================================================== + * + * OStorePageNameBlock. + * + *======================================================================*/ +struct OStorePageNameBlock +{ + typedef OStorePageGuard G; + typedef OStorePageKey K; + + /** Representation. + */ + G m_aGuard; + K m_aKey; + sal_uInt32 m_nAttrib; + sal_Char m_pData[STORE_MAXIMUM_NAMESIZE]; + + /** size. + */ + static const size_t theSize = sizeof(G) + sizeof(K) + sizeof(sal_uInt32) + sizeof(sal_Char[STORE_MAXIMUM_NAMESIZE]); + + /** initialize. + */ + void initialize (void) + { + m_aGuard = G(); + m_aKey = K(); + m_nAttrib = 0; + memset (m_pData, 0, sizeof(m_pData)); + } + + /** Construction. + */ + OStorePageNameBlock (void) + : m_aGuard(), m_aKey(), m_nAttrib (0) + { + memset (m_pData, 0, sizeof(m_pData)); + } + + /** 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_aKey, theSize - sizeof(G)); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aKey, theSize - sizeof(G)); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } +}; + +/*======================================================================== + * + * OStoreDirectoryDataBlock. + * + *======================================================================*/ +#define STORE_LIMIT_DATAPAGE_DIRECT 16 +#define STORE_LIMIT_DATAPAGE_SINGLE 8 +#define STORE_LIMIT_DATAPAGE_DOUBLE 1 +#define STORE_LIMIT_DATAPAGE_TRIPLE 1 + +struct OStoreDirectoryDataBlock +{ + typedef OStorePageGuard G; + + /** LinkDescriptor. + */ + struct LinkDescriptor + { + /** Representation. + */ + sal_uInt16 m_nIndex0; + sal_uInt16 m_nIndex1; + sal_uInt16 m_nIndex2; + sal_uInt16 m_nIndex3; + + /** Construction. + */ + LinkDescriptor (void) + : m_nIndex0 ((sal_uInt16)(~0)), + m_nIndex1 ((sal_uInt16)(~0)), + m_nIndex2 ((sal_uInt16)(~0)), + m_nIndex3 ((sal_uInt16)(~0)) + {} + }; + + /** LinkTable. + */ + struct LinkTable + { + /** Representation. + */ + sal_uInt32 m_pDirect[STORE_LIMIT_DATAPAGE_DIRECT]; + sal_uInt32 m_pSingle[STORE_LIMIT_DATAPAGE_SINGLE]; + sal_uInt32 m_pDouble[STORE_LIMIT_DATAPAGE_DOUBLE]; + sal_uInt32 m_pTriple[STORE_LIMIT_DATAPAGE_TRIPLE]; + + /** initialize. + */ + void initialize (void) + { + memset(m_pDirect, STORE_PAGE_NULL, sizeof(m_pDirect)); + memset(m_pSingle, STORE_PAGE_NULL, sizeof(m_pSingle)); + memset(m_pDouble, STORE_PAGE_NULL, sizeof(m_pDouble)); + memset(m_pTriple, STORE_PAGE_NULL, sizeof(m_pTriple)); + } + + /** Construction. + */ + LinkTable (void) + { + initialize(); + } + }; + + /** Representation. + */ + G m_aGuard; + LinkTable m_aTable; + sal_uInt32 m_nDataLen; + + /** size. + */ + static const size_t theSize = sizeof(G) + sizeof(LinkTable) + sizeof(sal_uInt32); + + /** initialize. + */ + void initialize (void) + { + m_aGuard = G(); + m_aTable.initialize(); + m_nDataLen = 0; + } + + /** Construction. + */ + OStoreDirectoryDataBlock (void) + : m_aGuard(), m_aTable(), m_nDataLen (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_aTable, theSize - sizeof(G)); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, &m_aTable, theSize - sizeof(G)); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } + + /** direct. + */ + static sal_uInt16 directCount (void) + { + return ((sal_uInt16)(STORE_LIMIT_DATAPAGE_DIRECT)); + } + sal_uInt32 directLink (sal_uInt16 nIndex) const + { + if (nIndex < directCount()) + return store::ntohl(m_aTable.m_pDirect[nIndex]); + else + return STORE_PAGE_NULL; + } + void directLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + if (nIndex < directCount()) + m_aTable.m_pDirect[nIndex] = store::htonl(nAddr); + } + + /** single. + */ + static sal_uInt16 singleCount (void) + { + return ((sal_uInt16)(STORE_LIMIT_DATAPAGE_SINGLE)); + } + sal_uInt32 singleLink (sal_uInt16 nIndex) const + { + if (nIndex < singleCount()) + return store::ntohl(m_aTable.m_pSingle[nIndex]); + else + return STORE_PAGE_NULL; + } + void singleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + if (nIndex < singleCount()) + m_aTable.m_pSingle[nIndex] = store::htonl(nAddr); + } + + /** double. + */ + static sal_uInt16 doubleCount (void) + { + return ((sal_uInt16)(STORE_LIMIT_DATAPAGE_DOUBLE)); + } + sal_uInt32 doubleLink (sal_uInt16 nIndex) const + { + if (nIndex < doubleCount()) + return store::ntohl(m_aTable.m_pDouble[nIndex]); + else + return STORE_PAGE_NULL; + } + void doubleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + if (nIndex < doubleCount()) + m_aTable.m_pDouble[nIndex] = store::htonl(nAddr); + } + + /** triple. + */ + static sal_uInt16 tripleCount (void) + { + return ((sal_uInt16)(STORE_LIMIT_DATAPAGE_TRIPLE)); + } + sal_uInt32 tripleLink (sal_uInt16 nIndex) const + { + if (nIndex < tripleCount()) + return store::ntohl(m_aTable.m_pTriple[nIndex]); + else + return STORE_PAGE_NULL; + } + void tripleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + if (nIndex < tripleCount()) + m_aTable.m_pTriple[nIndex] = store::htonl(nAddr); + } +}; + +/*======================================================================== + * + * OStoreDirectoryPageData. + * + *======================================================================*/ +#define STORE_MAGIC_DIRECTORYPAGE sal_uInt32(0x62190120) + +struct OStoreDirectoryPageData : public store::OStorePageData +{ + typedef OStorePageData base; + typedef OStoreDirectoryPageData self; + + typedef OStorePageDescriptor D; + typedef OStorePageNameBlock NameBlock; + typedef OStoreDirectoryDataBlock DataBlock; + + /** Representation. + */ + NameBlock m_aNameBlock; + DataBlock m_aDataBlock; + sal_uInt8 m_pData[1]; + + /** type. + */ + static const sal_uInt32 theTypeId = STORE_MAGIC_DIRECTORYPAGE; + + /** size. + */ + static const size_t theSize = NameBlock::theSize + DataBlock::theSize; + static const sal_uInt16 thePageSize = base::theSize + self::theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= self::thePageSize); + + /** capacity. + */ + sal_uInt16 capacity() const + { + return (store::ntohs(base::m_aDescr.m_nSize) - self::thePageSize); + } + + /** usage. + */ + sal_uInt16 usage() const + { + return (store::ntohs(base::m_aDescr.m_nUsed) - self::thePageSize); + } + + /** initialize. + */ + void initialize (void) + { + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); + + m_aNameBlock.initialize(); + m_aDataBlock.initialize(); + + memset (m_pData, 0, capacity()); + } + + /** Construction. + */ + explicit OStoreDirectoryPageData (sal_uInt16 nPageSize) + : base (nPageSize), m_aNameBlock(), m_aDataBlock() + { + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); + memset (m_pData, 0, capacity()); + } + + /** guard (external representation). + */ + void guard() + { + m_aNameBlock.guard(); + m_aDataBlock.guard(); + } + + /** verify (external representation). + */ + storeError verify() const + { + storeError eErrCode = m_aNameBlock.verify(); + if (eErrCode == store_E_None) + eErrCode = m_aDataBlock.verify(); + return eErrCode; + } + + /** ChunkDescriptor. + */ + struct ChunkDescriptor + { + /** Representation. + */ + sal_uInt32 m_nPage; + sal_uInt16 m_nOffset; + sal_uInt16 m_nLength; + + /** Construction. + */ + ChunkDescriptor (sal_uInt32 nPosition, sal_uInt16 nCapacity) + { + m_nPage = nPosition / nCapacity; + m_nOffset = (sal_uInt16)((nPosition % nCapacity) & 0xffff); + m_nLength = nCapacity - m_nOffset; + } + }; + + /** ChunkScope. + */ + enum ChunkScope + { + SCOPE_INTERNAL, + SCOPE_EXTERNAL, + SCOPE_DIRECT, + SCOPE_SINGLE, + SCOPE_DOUBLE, + SCOPE_TRIPLE, + SCOPE_UNREACHABLE, + SCOPE_UNKNOWN + }; + + /** scope (internal). + */ + ChunkScope scope (sal_uInt32 nPosition) const + { + sal_uInt32 nCapacity = capacity(); + if (nPosition < nCapacity) + return SCOPE_INTERNAL; + else + return SCOPE_EXTERNAL; + } +}; + +/*======================================================================== + * + * OStoreDirectoryPageObject. + * + *======================================================================*/ +class OStoreDirectoryPageObject : public store::OStorePageObject +{ + typedef OStorePageObject base; + typedef OStoreDirectoryPageData page; + typedef OStoreIndirectionPageData indirect; + + typedef OStorePageDescriptor D; + +public: + /** Construction. + */ + explicit OStoreDirectoryPageObject (PageHolder const & rxPage = PageHolder()) + : OStorePageObject (rxPage) + {} + + /** External representation. + */ + virtual storeError guard (sal_uInt32 nAddr); + virtual storeError verify (sal_uInt32 nAddr) const; + + /** attrib. + */ + sal_uInt32 attrib (void) const + { + return store::ntohl(PAGE().m_aNameBlock.m_nAttrib); + } + void attrib (sal_uInt32 nAttrib) + { + PAGE().m_aNameBlock.m_nAttrib = store::htonl(nAttrib); + touch(); + } + + /** key. + */ + OStorePageKey key (void) const + { + return PAGE().m_aNameBlock.m_aKey; + } + void key (OStorePageKey const & rKey) + { + PAGE().m_aNameBlock.m_aKey = rKey; + touch(); + } + + /** path. + */ + sal_uInt32 path (void) const + { + page const & rPage = PAGE(); + const sal_Char * pszName = rPage.m_aNameBlock.m_pData; + sal_uInt32 nPath = store::ntohl(rPage.m_aNameBlock.m_aKey.m_nHigh); + return rtl_crc32 (nPath, pszName, rtl_str_getLength(pszName)); + } + + sal_Size getName (sal_Char * pBuffer, sal_Size nBufsiz) const + { + sal_Char const * pszName = PAGE().m_aNameBlock.m_pData; + sal_Size nLength = rtl_str_getLength(pszName); + memcpy (pBuffer, pszName, SAL_MIN(nLength, nBufsiz)); + return nLength; + } + + /** dataLength. + */ + sal_uInt32 dataLength (void) const + { + return store::ntohl(PAGE().m_aDataBlock.m_nDataLen); + } + void dataLength (sal_uInt32 nLength) + { + PAGE().m_aDataBlock.m_nDataLen = store::htonl(nLength); + touch(); + } + + /** direct. + */ + sal_uInt32 directLink (sal_uInt16 nIndex) const + { + return PAGE().m_aDataBlock.directLink (nIndex); + } + void directLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + PAGE().m_aDataBlock.directLink (nIndex, nAddr); + touch(); + } + + /** single indirect. + */ + sal_uInt32 singleLink (sal_uInt16 nIndex) const + { + return PAGE().m_aDataBlock.singleLink (nIndex); + } + void singleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + PAGE().m_aDataBlock.singleLink (nIndex, nAddr); + touch(); + } + + /** double indirect. + */ + sal_uInt32 doubleLink (sal_uInt16 nIndex) const + { + return PAGE().m_aDataBlock.doubleLink (nIndex); + } + void doubleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + PAGE().m_aDataBlock.doubleLink (nIndex, nAddr); + touch(); + } + + /** triple indirect. + */ + sal_uInt32 tripleLink (sal_uInt16 nIndex) const + { + return PAGE().m_aDataBlock.tripleLink (nIndex); + } + void tripleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) + { + PAGE().m_aDataBlock.tripleLink (nIndex, nAddr); + touch(); + } + + /** read (external data page). + */ + storeError read ( + sal_uInt32 nPage, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + /** write (external data page). + */ + storeError write ( + sal_uInt32 nPage, + OStoreDataPageObject &rData, + OStorePageBIOS &rBIOS); + + /** truncate (external data page). + */ + storeError truncate ( + sal_uInt32 nPage, + OStorePageBIOS &rBIOS); + +private: + /** Representation. + */ + page & PAGE() + { + page * pImpl = static_cast<page*>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "OStoreDirectoryPageObject::PAGE(): Null pointer"); + return (*pImpl); + } + page const & PAGE() const + { + page const * pImpl = static_cast<page const *>(m_xPage.get()); + OSL_PRECOND(pImpl != 0, "OStoreDirectoryPageObject::PAGE(): Null pointer"); + return (*pImpl); + } + + /** scope (external data page; private). + */ + page::ChunkScope scope ( + sal_uInt32 nPage, + page::DataBlock::LinkDescriptor &rDescr) const; + + /** truncate (external data page scope; private). + */ + storeError truncate ( + page::ChunkScope eScope, + sal_uInt16 nRemain, + OStorePageBIOS &rBIOS); +}; + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORDATA_HXX_ */ + diff --git a/store/source/stordir.cxx b/store/source/stordir.cxx new file mode 100644 index 000000000000..0b3f16da3cfb --- /dev/null +++ b/store/source/stordir.cxx @@ -0,0 +1,241 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "stordir.hxx" + +#ifndef _SAL_TYPES_H_ +#include <sal/types.h> +#endif + +#ifndef _RTL_TEXTCVT_H_ +#include <rtl/textcvt.h> +#endif +#ifndef _RTL_REF_HXX_ +#include <rtl/ref.hxx> +#endif + +#ifndef _OSL_MUTEX_HXX_ +#include <osl/mutex.hxx> +#endif + +#ifndef _STORE_TYPES_H_ +#include "store/types.h" +#endif +#ifndef _STORE_OBJECT_HXX_ +#include "object.hxx" +#endif + +#ifndef _STORE_STORBASE_HXX_ +#include "storbase.hxx" +#endif +#ifndef _STORE_STORDATA_HXX_ +#include "stordata.hxx" +#endif +#ifndef _STORE_STORPAGE_HXX_ +#include "storpage.hxx" +#endif + +using namespace store; + +/*======================================================================== + * + * OStore... internals. + * + *======================================================================*/ +/* + * __store_convertTextToUnicode. + */ +inline sal_Size __store_convertTextToUnicode ( + rtl_TextToUnicodeConverter hConverter, + const sal_Char *pSrcBuffer, sal_Size nSrcLength, + sal_Unicode *pDstBuffer, sal_Size nDstLength) +{ + sal_uInt32 nCvtInfo = 0; + sal_Size nCvtBytes = 0; + return rtl_convertTextToUnicode ( + hConverter, 0, + pSrcBuffer, nSrcLength, + pDstBuffer, nDstLength, + OSTRING_TO_OUSTRING_CVTFLAGS, + &nCvtInfo, &nCvtBytes); +} + +/*======================================================================== + * + * OStoreDirectory_Impl implementation. + * + *======================================================================*/ +const sal_uInt32 OStoreDirectory_Impl::m_nTypeId = sal_uInt32(0x89191107); + +/* + * OStoreDirectory_Impl. + */ +OStoreDirectory_Impl::OStoreDirectory_Impl (void) + : m_xManager (), + m_aDescr (0, 0, 0), + m_nPath (0), + m_hTextCvt (NULL) +{} + +/* + * ~OStoreDirectory_Impl. + */ +OStoreDirectory_Impl::~OStoreDirectory_Impl (void) +{ + if (m_xManager.is()) + { + if (m_aDescr.m_nAddr != STORE_PAGE_NULL) + m_xManager->releasePage (m_aDescr, store_AccessReadOnly); + } + rtl_destroyTextToUnicodeConverter (m_hTextCvt); +} + +/* + * isKindOf. + */ +sal_Bool SAL_CALL OStoreDirectory_Impl::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == m_nTypeId); +} + +/* + * create. + */ +storeError OStoreDirectory_Impl::create ( + OStorePageManager *pManager, + rtl_String *pPath, + rtl_String *pName, + storeAccessMode eMode) +{ + rtl::Reference<OStorePageManager> xManager (pManager); + if (!xManager.is()) + return store_E_InvalidAccess; + + if (!(pPath && pName)) + return store_E_InvalidParameter; + + OStoreDirectoryPageObject aPage; + storeError eErrCode = xManager->iget ( + aPage, STORE_ATTRIB_ISDIR, + pPath, pName, eMode); + if (eErrCode != store_E_None) + return eErrCode; + + if (!(aPage.attrib() & STORE_ATTRIB_ISDIR)) + return store_E_NotDirectory; + + inode_holder_type xNode (aPage.get()); + eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadOnly); + if (eErrCode != store_E_None) + return eErrCode; + + // Evaluate iteration path. + m_nPath = aPage.path(); + m_nPath = rtl_crc32 (m_nPath, "/", 1); + + // Save page manager, and descriptor. + m_xManager = xManager; + m_aDescr = xNode->m_aDescr; + + return store_E_None; +} + +/* + * iterate. + */ +storeError OStoreDirectory_Impl::iterate (storeFindData &rFindData) +{ + if (!m_xManager.is()) + return store_E_InvalidAccess; + + storeError eErrCode = store_E_NoMoreFiles; + if (!rFindData.m_nReserved) + return eErrCode; + + // Acquire exclusive access. + osl::MutexGuard aGuard (*m_xManager); + + // Check TextConverter. + if (m_hTextCvt == NULL) + m_hTextCvt = rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_UTF8); + + // Setup iteration key. + OStorePageKey aKey (rFindData.m_nReserved, m_nPath); + + // Iterate. + for (;;) + { + OStorePageLink aLink; + eErrCode = m_xManager->iterate (aKey, aLink, rFindData.m_nAttrib); + if (!((eErrCode == store_E_None) && (aKey.m_nHigh == store::htonl(m_nPath)))) + break; + + if (!(rFindData.m_nAttrib & STORE_ATTRIB_ISLINK)) + { + // Load page. + OStoreDirectoryPageObject aPage; + eErrCode = m_xManager->loadObjectAt (aPage, aLink.location()); + if (eErrCode == store_E_None) + { + inode_holder_type xNode (aPage.get()); + + // Setup FindData. + sal_Char *p = xNode->m_aNameBlock.m_pData; + sal_Size n = rtl_str_getLength (p); + sal_Size k = rFindData.m_nLength; + + n = __store_convertTextToUnicode ( + m_hTextCvt, p, n, + rFindData.m_pszName, STORE_MAXIMUM_NAMESIZE - 1); + if (k > n) + { + k = (k - n) * sizeof(sal_Unicode); + memset (&rFindData.m_pszName[n], 0, k); + } + + rFindData.m_nLength = n; + rFindData.m_nAttrib |= aPage.attrib(); + rFindData.m_nSize = aPage.dataLength(); + + // Leave. + rFindData.m_nReserved = store::ntohl(aKey.m_nLow); + return store_E_None; + } + } + + if (aKey.m_nLow == 0) + break; + aKey.m_nLow = store::htonl(store::ntohl(aKey.m_nLow) - 1); + } + + // Finished. + memset (&rFindData, 0, sizeof (storeFindData)); + return store_E_NoMoreFiles; +} diff --git a/store/source/stordir.hxx b/store/source/stordir.hxx new file mode 100644 index 000000000000..66dd14bd81a6 --- /dev/null +++ b/store/source/stordir.hxx @@ -0,0 +1,149 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORDIR_HXX_ +#define _STORE_STORDIR_HXX_ "$Revision: 1.1.2.2 $" + +#ifndef _SAL_TYPES_H_ +#include <sal/types.h> +#endif + +#ifndef _RTL_TEXTCVT_H_ +#include <rtl/textcvt.h> +#endif +#ifndef _RTL_STRING_H_ +#include <rtl/string.h> +#endif +#ifndef _RTL_REF_HXX_ +#include <rtl/ref.hxx> +#endif + +#ifndef _STORE_OBJECT_HXX_ +#include "object.hxx" +#endif +#ifndef _STORE_STORBASE_HXX_ +#include "storbase.hxx" +#endif +#ifndef _STORE_STORPAGE_HXX_ +#include "storpage.hxx" +#endif + +namespace store +{ + +struct OStoreDirectoryPageData; + +/*======================================================================== + * + * OStoreDirectory_Impl interface. + * + *======================================================================*/ +class OStoreDirectory_Impl : public store::OStoreObject +{ +public: + /** Construction. + */ + OStoreDirectory_Impl (void); + + /** create (two-phase construction). + * @param pManager [in] + * @param pPath [in] + * @param pName [in] + * @param eAccessMode [in] + * @return store_E_None upon success. + */ + storeError create ( + OStorePageManager *pManager, + rtl_String *pPath, + rtl_String *pName, + storeAccessMode eAccessMode); + + /** iterate. + * @param rFindData [out] + * @return store_E_None upon success, + * store_E_NoMoreFiles upon end of iteration. + */ + storeError iterate ( + storeFindData &rFindData); + + /** IStoreHandle. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId); + +protected: + /** Destruction. + */ + virtual ~OStoreDirectory_Impl (void); + +private: + /** IStoreHandle TypeId. + */ + static const sal_uInt32 m_nTypeId; + + /** IStoreHandle query() template function specialization. + */ + friend OStoreDirectory_Impl* + SAL_CALL query<> (IStoreHandle *pHandle, OStoreDirectory_Impl*); + + /** Representation. + */ + typedef OStoreDirectoryPageData inode; + typedef PageHolderObject< inode > inode_holder_type; + + rtl::Reference<OStorePageManager> m_xManager; + + OStorePageDescriptor m_aDescr; + sal_uInt32 m_nPath; + rtl_TextToUnicodeConverter m_hTextCvt; + + /** Not implemented. + */ + OStoreDirectory_Impl (const OStoreDirectory_Impl&); + OStoreDirectory_Impl& operator= (const OStoreDirectory_Impl&); +}; + +template<> inline OStoreDirectory_Impl* +SAL_CALL query (IStoreHandle *pHandle, OStoreDirectory_Impl*) +{ + if (pHandle && pHandle->isKindOf (OStoreDirectory_Impl::m_nTypeId)) + { + // Handle is kind of OStoreDirectory_Impl. + return static_cast<OStoreDirectory_Impl*>(pHandle); + } + return 0; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORDIR_HXX_ */ + diff --git a/store/source/store.cxx b/store/source/store.cxx new file mode 100644 index 000000000000..fdcce8dd2d00 --- /dev/null +++ b/store/source/store.cxx @@ -0,0 +1,765 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "store/store.h" + +#include <sal/types.h> +#include <rtl/memory.h> +#include <rtl/string.hxx> +#include <rtl/ref.hxx> + +#include "object.hxx" +#include "lockbyte.hxx" + +#include "storbase.hxx" +#include "storpage.hxx" +#include "stordir.hxx" +#include "storlckb.hxx" + +using rtl::Reference; +using rtl::OString; + +namespace store +{ +/** Template helper class as type safe Reference to store_handle_type. + */ +template<class store_handle_type> +class OStoreHandle : public rtl::Reference<store_handle_type> +{ +public: + OStoreHandle (store_handle_type * pHandle) + : rtl::Reference<store_handle_type> (pHandle) + {} + + static store_handle_type * SAL_CALL query (void * pHandle) + { + return store::query ( + static_cast<IStoreHandle*>(pHandle), + static_cast<store_handle_type*>(0)); + } +}; +} + + +using namespace store; + +/*======================================================================== + * + * storeHandle implementation. + * + *======================================================================*/ +/* + * store_acquireHandle. + */ +storeError SAL_CALL store_acquireHandle ( + storeHandle Handle +) SAL_THROW_EXTERN_C() +{ + IStoreHandle *pHandle = static_cast<IStoreHandle*>(Handle); + if (!pHandle) + return store_E_InvalidHandle; + + pHandle->acquire(); + return store_E_None; +} + +/* + * store_releaseHandle. + */ +storeError SAL_CALL store_releaseHandle ( + storeHandle Handle +) SAL_THROW_EXTERN_C() +{ + IStoreHandle *pHandle = static_cast<IStoreHandle*>(Handle); + if (!pHandle) + return store_E_InvalidHandle; + + pHandle->release(); + return store_E_None; +} + +/*======================================================================== + * + * storeFileHandle implementation. + * + *======================================================================*/ +/* + * store_createMemoryFile. + */ +storeError SAL_CALL store_createMemoryFile ( + sal_uInt16 nPageSize, + storeFileHandle *phFile +) SAL_THROW_EXTERN_C() +{ + if (!phFile) + return store_E_InvalidParameter; + *phFile = NULL; + + Reference<ILockBytes> xLockBytes; + + storeError eErrCode = MemoryLockBytes_createInstance(xLockBytes); + if (eErrCode != store_E_None) + return eErrCode; + OSL_ASSERT(xLockBytes.is()); + + Reference<OStorePageManager> xManager (new OStorePageManager()); + if (!xManager.is()) + return store_E_OutOfMemory; + + eErrCode = xManager->initialize ( + &*xLockBytes, store_AccessCreate, nPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + xManager->acquire(); + + *phFile = (storeFileHandle)&(*xManager); + return store_E_None; +} + +/* + * store_openFile. + */ +storeError SAL_CALL store_openFile ( + rtl_uString *pFilename, + storeAccessMode eAccessMode, + sal_uInt16 nPageSize, + storeFileHandle *phFile +) SAL_THROW_EXTERN_C() +{ + if (phFile) + *phFile = NULL; + + if (!(pFilename && phFile)) + return store_E_InvalidParameter; + + Reference<ILockBytes> xLockBytes; + + storeError eErrCode = FileLockBytes_createInstance (xLockBytes, pFilename, eAccessMode); + if (eErrCode != store_E_None) + return eErrCode; + OSL_ASSERT(xLockBytes.is()); + + Reference<OStorePageManager> xManager (new OStorePageManager()); + if (!xManager.is()) + return store_E_OutOfMemory; + + eErrCode = xManager->initialize ( + &*xLockBytes, eAccessMode, nPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + xManager->acquire(); + + *phFile = (storeFileHandle)&(*xManager); + return store_E_None; +} + +/* + * store_closeFile. + */ +storeError SAL_CALL store_closeFile ( + storeFileHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStorePageManager *pManager = + OStoreHandle<OStorePageManager>::query (Handle); + if (!pManager) + return store_E_InvalidHandle; + + storeError eErrCode = pManager->close(); + pManager->release(); + return eErrCode; +} + +/* + * store_flushFile. + */ +storeError SAL_CALL store_flushFile ( + storeFileHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + return xManager->flush(); +} + +/* + * store_getFileRefererCount. + */ +storeError SAL_CALL store_getFileRefererCount ( + storeFileHandle Handle, + sal_uInt32 *pnRefCount +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!pnRefCount) + return store_E_InvalidParameter; + + *pnRefCount = xManager->getRefererCount(); + return store_E_None; +} + +/* + * store_getFileSize. + */ +storeError SAL_CALL store_getFileSize ( + storeFileHandle Handle, + sal_uInt32 *pnSize +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!pnSize) + return store_E_InvalidParameter; + + return xManager->size (*pnSize); +} + +/* + * store_rebuildFile. + */ +storeError SAL_CALL store_rebuildFile ( + rtl_uString *pSrcFilename, + rtl_uString *pDstFilename +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + if (!(pSrcFilename && pDstFilename)) + return store_E_InvalidParameter; + + Reference<OStorePageManager> xManager (new OStorePageManager()); + if (!xManager.is()) + return store_E_OutOfMemory; + + Reference<ILockBytes> xSrcLB; + eErrCode = FileLockBytes_createInstance (xSrcLB, pSrcFilename, store_AccessReadOnly); + if (eErrCode != store_E_None) + return eErrCode; + OSL_ASSERT(xSrcLB.is()); + + Reference<ILockBytes> xDstLB; + eErrCode = FileLockBytes_createInstance (xDstLB, pDstFilename, store_AccessCreate); + if (eErrCode != store_E_None) + return eErrCode; + OSL_ASSERT(xDstLB.is()); + + return xManager->rebuild (&*xSrcLB, &*xDstLB); +} + +/*======================================================================== + * + * storeDirectoryHandle implementation. + * + *======================================================================*/ +/* + * store_openDirectory. + */ +storeError SAL_CALL store_openDirectory ( + storeFileHandle hFile, + rtl_uString *pPath, + rtl_uString *pName, + storeAccessMode eAccessMode, + storeDirectoryHandle *phDirectory +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + if (phDirectory) + *phDirectory = NULL; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (hFile)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pPath && pName && phDirectory)) + return store_E_InvalidParameter; + + Reference<OStoreDirectory_Impl> xDirectory (new OStoreDirectory_Impl()); + if (!xDirectory.is()) + return store_E_OutOfMemory; + + OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8); + OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8); + + eErrCode = xDirectory->create (&*xManager, aPath.pData, aName.pData, eAccessMode); + if (eErrCode != store_E_None) + return eErrCode; + + xDirectory->acquire(); + + *phDirectory = (storeDirectoryHandle)&(*xDirectory); + return store_E_None; +} + +/* + * store_closeDirectory. + */ +storeError SAL_CALL store_closeDirectory ( + storeDirectoryHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStoreDirectory_Impl *pDirectory = + OStoreHandle<OStoreDirectory_Impl>::query (Handle); + if (!pDirectory) + return store_E_InvalidHandle; + + pDirectory->release(); + return store_E_None; +} + +/* + * store_findFirst. + */ +storeError SAL_CALL store_findFirst ( + storeDirectoryHandle Handle, + storeFindData *pFindData +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreDirectory_Impl> xDirectory ( + OStoreHandle<OStoreDirectory_Impl>::query (Handle)); + if (!xDirectory.is()) + return store_E_InvalidHandle; + + if (!pFindData) + return store_E_InvalidParameter; + + // Initialize FindData. + rtl_zeroMemory (pFindData, sizeof (storeFindData)); + + // Find first. + pFindData->m_nReserved = (sal_uInt32)(~0); + return xDirectory->iterate (*pFindData); +} + +/* + * store_findNext. + */ +storeError SAL_CALL store_findNext ( + storeDirectoryHandle Handle, + storeFindData *pFindData +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreDirectory_Impl> xDirectory ( + OStoreHandle<OStoreDirectory_Impl>::query (Handle)); + if (!xDirectory.is()) + return store_E_InvalidHandle; + + if (!pFindData) + return store_E_InvalidParameter; + + // Check FindData. + if (!pFindData->m_nReserved) + return store_E_NoMoreFiles; + + // Find next. + pFindData->m_nReserved -= 1; + return xDirectory->iterate (*pFindData); +} + +/*======================================================================== + * + * storeStreamHandle implementation. + * + *======================================================================*/ +/* + * store_openStream + */ +storeError SAL_CALL store_openStream ( + storeFileHandle hFile, + rtl_uString *pPath, + rtl_uString *pName, + storeAccessMode eAccessMode, + storeStreamHandle *phStream +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + if (phStream) + *phStream = NULL; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (hFile)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pPath && pName && phStream)) + return store_E_InvalidParameter; + + Reference<OStoreLockBytes> xLockBytes (new OStoreLockBytes()); + if (!xLockBytes.is()) + return store_E_OutOfMemory; + + OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8); + OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8); + + eErrCode = xLockBytes->create (&*xManager, aPath.pData, aName.pData, eAccessMode); + if (eErrCode != store_E_None) + return eErrCode; + + xLockBytes->acquire(); + + *phStream = (storeStreamHandle)&(*xLockBytes); + return store_E_None; +} + +/* + * store_closeStream. + */ +storeError SAL_CALL store_closeStream ( + storeStreamHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStoreLockBytes *pLockBytes = + OStoreHandle<OStoreLockBytes>::query (Handle); + if (!pLockBytes) + return store_E_InvalidHandle; + + pLockBytes->release(); + return store_E_None; +} + +/* + * store_readStream. + */ +storeError SAL_CALL store_readStream ( + storeStreamHandle Handle, + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 *pnDone +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + if (!(pBuffer && pnDone)) + return store_E_InvalidParameter; + + return xLockBytes->readAt (nOffset, pBuffer, nBytes, *pnDone); +} + +/* + * store_writeStream. + */ +storeError SAL_CALL store_writeStream ( + storeStreamHandle Handle, + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 *pnDone +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + if (!(pBuffer && pnDone)) + return store_E_InvalidParameter; + + return xLockBytes->writeAt (nOffset, pBuffer, nBytes, *pnDone); +} + +/* + * store_flushStream. + */ +storeError SAL_CALL store_flushStream ( + storeStreamHandle Handle +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + return xLockBytes->flush(); +} + +/* + * store_getStreamSize. + */ +storeError SAL_CALL store_getStreamSize ( + storeStreamHandle Handle, + sal_uInt32 *pnSize +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + if (!pnSize) + return store_E_InvalidParameter; + + return xLockBytes->stat (*pnSize); +} + +/* + * store_setStreamSize. + */ +storeError SAL_CALL store_setStreamSize ( + storeStreamHandle Handle, + sal_uInt32 nSize +) SAL_THROW_EXTERN_C() +{ + OStoreHandle<OStoreLockBytes> xLockBytes ( + OStoreHandle<OStoreLockBytes>::query (Handle)); + if (!xLockBytes.is()) + return store_E_InvalidHandle; + + return xLockBytes->setSize (nSize); +} + +/*======================================================================== + * + * Common storeDirectoryHandle and storeStreamHandle operations. + * + *======================================================================*/ +/* + * store_attrib. + */ +storeError SAL_CALL store_attrib ( + storeFileHandle Handle, + rtl_uString *pPath, + rtl_uString *pName, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 *pnAttrib +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + if (pnAttrib) + *pnAttrib = 0; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pPath && pName)) + return store_E_InvalidParameter; + + // Setup page key. + OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8); + OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aKey; + + eErrCode = OStorePageManager::namei (aPath.pData, aName.pData, aKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Obtain or modify page attributes. + sal_uInt32 nAttrib = 0; + eErrCode = xManager->attrib (aKey, nMask1, nMask2, nAttrib); + if (pnAttrib) + *pnAttrib = nAttrib; + return eErrCode; +} + +/* + * store_link. + */ +storeError SAL_CALL store_link ( + storeFileHandle Handle, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pSrcPath && pSrcName)) + return store_E_InvalidParameter; + + if (!(pDstPath && pDstName)) + return store_E_InvalidParameter; + + // Setup 'Source' page key. + OString aSrcPath ( + pSrcPath->buffer, pSrcPath->length, RTL_TEXTENCODING_UTF8); + OString aSrcName ( + pSrcName->buffer, pSrcName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aSrcKey; + + eErrCode = OStorePageManager::namei ( + aSrcPath.pData, aSrcName.pData, aSrcKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Setup 'Destination' page key. + OString aDstPath ( + pDstPath->buffer, pDstPath->length, RTL_TEXTENCODING_UTF8); + OString aDstName ( + pDstName->buffer, pDstName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aDstKey; + + eErrCode = OStorePageManager::namei ( + aDstPath.pData, aDstName.pData, aDstKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Link 'Source' hard to 'Destination'. + return xManager->link (aSrcKey, aDstKey); +} + +/* + * store_symlink. + */ +storeError SAL_CALL store_symlink ( + storeFileHandle Handle, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pSrcPath && pSrcName)) + return store_E_InvalidParameter; + + if (!(pDstPath && pDstName)) + return store_E_InvalidParameter; + + // Setup 'Destination' page key. + OString aDstPath ( + pDstPath->buffer, pDstPath->length, RTL_TEXTENCODING_UTF8); + OString aDstName ( + pDstName->buffer, pDstName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aDstKey; + + eErrCode = OStorePageManager::namei ( + aDstPath.pData, aDstName.pData, aDstKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert 'Source' as symlink to 'Destination'. + OString aSrcPath ( + pSrcPath->buffer, pSrcPath->length, RTL_TEXTENCODING_UTF8); + OString aSrcName ( + pSrcName->buffer, pSrcName->length, RTL_TEXTENCODING_UTF8); + + return xManager->symlink (aSrcPath.pData, aSrcName.pData, aDstKey); +} + +/* + * store_rename. + */ +storeError SAL_CALL store_rename ( + storeFileHandle Handle, + rtl_uString *pSrcPath, rtl_uString *pSrcName, + rtl_uString *pDstPath, rtl_uString *pDstName +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pSrcPath && pSrcName)) + return store_E_InvalidParameter; + + if (!(pDstPath && pDstName)) + return store_E_InvalidParameter; + + // Setup 'Source' page key. + OString aSrcPath ( + pSrcPath->buffer, pSrcPath->length, RTL_TEXTENCODING_UTF8); + OString aSrcName ( + pSrcName->buffer, pSrcName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aSrcKey; + + eErrCode = OStorePageManager::namei ( + aSrcPath.pData, aSrcName.pData, aSrcKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Rename 'Source' into 'Destination'. + OString aDstPath ( + pDstPath->buffer, pDstPath->length, RTL_TEXTENCODING_UTF8); + OString aDstName ( + pDstName->buffer, pDstName->length, RTL_TEXTENCODING_UTF8); + + return xManager->rename (aSrcKey, aDstPath.pData, aDstName.pData); +} + +/* + * store_remove. + */ +storeError SAL_CALL store_remove ( + storeFileHandle Handle, + rtl_uString *pPath, + rtl_uString *pName +) SAL_THROW_EXTERN_C() +{ + storeError eErrCode = store_E_None; + + OStoreHandle<OStorePageManager> xManager ( + OStoreHandle<OStorePageManager>::query (Handle)); + if (!xManager.is()) + return store_E_InvalidHandle; + + if (!(pPath && pName)) + return store_E_InvalidParameter; + + // Setup page key. + OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8); + OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8); + OStorePageKey aKey; + + eErrCode = OStorePageManager::namei (aPath.pData, aName.pData, aKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Remove. + return xManager->remove (aKey); +} diff --git a/store/source/storlckb.cxx b/store/source/storlckb.cxx new file mode 100644 index 000000000000..5a02131d53eb --- /dev/null +++ b/store/source/storlckb.cxx @@ -0,0 +1,451 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storlckb.hxx" + +#include "sal/types.h" +#include "sal/macros.h" +#include "rtl/string.h" +#include "rtl/ref.hxx" +#include "osl/mutex.hxx" + +#include "store/types.h" +#include "object.hxx" + +#include "storbase.hxx" +#include "stordata.hxx" +#include "storpage.hxx" + +using namespace store; + +/*======================================================================== + * + * OStoreLockBytes implementation. + * + *======================================================================*/ +const sal_uInt32 OStoreLockBytes::m_nTypeId = sal_uInt32(0x94190310); + +/* + * OStoreLockBytes. + */ +OStoreLockBytes::OStoreLockBytes (void) + : m_xManager (), + m_xNode (), + m_bWriteable (false) +{ +} + +/* + * ~OStoreLockBytes. + */ +OStoreLockBytes::~OStoreLockBytes (void) +{ + if (m_xManager.is()) + { + if (m_xNode.is()) + { + OStorePageDescriptor aDescr (m_xNode->m_aDescr); + if (m_bWriteable) + m_xManager->releasePage (aDescr, store_AccessReadWrite); + else + m_xManager->releasePage (aDescr, store_AccessReadOnly); + } + } +} + +/* + * isKindOf. + */ +sal_Bool SAL_CALL OStoreLockBytes::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == m_nTypeId); +} + +/* + * create. + */ +storeError OStoreLockBytes::create ( + OStorePageManager *pManager, + rtl_String *pPath, + rtl_String *pName, + storeAccessMode eMode) +{ + rtl::Reference<OStorePageManager> xManager (pManager); + if (!xManager.is()) + return store_E_InvalidAccess; + + if (!(pPath && pName)) + return store_E_InvalidParameter; + + OStoreDirectoryPageObject aPage; + storeError eErrCode = xManager->iget ( + aPage, STORE_ATTRIB_ISFILE, + pPath, pName, eMode); + if (eErrCode != store_E_None) + return eErrCode; + + if (!(aPage.attrib() & STORE_ATTRIB_ISFILE)) + { + // No ISFILE in older versions (backward compatibility). + if (aPage.attrib() & STORE_ATTRIB_ISLINK) + return store_E_NotFile; + } + + // ... + inode_holder_type xNode (aPage.get()); + if (eMode != store_AccessReadOnly) + eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadWrite); + else + eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadOnly); + if (eErrCode != store_E_None) + return eErrCode; + + // ... + m_xManager = xManager; + m_xNode = xNode; + m_bWriteable = (eMode != store_AccessReadOnly); + + // Check for truncation. + if (eMode == store_AccessCreate) + { + // Truncate to zero length. + eErrCode = setSize(0); + } + return eErrCode; +} + +/* + * readAt. + */ +storeError OStoreLockBytes::readAt ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone) +{ + rnDone = 0; + + if (!m_xManager.is()) + return store_E_InvalidAccess; + + if (!pBuffer) + return store_E_InvalidParameter; + if (!nBytes) + return store_E_None; + + // Acquire exclusive access. + osl::MutexGuard aGuard (*m_xManager); + + // Determine data length. + OStoreDirectoryPageObject aPage (m_xNode.get()); + + sal_uInt32 nDataLen = aPage.dataLength(); + if ((nOffset + nBytes) > nDataLen) + nBytes = nDataLen - nOffset; + + // Read data. + OStoreDataPageObject aData; + sal_uInt8 *pData = (sal_uInt8*)pBuffer; + while ((0 < nBytes) && (nOffset < nDataLen)) + { + // Determine 'Offset' scope. + inode::ChunkScope eScope = m_xNode->scope (nOffset); + if (eScope == inode::SCOPE_INTERNAL) + { + // Read from inode page (internal scope). + inode::ChunkDescriptor aDescr ( + nOffset, m_xNode->capacity()); + + sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); + nLength = SAL_MIN(nLength, nBytes); + + memcpy ( + &pData[rnDone], + &m_xNode->m_pData[aDescr.m_nOffset], + nLength); + + // Adjust counters. + rnDone += nLength; + nOffset += nLength; + nBytes -= nLength; + } + else + { + // Read from data page (external scope). + inode::ChunkDescriptor aDescr ( + nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ + + sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); + nLength = SAL_MIN(nLength, nBytes); + + storeError eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_NotExists) + return eErrCode; + + memset ( + &pData[rnDone], + 0, + nLength); + } + else + { + PageHolderObject< data > xData (aData.makeHolder<data>()); + memcpy ( + &pData[rnDone], + &xData->m_pData[aDescr.m_nOffset], + nLength); + } + + // Adjust counters. + rnDone += nLength; + nOffset += nLength; + nBytes -= nLength; + } + } + + // Done. + return store_E_None; +} + +/* + * writeAt. + */ +storeError OStoreLockBytes::writeAt ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone) +{ + rnDone = 0; + + if (!m_xManager.is()) + return store_E_InvalidAccess; + if (!m_bWriteable) + return store_E_AccessViolation; + + if (!pBuffer) + return store_E_InvalidParameter; + if (!nBytes) + return store_E_None; + + // Acquire exclusive access. + osl::MutexGuard aGuard (*m_xManager); + + // Write data. + OStoreDirectoryPageObject aPage (m_xNode.get()); + const sal_uInt8 *pData = (const sal_uInt8*)pBuffer; + + storeError eErrCode = store_E_None; + while (nBytes > 0) + { + // Determine 'Offset' scope. + inode::ChunkScope eScope = m_xNode->scope (nOffset); + if (eScope == inode::SCOPE_INTERNAL) + { + // Write to inode page (internal scope). + inode::ChunkDescriptor aDescr ( + nOffset, m_xNode->capacity()); + + sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); + nLength = SAL_MIN(nLength, nBytes); + + memcpy ( + &m_xNode->m_pData[aDescr.m_nOffset], + &pData[rnDone], nLength); + + // Mark inode dirty. + aPage.touch(); + + // Adjust counters. + rnDone += nLength; + nOffset += nLength; + nBytes -= nLength; + + // Adjust data length. + if (aPage.dataLength() < nOffset) + aPage.dataLength (nOffset); + } + else + { + // Write to data page (external scope). + OStoreDataPageObject aData; + + inode::ChunkDescriptor aDescr ( + nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ + + sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); + if ((aDescr.m_nOffset > 0) || (nBytes < nLength)) + { + // Unaligned. Need to load/create data page. +// @@@ loadOrCreate() + eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_NotExists) + return eErrCode; + + eErrCode = aData.construct<data>(m_xManager->allocator()); + if (eErrCode != store_E_None) + return eErrCode; + } + } + + PageHolderObject< data > xData (aData.makeHolder<data>()); + if (!xData.is()) + { + eErrCode = aData.construct<data>(m_xManager->allocator()); + if (eErrCode != store_E_None) + return eErrCode; + xData = aData.makeHolder<data>(); + } + + // Modify data page. + nLength = SAL_MIN(nLength, nBytes); + memcpy ( + &xData->m_pData[aDescr.m_nOffset], + &pData[rnDone], nLength); + + // Save data page. + eErrCode = aPage.write (aDescr.m_nPage, aData, *m_xManager); + if (eErrCode != store_E_None) + return eErrCode; + + // Adjust counters. + rnDone += nLength; + nOffset += nLength; + nBytes -= nLength; + + // Adjust data length. + if (aPage.dataLength() < nOffset) + aPage.dataLength (nOffset); + } + } + + // Check for modified inode. + if (aPage.dirty()) + return m_xManager->saveObjectAt (aPage, aPage.location()); + else + return store_E_None; +} + +/* + * flush. + */ +storeError OStoreLockBytes::flush (void) +{ + if (!m_xManager.is()) + return store_E_InvalidAccess; + + return m_xManager->flush(); +} + +/* + * setSize. + */ +storeError OStoreLockBytes::setSize (sal_uInt32 nSize) +{ + if (!m_xManager.is()) + return store_E_InvalidAccess; + if (!m_bWriteable) + return store_E_AccessViolation; + + // Acquire exclusive access. + osl::MutexGuard aGuard (*m_xManager); + + // Determine current length. + OStoreDirectoryPageObject aPage (m_xNode.get()); + sal_uInt32 nDataLen = aPage.dataLength(); + + if (nSize == nDataLen) + return store_E_None; + + if (nSize < nDataLen) + { + // Truncate. + storeError eErrCode = store_E_None; + + // Determine 'Size' scope. + inode::ChunkScope eSizeScope = m_xNode->scope (nSize); + if (eSizeScope == inode::SCOPE_INTERNAL) + { + // Internal 'Size' scope. Determine 'Data' scope. + inode::ChunkScope eDataScope = m_xNode->scope (nDataLen); + if (eDataScope == inode::SCOPE_EXTERNAL) + { + // External 'Data' scope. Truncate all external data pages. + eErrCode = aPage.truncate (0, *m_xManager); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Truncate internal data page. + inode::ChunkDescriptor aDescr (nSize, m_xNode->capacity()); + memset ( + &(m_xNode->m_pData[aDescr.m_nOffset]), + 0, aDescr.m_nLength); + } + else + { + // External 'Size' scope. Truncate external data pages. + inode::ChunkDescriptor aDescr ( + nSize - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ + + sal_uInt32 nPage = aDescr.m_nPage; + if (aDescr.m_nOffset) nPage += 1; + + eErrCode = aPage.truncate (nPage, *m_xManager); + if (eErrCode != store_E_None) + return eErrCode; + } + } + + // Set (extended or truncated) size. + aPage.dataLength (nSize); + + // Save modified inode. + return m_xManager->saveObjectAt (aPage, aPage.location()); +} + +/* + * stat. + */ +storeError OStoreLockBytes::stat (sal_uInt32 &rnSize) +{ + rnSize = 0; + + if (!m_xManager.is()) + return store_E_InvalidAccess; + + OStoreDirectoryPageObject aPage (m_xNode.get()); + rnSize = aPage.dataLength(); + return store_E_None; +} diff --git a/store/source/storlckb.hxx b/store/source/storlckb.hxx new file mode 100644 index 000000000000..fd6ef7384613 --- /dev/null +++ b/store/source/storlckb.hxx @@ -0,0 +1,171 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORLCKB_HXX_ +#define _STORE_STORLCKB_HXX_ "$Revision: 1.6.8.1 $" + +#include "sal/types.h" + +#include "rtl/ustring.h" +#include "rtl/ref.hxx" + +#include "object.hxx" +#include "storbase.hxx" +#include "storpage.hxx" + +namespace store +{ + +struct OStoreDataPageData; +struct OStoreDirectoryPageData; + +/*======================================================================== + * + * OStoreLockBytes interface. + * + *======================================================================*/ +class OStoreLockBytes : public store::OStoreObject +{ +public: + /** Construction. + */ + OStoreLockBytes (void); + + /** create (two-phase construction). + * @param pManager [in] + * @param pPath [in] + * @param pName [in] + * @param eMode [in] + * @return store_E_None upon success + */ + storeError create ( + OStorePageManager *pManager, + rtl_String *pPath, + rtl_String *pName, + storeAccessMode eAccessMode); + + /** Read at Offset into Buffer. + * @param nOffset [in] + * @param pBuffer [out] + * @param nBytes [in] + * @param rnDone [out] + * @return store_E_None upon success + */ + storeError readAt ( + sal_uInt32 nOffset, + void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone); + + /** Write at Offset from Buffer. + * @param nOffset [in] + * @param pBuffer [in] + * @param nBytes [in] + * @param rnDone [out] + * @return store_E_None upon success + */ + storeError writeAt ( + sal_uInt32 nOffset, + const void *pBuffer, + sal_uInt32 nBytes, + sal_uInt32 &rnDone); + + /** flush. + * @return store_E_None upon success + */ + storeError flush (void); + + /** setSize. + * @param nSize [in] + * @return store_E_None upon success + */ + storeError setSize (sal_uInt32 nSize); + + /** stat. + * @paran rnSize [out] + * @return store_E_None upon success + */ + storeError stat (sal_uInt32 &rnSize); + + /** IStoreHandle. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nMagic); + +protected: + /** Destruction (OReference). + */ + virtual ~OStoreLockBytes (void); + +private: + /** IStoreHandle TypeId. + */ + static const sal_uInt32 m_nTypeId; + + /** IStoreHandle query() template specialization. + */ + friend OStoreLockBytes* + SAL_CALL query<> (IStoreHandle *pHandle, OStoreLockBytes*); + + /** Representation. + */ + rtl::Reference<OStorePageManager> m_xManager; + + typedef OStoreDataPageData data; + typedef OStoreDirectoryPageData inode; + + typedef PageHolderObject< inode > inode_holder_type; + inode_holder_type m_xNode; + + bool m_bWriteable; + + /** Not implemented. + */ + OStoreLockBytes (const OStoreLockBytes&); + OStoreLockBytes& operator= (const OStoreLockBytes&); +}; + +template<> inline OStoreLockBytes* +SAL_CALL query (IStoreHandle *pHandle, OStoreLockBytes*) +{ + if (pHandle && pHandle->isKindOf (OStoreLockBytes::m_nTypeId)) + { + // Handle is kind of OStoreLockBytes. + return static_cast<OStoreLockBytes*>(pHandle); + } + return 0; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORLCKB_HXX_ */ + diff --git a/store/source/storpage.cxx b/store/source/storpage.cxx new file mode 100644 index 000000000000..a49e850061b6 --- /dev/null +++ b/store/source/storpage.cxx @@ -0,0 +1,1057 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "storpage.hxx" + +#include "sal/types.h" +#include "rtl/string.h" +#include "rtl/ref.hxx" +#include "osl/diagnose.h" +#include "osl/mutex.hxx" + +#include "store/types.h" + +#include "object.hxx" +#include "lockbyte.hxx" + +#include "storbase.hxx" +#include "stordata.hxx" +#include "stortree.hxx" + +using namespace store; + +/*======================================================================== + * + * OStorePageManager implementation. + * + *======================================================================*/ +const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120); + +/* + * OStorePageManager. + */ +OStorePageManager::OStorePageManager (void) +{ +} + +/* + * ~OStorePageManager. + */ +OStorePageManager::~OStorePageManager (void) +{ +} + +/* + * isKindOf. + */ +sal_Bool SAL_CALL OStorePageManager::isKindOf (sal_uInt32 nTypeId) +{ + return (nTypeId == m_nTypeId); +} + +/* + * initialize (two-phase construction). + * Precond: none. + */ +storeError OStorePageManager::initialize ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check arguments. + if (!pLockBytes) + return store_E_InvalidParameter; + + // Initialize base. + storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for (not) writeable. + if (!base::isWriteable()) + { + // Readonly. Load RootNode. + return base::loadObjectAt (m_aRoot, rnPageSize); + } + + // Writeable. Load or Create RootNode. + eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this); + if (eErrCode == store_E_Pending) + { + // Creation notification. + PageHolderObject< page > xRoot (m_aRoot.get()); + + // Pre-allocate left most entry (ugly, but we can't insert to left). + OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0); + xRoot->insert (0, entry(aKey)); + + // Save RootNode. + eErrCode = base::saveObjectAt (m_aRoot, rnPageSize); + } + + // Done. + return eErrCode; +} + +/* + * find_lookup (w/o split()). + * Internal: Precond: initialized, readable, exclusive access. + */ +storeError OStorePageManager::find_lookup ( + OStoreBTreeNodeObject & rNode, + sal_uInt16 & rIndex, + OStorePageKey const & rKey) +{ + // Find Node and Index. + storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // Greater or Equal. + PageHolderObject< page > xPage (rNode.get()); + OSL_POSTCOND(rIndex < xPage->usageCount(), "store::PageManager::find_lookup(): logic error"); + entry e (xPage->m_pData[rIndex]); + + // Check for exact match. + if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL) + { + // Page not present. + return store_E_NotExists; + } + + // Check address. + if (e.m_aLink.location() == STORE_PAGE_NULL) + { + // Page not present. + return store_E_NotExists; + } + + return store_E_None; +} + +/* + * remove_Impl (possibly down from root). + * Internal: Precond: initialized, writeable, exclusive access. + */ +#if 0 /* EXP */ +storeError OStorePageManager::remove_Impl (entry & rEntry) +{ + // Find Node and Index. + OStoreBTreeNodeObject aNode; + sal_uInt16 nIndex = 0; + eErrCode = m_aRoot.find_lookup (aNode, nIndex, entry::CompareGreater(rEntry), *this); + + // @@@ + + PageHolderObject< page > xPage (aNode.get()); + page & rPage = (*xPage); + + // Check current page index. + sal_uInt16 i = rPage.find (rEntry), n = rPage.usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Compare entry. + entry::CompareResult result = rEntry.compare (rPage.m_pData[i]); + + for (; result == entry::COMPARE_GREATER && xPage->depth() > 0; ) + { + // Check next node address. + sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location(); + if (nAddr == STORE_PAGE_NULL) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Load next node page. + eErrCode = loadObjectAt (aNode, nAddr); + + PageHolderObject< page > xNext (aNode.get()); + xNext.swap (xPage); + } + + aNode.remove (nIndex, rEntry, *this); + + + do + { + // Load next node page. + eErrCode = loadObjectAt (aNode, nAddr); + + page const & rPage = (*xPage); + + // Check current page index. + sal_uInt16 i = rPage.find (rEntry), n = rPage.usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Compare entry. + result = rEntry.compare (rPage.m_pData[i]); + + } while (result == entry::COMPATE_GREATER); +} +#endif /* EXP */ + +storeError OStorePageManager::remove_Impl (entry & rEntry) +{ + OStoreBTreeNodeObject aNode (m_aRoot.get()); + + // Check current page index. + PageHolderObject< page > xPage (aNode.get()); + sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Compare entry. + entry::CompareResult result = rEntry.compare (xPage->m_pData[i]); + + // Iterate down until equal match. + while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0)) + { + // Check link address. + sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location(); + if (nAddr == STORE_PAGE_NULL) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Load link page. + storeError eErrCode = loadObjectAt (aNode, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + PageHolderObject< page > xNext (aNode.get()); + xNext.swap (xPage); + + // Check index. + i = xPage->find (rEntry), n = xPage->usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Compare entry. + result = rEntry.compare (xPage->m_pData[i]); + } + + OSL_POSTCOND( + result != entry::COMPARE_LESS, + "OStorePageManager::remove(): find failed"); + + // Check entry comparison. + if (result == entry::COMPARE_LESS) + { + // Must not happen. + return store_E_Unknown; + } + + // Remove down from current page (recursive). + return aNode.remove (i, rEntry, *this); +} + +/* + * namei. + * Precond: none (static). + */ +storeError OStorePageManager::namei ( + const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey) +{ + // Check parameter. + if (!(pPath && pName)) + return store_E_InvalidParameter; + + // Check name length. + if (!(pName->length < STORE_MAXIMUM_NAMESIZE)) + return store_E_NameTooLong; + + // Transform pathname into key. + rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length)); + rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length)); + + // Done. + return store_E_None; +} + +/* + * iget. + * Precond: initialized. + */ +storeError OStorePageManager::iget ( + OStoreDirectoryPageObject & rPage, + sal_uInt32 nAttrib, + const rtl_String * pPath, + const rtl_String * pName, + storeAccessMode eMode) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + // Setup inode page key. + OStorePageKey aKey; + storeError eErrCode = namei (pPath, pName, aKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for directory. + if (nAttrib & STORE_ATTRIB_ISDIR) + { + // Ugly, but necessary (backward compatibility). + aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1)); + } + + // Load inode page. + eErrCode = load_dirpage_Impl (aKey, rPage); + if (eErrCode != store_E_None) + { + // Check mode and reason. + if (eErrCode != store_E_NotExists) + return eErrCode; + + if (eMode == store_AccessReadWrite) + return store_E_NotExists; + if (eMode == store_AccessReadOnly) + return store_E_NotExists; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Create inode page. + eErrCode = rPage.construct< inode >(base::allocator()); + if (eErrCode != store_E_None) + return eErrCode; + + // Setup inode nameblock. + PageHolderObject< inode > xPage (rPage.get()); + + rPage.key (aKey); + rPage.attrib (nAttrib); + + memcpy ( + &(xPage->m_aNameBlock.m_pData[0]), + pName->buffer, pName->length); + + // Save inode page. + eErrCode = save_dirpage_Impl (aKey, rPage); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Check for symbolic link. + if (rPage.attrib() & STORE_ATTRIB_ISLINK) + { + // Obtain 'Destination' page key. + PageHolderObject< inode > xPage (rPage.get()); + OStorePageKey aDstKey; + memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey)); + + // Load 'Destination' inode. + eErrCode = load_dirpage_Impl (aDstKey, rPage); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Done. + return store_E_None; +} + +/* + * iterate. + * Precond: initialized. + * ToDo: skip hardlink entries. + */ +storeError OStorePageManager::iterate ( + OStorePageKey & rKey, + OStorePageLink & rLink, + sal_uInt32 & rAttrib) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + // Find NodePage and Index. + OStoreBTreeNodeObject aNode; + sal_uInt16 i = 0; + storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // GreaterEqual. Found next entry. + PageHolderObject< page > xNode (aNode.get()); + entry e (xNode->m_pData[i]); + + // Setup result. + rKey = e.m_aKey; + rLink = e.m_aLink; + rAttrib = store::ntohl(e.m_nAttrib); + + // Done. + return store_E_None; +} + +/* + * load => private: iget() @@@ + * Internal: Precond: initialized, exclusive access. + */ +storeError OStorePageManager::load_dirpage_Impl ( + const OStorePageKey &rKey, + OStoreDirectoryPageObject &rPage) +{ + // Find Node and Index. + OStoreBTreeNodeObject aNode; + sal_uInt16 i = 0; + storeError eErrCode = find_lookup (aNode, i, rKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing entry. Load page. + PageHolderObject< page > xNode (aNode.get()); + entry e (xNode->m_pData[i]); + return loadObjectAt (rPage, e.m_aLink.location()); +} + +/* + * save => private: iget(), rebuild() @@@ + * Internal: Precond: initialized, writeable, exclusive access. + */ +storeError OStorePageManager::save_dirpage_Impl ( + const OStorePageKey &rKey, + OStoreDirectoryPageObject &rPage) +{ + // Find NodePage and Index. + node aNode; + sal_uInt16 i = 0; + + storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this); + PageHolderObject< page > xNode (aNode.get()); + if (eErrCode != store_E_None) + { + if (eErrCode != store_E_AlreadyExists) + return eErrCode; + + // Existing entry. + entry e (xNode->m_pData[i]); + if (e.m_aLink.location() != STORE_PAGE_NULL) + { + // Save page to existing location. + return saveObjectAt (rPage, e.m_aLink.location()); + } + + // Allocate page. + eErrCode = base::allocate (rPage); + if (eErrCode != store_E_None) + return eErrCode; + + // Update page location. + xNode->m_pData[i].m_aLink = rPage.location(); + + // Save modified NodePage. + return saveObjectAt (aNode, aNode.location()); + } + + // Allocate page. + eErrCode = base::allocate (rPage); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert. + OStorePageLink aLink (rPage.location()); + xNode->insert (i + 1, entry (rKey, aLink)); + + // Save modified NodePage. + return saveObjectAt (aNode, aNode.location()); +} + +/* + * attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)]. + * Precond: initialized. + */ +storeError OStorePageManager::attrib ( + const OStorePageKey &rKey, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 &rAttrib) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + // Find NodePage and index. + OStoreBTreeNodeObject aNode; + sal_uInt16 i = 0; + storeError eErrCode = find_lookup (aNode, i, rKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing entry. + PageHolderObject< page > xNode (aNode.get()); + entry e (xNode->m_pData[i]); + if (nMask1 != nMask2) + { + // Evaluate new attributes. + sal_uInt32 nAttrib = store::ntohl(e.m_nAttrib); + + nAttrib &= ~nMask1; + nAttrib |= nMask2; + + if (store::htonl(nAttrib) != e.m_nAttrib) + { + // Check access mode. + if (base::isWriteable()) + { + // Set new attributes. + e.m_nAttrib = store::htonl(nAttrib); + xNode->m_pData[i] = e; + + // Save modified NodePage. + eErrCode = saveObjectAt (aNode, aNode.location()); + } + else + { + // Access denied. + eErrCode = store_E_AccessViolation; + } + } + } + + // Obtain current attributes. + rAttrib = store::ntohl(e.m_nAttrib); + return eErrCode; +} + +/* + * link (insert 'Source' as hardlink to 'Destination'). + * Precond: initialized, writeable. + */ +storeError OStorePageManager::link ( + const OStorePageKey &rSrcKey, + const OStorePageKey &rDstKey) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Find 'Destination' NodePage and Index. + OStoreBTreeNodeObject aDstNode; + sal_uInt16 i = 0; + storeError eErrCode = find_lookup (aDstNode, i, rDstKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing 'Destination' entry. + PageHolderObject< page > xDstNode (aDstNode.get()); + entry e (xDstNode->m_pData[i]); + OStorePageLink aDstLink (e.m_aLink); + + // Find 'Source' NodePage and Index. + OStoreBTreeNodeObject aSrcNode; + eErrCode = m_aRoot.find_insert (aSrcNode, i, rSrcKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert 'Source' entry. + PageHolderObject< page > xSrcNode (aSrcNode.get()); + xSrcNode->insert (i + 1, entry (rSrcKey, aDstLink, STORE_ATTRIB_ISLINK)); + return saveObjectAt (aSrcNode, aSrcNode.location()); +} + +/* + * symlink (insert 'Source' DirectoryPage as symlink to 'Destination'). + * Precond: initialized, writeable. + */ +storeError OStorePageManager::symlink ( + const rtl_String *pSrcPath, + const rtl_String *pSrcName, + const OStorePageKey &rDstKey) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Check 'Source' parameter. + storeError eErrCode = store_E_InvalidParameter; + if (!(pSrcPath && pSrcName)) + return eErrCode; + + // Setup 'Source' page key. + OStorePageKey aSrcKey; + eErrCode = namei (pSrcPath, pSrcName, aSrcKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Find 'Source' NodePage and Index. + OStoreBTreeNodeObject aSrcNode; + sal_uInt16 i = 0; + eErrCode = m_aRoot.find_insert (aSrcNode, i, aSrcKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // Initialize directory page. + OStoreDirectoryPageObject aPage; + eErrCode = aPage.construct< inode >(base::allocator()); + if (eErrCode != store_E_None) + return eErrCode; + + // Setup as 'Source' directory page. + inode_holder_type xNode (aPage.get()); + aPage.key (aSrcKey); + memcpy ( + &(xNode->m_aNameBlock.m_pData[0]), + pSrcName->buffer, pSrcName->length); + + // Store 'Destination' page key. + OStorePageKey aDstKey (rDstKey); + memcpy (&(xNode->m_pData[0]), &aDstKey, sizeof(aDstKey)); + + // Mark 'Source' as symbolic link to 'Destination'. + aPage.attrib (STORE_ATTRIB_ISLINK); + aPage.dataLength (sal_uInt32(sizeof(aDstKey))); + + // Allocate and save 'Source' directory page. + eErrCode = base::allocate (aPage); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert 'Source' entry. + PageHolderObject< page > xSrcNode (aSrcNode.get()); + OStorePageLink aSrcLink (aPage.location()); + xSrcNode->insert (i + 1, entry(aSrcKey, aSrcLink)); + + // Save modified NodePage. + return saveObjectAt (aSrcNode, aSrcNode.location()); +} + +/* + * rename. + * Precond: initialized, writeable. + */ +storeError OStorePageManager::rename ( + const OStorePageKey &rSrcKey, + const rtl_String *pDstPath, + const rtl_String *pDstName) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Check 'Destination' parameter. + storeError eErrCode = store_E_InvalidParameter; + if (!(pDstPath && pDstName)) + return eErrCode; + + // Setup 'Destination' page key. + OStorePageKey aDstKey; + eErrCode = namei (pDstPath, pDstName, aDstKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Find 'Source' NodePage and Index. + OStoreBTreeNodeObject aSrcNode; + sal_uInt16 i = 0; + eErrCode = find_lookup (aSrcNode, i, rSrcKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing 'Source' entry. + PageHolderObject< page > xSrcNode (aSrcNode.get()); + entry e (xSrcNode->m_pData[i]); + + // Check for (not a) hardlink. + OStoreDirectoryPageObject aPage; + if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK)) + { + // Load directory page. + eErrCode = base::loadObjectAt (aPage, e.m_aLink.location()); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for directory. + if (aPage.attrib() & STORE_ATTRIB_ISDIR) + { + // Ugly, but necessary (backward compatibility). + aDstKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aDstKey.m_nLow), "/", 1)); + } + } + + // Let 'Source' entry be 'Destination' entry. + e.m_aKey = aDstKey; + + // Find 'Destination' NodePage and Index. + OStoreBTreeNodeObject aDstNode; + eErrCode = m_aRoot.find_insert (aDstNode, i, e.m_aKey, *this); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert 'Destination' entry. + PageHolderObject< page > xDstNode (aDstNode.get()); + xDstNode->insert (i + 1, e); + + eErrCode = saveObjectAt (aDstNode, aDstNode.location()); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for (not a) hardlink. + if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK)) + { + // Modify 'Source' directory page. + inode_holder_type xNode (aPage.get()); + + // Setup 'Destination' NameBlock. + sal_Int32 nDstLen = pDstName->length; + memcpy ( + &(xNode->m_aNameBlock.m_pData[0]), + pDstName->buffer, pDstName->length); + memset ( + &(xNode->m_aNameBlock.m_pData[nDstLen]), + 0, STORE_MAXIMUM_NAMESIZE - nDstLen); + aPage.key (e.m_aKey); + + // Save directory page. + eErrCode = base::saveObjectAt (aPage, e.m_aLink.location()); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Remove 'Source' entry. + e.m_aKey = rSrcKey; + return remove_Impl (e); +} + +/* + * remove. + * Precond: initialized, writeable. + */ +storeError OStorePageManager::remove (const OStorePageKey &rKey) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check precond. + if (!self::isValid()) + return store_E_InvalidAccess; + + if (!base::isWriteable()) + return store_E_AccessViolation; + + // Find NodePage and index. + OStoreBTreeNodeObject aNodePage; + sal_uInt16 i = 0; + storeError eErrCode = find_lookup (aNodePage, i, rKey); + if (eErrCode != store_E_None) + return eErrCode; + + // Existing entry. + PageHolderObject< page > xNodePage (aNodePage.get()); + entry e (xNodePage->m_pData[i]); + + // Check for (not a) hardlink. + if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK)) + { + // Load directory page. + OStoreDirectoryPageObject aPage; + eErrCode = base::loadObjectAt (aPage, e.m_aLink.location()); + if (eErrCode != store_E_None) + return eErrCode; + + inode_holder_type xNode (aPage.get()); + + // Acquire page write access. + OStorePageDescriptor aDescr (xNode->m_aDescr); + eErrCode = base::acquirePage (aDescr, store_AccessReadWrite); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for symbolic link. + if (!(aPage.attrib() & STORE_ATTRIB_ISLINK)) + { + // Ordinary inode. Determine 'Data' scope. + inode::ChunkScope eScope = xNode->scope (aPage.dataLength()); + if (eScope == inode::SCOPE_EXTERNAL) + { + // External 'Data' scope. Truncate all external data pages. + eErrCode = aPage.truncate (0, *this); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Truncate internal data page. + memset (&(xNode->m_pData[0]), 0, xNode->capacity()); + aPage.dataLength (0); + } + + // Release page write access. + eErrCode = base::releasePage (aDescr, store_AccessReadWrite); + + // Release and free directory page. + eErrCode = base::free (aPage.location()); + } + + // Remove entry. + return remove_Impl (e); +} + +/* + * RebuildContext. + */ +struct RebuildContext +{ + /** Representation. + */ + rtl::Reference<OStorePageBIOS> m_xBIOS; + OStorePageBIOS::ScanContext m_aCtx; + sal_uInt16 m_nPageSize; + + /** Construction. + */ + RebuildContext (void) + : m_xBIOS (new OStorePageBIOS()), + m_nPageSize (0) + {} + + /** initialize (PageBIOS and ScanContext). + */ + storeError initialize (ILockBytes *pLockBytes, sal_uInt32 nMagic = 0) + { + storeError eErrCode = store_E_InvalidParameter; + if (pLockBytes) + { + m_xBIOS->initialize (pLockBytes, store_AccessReadOnly, m_nPageSize); + eErrCode = m_xBIOS->scanBegin (m_aCtx, nMagic); + } + return eErrCode; + } + + /** initialize (ScanContext). + */ + storeError initialize (sal_uInt32 nMagic = 0) + { + return m_xBIOS->scanBegin (m_aCtx, nMagic); + } + + /** load (next ScanContext matching page). + */ + storeError load (OStorePageObject &rPage) + { + if (m_aCtx.isValid()) + return m_xBIOS->scanNext (m_aCtx, rPage); + else + return store_E_CantSeek; + } +}; + +/* + * rebuild. + * Precond: none. + */ +storeError OStorePageManager::rebuild ( + ILockBytes *pSrcLB, ILockBytes *pDstLB) +{ + // Acquire exclusive access. + osl::MutexGuard aGuard(*this); + + // Check arguments. + storeError eErrCode = store_E_InvalidParameter; + if (!(pSrcLB && pDstLB)) + return eErrCode; + + // Initialize 'Source' rebuild context. + RebuildContext aCtx; + eErrCode = aCtx.initialize (pSrcLB, STORE_MAGIC_DIRECTORYPAGE); + if (eErrCode != store_E_None) + return eErrCode; + rtl::Reference<OStorePageBIOS> xSrcBIOS (aCtx.m_xBIOS); + + // Initialize as 'Destination' with 'Source' page size. + eErrCode = self::initialize (pDstLB, store_AccessCreate, aCtx.m_nPageSize); + if (eErrCode != store_E_None) + return eErrCode; + + // Pass One: Scan 'Source' directory pages. + { + // Scan 'Source' directory pages. + OStoreDirectoryPageObject aSrcPage; + while ((eErrCode = aCtx.load(aSrcPage)) == store_E_None) + { + OStoreDirectoryPageObject aDstPage; + eErrCode = aDstPage.construct< inode >(base::allocator()); + if (eErrCode != store_E_None) + break; + + inode_holder_type xSrcDir (aSrcPage.get()); + inode_holder_type xDstDir (aDstPage.get()); + + // Copy NameBlock @@@ OLD @@@ + memcpy (&(xDstDir->m_aNameBlock), &(xSrcDir->m_aNameBlock), sizeof(xSrcDir->m_aNameBlock)); + + // Obtain 'Source' data length. + sal_uInt32 nDataLen = aSrcPage.dataLength(); + if (nDataLen > 0) + { + // Copy internal data area @@@ OLD @@@ + memcpy (&(xDstDir->m_pData[0]), &(xSrcDir->m_pData[0]), xSrcDir->capacity()); + } + + // Insert 'Destination' directory page. + eErrCode = save_dirpage_Impl (aDstPage.key(), aDstPage); + if (eErrCode != store_E_None) + break; + + // Check for external data page scope. + if (xSrcDir->scope(nDataLen) != inode::SCOPE_INTERNAL) + { + // Initialize 'Destination' data page. + typedef OStoreDataPageData data; + PageHolderObject< data > xData; + if (!xData.construct(base::allocator())) + return store_E_OutOfMemory; + + // Determine data page count. + inode::ChunkDescriptor aDescr ( + nDataLen - xDstDir->capacity(), xData->capacity()); + + sal_uInt32 i, n = aDescr.m_nPage; + if (aDescr.m_nOffset) n += 1; + + // Copy data pages. + OStoreDataPageObject aData; + for (i = 0; i < n; i++) + { + // Read 'Source' data page. + osl::MutexGuard aSrcGuard (*xSrcBIOS); + + eErrCode = aSrcPage.read (i, aData, *xSrcBIOS); + if (eErrCode != store_E_None) + continue; + + // Write 'Destination' data page. @@@ READONLY @@@ + eErrCode = aDstPage.write (i, aData, *this); + } + } + + // Update 'Destination' directory page. + aDstPage.dataLength (nDataLen); + eErrCode = base::saveObjectAt (aDstPage, aDstPage.location()); + } + + // Save directory scan results. + flush(); + } + + // Pass Two: Scan 'Source' BTree nodes. + { + // Re-start 'Source' rebuild context. + aCtx.initialize (STORE_MAGIC_BTREENODE); + + // Scan 'Source' BTree nodes. + OStoreBTreeNodeObject aNode; + while ((eErrCode = aCtx.load(aNode)) == store_E_None) + { + // Check for leaf node. + PageHolderObject< page > xNode (aNode.get()); + if (xNode->depth() == 0) + { + sal_uInt16 i, n = xNode->usageCount(); + for (i = 0; i < n; i++) + { + entry e (xNode->m_pData[i]); + + // Check for Hard link. + if (e.m_nAttrib & STORE_ATTRIB_ISLINK) + { + // Load the hard link destination. + OStoreDirectoryPageObject aSrcPage; + eErrCode = xSrcBIOS->loadObjectAt (aSrcPage, e.m_aLink.location()); + if (eErrCode == store_E_None) + { + OStorePageKey aDstKey (aSrcPage.key()); + eErrCode = link (e.m_aKey, aDstKey); + } + e.m_nAttrib &= ~STORE_ATTRIB_ISLINK; + } + + if (e.m_nAttrib) + { + // Ordinary attributes. + sal_uInt32 nAttrib = 0; + eErrCode = attrib (e.m_aKey, 0, e.m_nAttrib, nAttrib); + } + } + } + } + + // Save BTree node scan results. + flush(); + } + + // Done. + return store_E_None; +} diff --git a/store/source/storpage.hxx b/store/source/storpage.hxx new file mode 100644 index 000000000000..bd5d60a72d3c --- /dev/null +++ b/store/source/storpage.hxx @@ -0,0 +1,226 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORPAGE_HXX_ +#define _STORE_STORPAGE_HXX_ "$Revision: 1.6.8.2 $" + +#include "sal/types.h" + +#include "object.hxx" +#include "lockbyte.hxx" + +#include "storbase.hxx" +#include "storbios.hxx" +#include "stortree.hxx" + +namespace store +{ + +struct OStoreDirectoryPageData; +class OStoreDirectoryPageObject; + +/*======================================================================== + * + * OStorePageManager interface. + * + *======================================================================*/ +class OStorePageManager : public store::OStorePageBIOS +{ +public: + /** Construction. + */ + OStorePageManager (void); + + /** Initialization (two-phase construction). + */ + virtual storeError initialize ( + ILockBytes * pLockBytes, + storeAccessMode eAccessMode, + sal_uInt16 & rnPageSize); + + /** isValid. + * @return sal_True upon successful initialization, + * sal_False otherwise. + */ + inline sal_Bool isValid (void) const; + + /** DirectoryPage I/O (managed). + */ + static storeError namei ( + const rtl_String *pPath, + const rtl_String *pName, + OStorePageKey &rKey); + + storeError iget ( + OStoreDirectoryPageObject & rPage, // [out] + sal_uInt32 nAttrib, + const rtl_String * pPath, + const rtl_String * pName, + storeAccessMode eMode); + + storeError iterate ( + OStorePageKey & rKey, + OStorePageLink & rLink, + sal_uInt32 & rAttrib); + + /** attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)]. + * @see store_attrib() + */ + storeError attrib ( + const OStorePageKey &rKey, + sal_uInt32 nMask1, + sal_uInt32 nMask2, + sal_uInt32 &rAttrib); + + /** link (insert Source Key as hardlink to Destination). + * @see store_link() + */ + storeError link ( + const OStorePageKey &rSrcKey, + const OStorePageKey &rDstKey); + + /** symlink (insert Source DirectoryPage as symlink to Destination). + * @see store_symlink() + */ + storeError symlink ( + const rtl_String *pSrcPath, + const rtl_String *pSrcName, + const OStorePageKey &rDstKey); + + /** rename. + * @see store_rename() + */ + storeError rename ( + const OStorePageKey &rSrcKey, + const rtl_String *pDstPath, + const rtl_String *pDstName); + + /** remove. + * @see store_remove() + */ + storeError remove ( + const OStorePageKey &rKey); + + /** rebuild (combines recover and compact from 'Src' to 'Dst'). + * @param pSrcLB [in] accessed readonly. + * @param pDstLB [in] truncated and accessed readwrite (as initialize()). + * @return store_E_None upon success. + * + * @see store_rebuildFile() + */ + storeError rebuild ( + ILockBytes *pSrcLB, + ILockBytes *pDstLB); + + /** IStoreHandle. + */ + virtual sal_Bool SAL_CALL isKindOf (sal_uInt32 nTypeId); + +protected: + /** Destruction. + */ + virtual ~OStorePageManager (void); + +private: + /** Implementation. + */ + typedef OStorePageBIOS base; + typedef OStorePageManager self; + + typedef OStoreBTreeEntry entry; + typedef OStoreBTreeNodeData page; + typedef OStoreBTreeNodeObject node; + + typedef OStoreDirectoryPageData inode; + typedef PageHolderObject< inode > inode_holder_type; + + /** IStoreHandle TypeId. + */ + static const sal_uInt32 m_nTypeId; + + /** IStoreHandle query() template function specialization. + */ + friend OStorePageManager* + SAL_CALL query<> (IStoreHandle *pHandle, OStorePageManager*); + + /** Representation. + */ + OStoreBTreeRootObject m_aRoot; + + /** DirectoryPage I/O (managed). + */ + storeError load_dirpage_Impl ( // @@@ => private: iget() @@@ + const OStorePageKey &rKey, + OStoreDirectoryPageObject &rPage); + + storeError save_dirpage_Impl ( // @@@ => private: iget(), rebuild() @@@ + const OStorePageKey &rKey, + OStoreDirectoryPageObject &rPage); + + /** find_lookup (node page and index, w/o split). + */ + storeError find_lookup ( + OStoreBTreeNodeObject & rNode, + sal_uInt16 & rIndex, + OStorePageKey const & rKey); + + /** remove (possibly down from root). + */ + storeError remove_Impl (entry & rEntry); + + /** Not implemented. + */ + OStorePageManager (const OStorePageManager&); + OStorePageManager& operator= (const OStorePageManager&); +}; + +inline sal_Bool OStorePageManager::isValid (void) const +{ + return (base::isValid() /* @@@ NYI && (m_aRoot.is()) */); +} + +template<> inline OStorePageManager* +SAL_CALL query (IStoreHandle *pHandle, OStorePageManager*) +{ + if (pHandle && pHandle->isKindOf (OStorePageManager::m_nTypeId)) + { + // Handle is kind of OStorePageManager. + return static_cast<OStorePageManager*>(pHandle); + } + return 0; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORPAGE_HXX_ */ + diff --git a/store/source/stortree.cxx b/store/source/stortree.cxx new file mode 100644 index 000000000000..23d7ca778961 --- /dev/null +++ b/store/source/stortree.cxx @@ -0,0 +1,582 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_store.hxx" + +#include "stortree.hxx" + +#include "sal/types.h" +#include "osl/diagnose.h" + +#include "store/types.h" + +#include "storbase.hxx" +#include "storbios.hxx" + +using namespace store; + +/*======================================================================== + * + * OStoreBTreeNodeData implementation. + * + *======================================================================*/ +/* + * OStoreBTreeNodeData. + */ +OStoreBTreeNodeData::OStoreBTreeNodeData (sal_uInt16 nPageSize) + : OStorePageData (nPageSize) +{ + base::m_aGuard.m_nMagic = store::htonl(self::theTypeId); + base::m_aDescr.m_nUsed = store::htons(self::thePageSize); // usageCount(0) + self::m_aGuard.m_nMagic = store::htonl(0); // depth(0) + + sal_uInt16 const n = capacityCount(); + T const t; + + for (sal_uInt16 i = 1; i < n; i++) + m_pData[i] = t; +} + +/* + * find. + */ +sal_uInt16 OStoreBTreeNodeData::find (const T& t) const +{ + register sal_Int32 l = 0; + register sal_Int32 r = usageCount() - 1; + + while (l < r) + { + register sal_Int32 const m = ((l + r) >> 1); + + if (t.m_aKey == m_pData[m].m_aKey) + return ((sal_uInt16)(m)); + if (t.m_aKey < m_pData[m].m_aKey) + r = m - 1; + else + l = m + 1; + } + + sal_uInt16 const k = ((sal_uInt16)(r)); + if ((k < capacityCount()) && (t.m_aKey < m_pData[k].m_aKey)) + return(k - 1); + else + return(k); +} + +/* + * insert. + */ +void OStoreBTreeNodeData::insert (sal_uInt16 i, const T& t) +{ + sal_uInt16 const n = usageCount(); + sal_uInt16 const m = capacityCount(); + if ((n < m) && (i < m)) + { + // shift right. + memmove (&(m_pData[i + 1]), &(m_pData[i]), (n - i) * sizeof(T)); + + // insert. + m_pData[i] = t; + usageCount (n + 1); + } +} + +/* + * remove. + */ +void OStoreBTreeNodeData::remove (sal_uInt16 i) +{ + sal_uInt16 const n = usageCount(); + if (i < n) + { + // shift left. + memmove (&(m_pData[i]), &(m_pData[i + 1]), (n - i - 1) * sizeof(T)); + + // truncate. + m_pData[n - 1] = T(); + usageCount (n - 1); + } +} + +#if 0 /* NYI */ +/* + * merge (with right page). + */ +void OStoreBTreeNodeData::merge (const self& rPageR) +{ + sal_uInt16 const n = usageCount(); + sal_uInt16 const m = rPageR.usageCount(); + if ((n + m) <= capacityCount()) + { + memcpy (&(m_pData[n]), &(rPageR.m_pData[0]), m * sizeof(T)); + usageCount (n + m); + } +} +#endif + +/* + * split (left half copied from right half of left page). + */ +void OStoreBTreeNodeData::split (const self& rPageL) +{ + sal_uInt16 const h = capacityCount() / 2; + memcpy (&(m_pData[0]), &(rPageL.m_pData[h]), h * sizeof(T)); + truncate (h); +} + +/* + * truncate. + */ +void OStoreBTreeNodeData::truncate (sal_uInt16 n) +{ + sal_uInt16 const m = capacityCount(); + T const t; + + for (sal_uInt16 i = n; i < m; i++) + m_pData[i] = t; + usageCount (n); +} + +/*======================================================================== + * + * OStoreBTreeNodeObject implementation. + * + *======================================================================*/ +/* + * guard. + */ +storeError OStoreBTreeNodeObject::guard (sal_uInt32 nAddr) +{ + return PageHolderObject< page >::guard (m_xPage, nAddr); +} + +/* + * verify. + */ +storeError OStoreBTreeNodeObject::verify (sal_uInt32 nAddr) const +{ + return PageHolderObject< page >::verify (m_xPage, nAddr); +} + +/* + * split. + */ +storeError OStoreBTreeNodeObject::split ( + sal_uInt16 nIndexL, + PageHolderObject< page > & rxPageL, + OStorePageBIOS & rBIOS) +{ + PageHolderObject< page > xPage (m_xPage); + if (!xPage.is()) + return store_E_InvalidAccess; + + // Check left page usage. + if (!rxPageL.is()) + return store_E_InvalidAccess; + if (!rxPageL->querySplit()) + return store_E_None; + + // Construct right page. + PageHolderObject< page > xPageR; + if (!xPageR.construct (rBIOS.allocator())) + return store_E_OutOfMemory; + + // Split right page off left page. + xPageR->split (*rxPageL); + xPageR->depth (rxPageL->depth()); + + // Allocate right page. + self aNodeR (xPageR.get()); + storeError eErrCode = rBIOS.allocate (aNodeR); + if (eErrCode != store_E_None) + return eErrCode; + + // Truncate left page. + rxPageL->truncate (rxPageL->capacityCount() / 2); + + // Save left page. + self aNodeL (rxPageL.get()); + eErrCode = rBIOS.saveObjectAt (aNodeL, aNodeL.location()); + if (eErrCode != store_E_None) + return eErrCode; + + // Insert right page. + OStorePageLink aLink (xPageR->location()); + xPage->insert (nIndexL + 1, T(xPageR->m_pData[0].m_aKey, aLink)); + + // Save this page and leave. + return rBIOS.saveObjectAt (*this, location()); +} + +/* + * remove (down to leaf node, recursive). + */ +storeError OStoreBTreeNodeObject::remove ( + sal_uInt16 nIndexL, + OStoreBTreeEntry & rEntryL, + OStorePageBIOS & rBIOS) +{ + PageHolderObject< page > xImpl (m_xPage); + page & rPage = (*xImpl); + + // Check depth. + storeError eErrCode = store_E_None; + if (rPage.depth()) + { + // Check link entry. + T const aEntryL (rPage.m_pData[nIndexL]); + if (!(rEntryL.compare (aEntryL) == T::COMPARE_EQUAL)) + return store_E_InvalidAccess; + + // Load link node. + self aNodeL; + eErrCode = rBIOS.loadObjectAt (aNodeL, aEntryL.m_aLink.location()); + if (eErrCode != store_E_None) + return eErrCode; + + // Recurse: remove from link node. + eErrCode = aNodeL.remove (0, rEntryL, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Check resulting link node usage. + PageHolderObject< page > xPageL (aNodeL.get()); + if (xPageL->usageCount() == 0) + { + // Free empty link node. + eErrCode = rBIOS.free (xPageL->location()); + if (eErrCode != store_E_None) + return eErrCode; + + // Remove index. + rPage.remove (nIndexL); + touch(); + } + else + { +#if 0 /* NYI */ + // Check for right sibling. + sal_uInt16 const nIndexR = nIndexL + 1; + if (nIndexR < rPage.usageCount()) + { + // Load right link node. + self aNodeR; + eErrCode = rBIOS.loadObjectAt (aNodeR, rPage.m_pData[nIndexR].m_aLink.location()); + if (eErrCode == store_E_None) + { + if (rPageL.queryMerge (rPageR)) + { + rPageL.merge (rPageR); + + eErrCode = rBIOS.free (rPageR.location()); + } + } + } +#endif /* NYI */ + + // Relink. + rPage.m_pData[nIndexL].m_aKey = xPageL->m_pData[0].m_aKey; + touch(); + } + } + else + { + // Check leaf entry. + if (!(rEntryL.compare (rPage.m_pData[nIndexL]) == T::COMPARE_EQUAL)) + return store_E_NotExists; + + // Save leaf entry. + rEntryL = rPage.m_pData[nIndexL]; + + // Remove leaf index. + rPage.remove (nIndexL); + touch(); + } + + // Check for modified node. + if (dirty()) + { + // Save this page. + eErrCode = rBIOS.saveObjectAt (*this, location()); + } + + // Done. + return eErrCode; +} + +/*======================================================================== + * + * OStoreBTreeRootObject implementation. + * + *======================================================================*/ +/* + * testInvariant. + * Precond: root node page loaded. + */ +bool OStoreBTreeRootObject::testInvariant (char const * message) +{ + OSL_PRECOND(m_xPage.get() != 0, "OStoreBTreeRootObject::testInvariant(): Null pointer"); + bool result = ((m_xPage->location() - m_xPage->size()) == 0); + OSL_POSTCOND(result, message); (void) message; + return result; +} + +/* + * loadOrCreate. + */ +storeError OStoreBTreeRootObject::loadOrCreate ( + sal_uInt32 nAddr, + OStorePageBIOS & rBIOS) +{ + storeError eErrCode = rBIOS.loadObjectAt (*this, nAddr); + if (eErrCode != store_E_NotExists) + return eErrCode; + + eErrCode = construct<page>(rBIOS.allocator()); + if (eErrCode != store_E_None) + return eErrCode; + + eErrCode = rBIOS.allocate (*this); + if (eErrCode != store_E_None) + return eErrCode; + + // Notify caller of the creation. + (void) testInvariant("OStoreBTreeRootObject::loadOrCreate(): leave"); + return store_E_Pending; +} + +/* + * change. + */ +storeError OStoreBTreeRootObject::change ( + PageHolderObject< page > & rxPageL, + OStorePageBIOS & rBIOS) +{ + PageHolderObject< page > xPage (m_xPage); + (void) testInvariant("OStoreBTreeRootObject::change(): enter"); + + // Save root location. + sal_uInt32 const nRootAddr = xPage->location(); + + // Construct new root. + if (!rxPageL.construct (rBIOS.allocator())) + return store_E_OutOfMemory; + + // Save this as prev root. + storeError eErrCode = rBIOS.allocate (*this); + if (eErrCode != store_E_None) + return store_E_OutOfMemory; + + // Setup new root. + rxPageL->depth (xPage->depth() + 1); + rxPageL->m_pData[0] = xPage->m_pData[0]; + rxPageL->m_pData[0].m_aLink = xPage->location(); + rxPageL->usageCount(1); + + // Change root. + rxPageL.swap (xPage); + { + PageHolder tmp (xPage.get()); + tmp.swap (m_xPage); + } + + // Save this as new root and finish. + eErrCode = rBIOS.saveObjectAt (*this, nRootAddr); + (void) testInvariant("OStoreBTreeRootObject::change(): leave"); + return eErrCode; +} + +/* + * find_lookup (w/o split()). + * Precond: root node page loaded. + */ +storeError OStoreBTreeRootObject::find_lookup ( + OStoreBTreeNodeObject & rNode, // [out] + sal_uInt16 & rIndex, // [out] + OStorePageKey const & rKey, + OStorePageBIOS & rBIOS) +{ + // Init node w/ root page. + (void) testInvariant("OStoreBTreeRootObject::find_lookup(): enter"); + { + PageHolder tmp (m_xPage); + tmp.swap (rNode.get()); + } + + // Setup BTree entry. + T const entry (rKey); + + // Check current page. + PageHolderObject< page > xPage (rNode.get()); + for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >()) + { + // Find next page. + page const & rPage = (*xPage); + sal_uInt16 const i = rPage.find(entry); + sal_uInt16 const n = rPage.usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Check address. + sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location(); + if (nAddr == STORE_PAGE_NULL) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Load next page. + storeError eErrCode = rBIOS.loadObjectAt (rNode, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Find index. + page const & rPage = (*xPage); + rIndex = rPage.find(entry); + if (!(rIndex < rPage.usageCount())) + return store_E_NotExists; + + // Compare entry. + T::CompareResult eResult = entry.compare(rPage.m_pData[rIndex]); + OSL_POSTCOND(eResult != T::COMPARE_LESS, "store::BTreeRoot::find_lookup(): sort error"); + if (eResult == T::COMPARE_LESS) + return store_E_Unknown; + + // Greater or Equal. + (void) testInvariant("OStoreBTreeRootObject::find_lookup(): leave"); + return store_E_None; +} + +/* + * find_insert (possibly with split()). + * Precond: root node page loaded. + */ +storeError OStoreBTreeRootObject::find_insert ( + OStoreBTreeNodeObject & rNode, // [out] + sal_uInt16 & rIndex, // [out] + OStorePageKey const & rKey, + OStorePageBIOS & rBIOS) +{ + (void) testInvariant("OStoreBTreeRootObject::find_insert(): enter"); + + // Check for RootNode split. + PageHolderObject< page > xRoot (m_xPage); + if (xRoot->querySplit()) + { + PageHolderObject< page > xPageL; + + // Change root. + storeError eErrCode = change (xPageL, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Split left page (prev root). + eErrCode = split (0, xPageL, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + } + + // Init node w/ root page. + { + PageHolder tmp (m_xPage); + tmp.swap (rNode.get()); + } + + // Setup BTree entry. + T const entry (rKey); + + // Check current Page. + PageHolderObject< page > xPage (rNode.get()); + for (; xPage->depth() > 0; xPage = rNode.makeHolder< page >()) + { + // Find next page. + page const & rPage = (*xPage); + sal_uInt16 const i = rPage.find (entry); + sal_uInt16 const n = rPage.usageCount(); + if (!(i < n)) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Check address. + sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location(); + if (nAddr == STORE_PAGE_NULL) + { + // Path to entry not exists (Must not happen(?)). + return store_E_NotExists; + } + + // Load next page. + OStoreBTreeNodeObject aNext; + storeError eErrCode = rBIOS.loadObjectAt (aNext, nAddr); + if (eErrCode != store_E_None) + return eErrCode; + + // Check for next node split. + PageHolderObject< page > xNext (aNext.get()); + if (xNext->querySplit()) + { + // Split next node. + eErrCode = rNode.split (i, xNext, rBIOS); + if (eErrCode != store_E_None) + return eErrCode; + + // Restart. + continue; + } + + // Let next page be current. + PageHolder tmp (aNext.get()); + tmp.swap (rNode.get()); + } + + // Find index. + page const & rPage = (*xPage); + rIndex = rPage.find(entry); + if (rIndex < rPage.usageCount()) + { + // Compare entry. + T::CompareResult result = entry.compare (rPage.m_pData[rIndex]); + OSL_POSTCOND(result != T::COMPARE_LESS, "store::BTreeRoot::find_insert(): sort error"); + if (result == T::COMPARE_LESS) + return store_E_Unknown; + + if (result == T::COMPARE_EQUAL) + return store_E_AlreadyExists; + } + + // Greater or not (yet) existing. + (void) testInvariant("OStoreBTreeRootObject::find_insert(): leave"); + return store_E_None; +} diff --git a/store/source/stortree.hxx b/store/source/stortree.hxx new file mode 100644 index 000000000000..820b270b3649 --- /dev/null +++ b/store/source/stortree.hxx @@ -0,0 +1,345 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _STORE_STORTREE_HXX +#define _STORE_STORTREE_HXX "$Revision: 1.6.8.2 $" + +#include "sal/types.h" + +#include "store/types.h" + +#include "storbase.hxx" + +namespace store +{ + +class OStorePageBIOS; + +/*======================================================================== + * + * OStoreBTreeEntry. + * + *======================================================================*/ +struct OStoreBTreeEntry +{ + typedef OStorePageKey K; + typedef OStorePageLink L; + + /** Representation. + */ + K m_aKey; + L m_aLink; + sal_uInt32 m_nAttrib; + + /** Construction. + */ + explicit OStoreBTreeEntry ( + K const & rKey = K(), + L const & rLink = L(), + sal_uInt32 nAttrib = 0) + : m_aKey (rKey), + m_aLink (rLink), + m_nAttrib (store::htonl(nAttrib)) + {} + + OStoreBTreeEntry (const OStoreBTreeEntry & rhs) + : m_aKey (rhs.m_aKey), + m_aLink (rhs.m_aLink), + m_nAttrib (rhs.m_nAttrib) + {} + + OStoreBTreeEntry& operator= (const OStoreBTreeEntry & rhs) + { + m_aKey = rhs.m_aKey; + m_aLink = rhs.m_aLink; + m_nAttrib = rhs.m_nAttrib; + return *this; + } + + /** Comparison. + */ + enum CompareResult + { + COMPARE_LESS = -1, + COMPARE_EQUAL = 0, + COMPARE_GREATER = 1 + }; + + CompareResult compare (const OStoreBTreeEntry& rOther) const + { + if (m_aKey < rOther.m_aKey) + return COMPARE_LESS; + else if (m_aKey == rOther.m_aKey) + return COMPARE_EQUAL; + else + return COMPARE_GREATER; + } +}; + +/*======================================================================== + * + * OStoreBTreeNodeData. + * + *======================================================================*/ +#define STORE_MAGIC_BTREENODE sal_uInt32(0x58190322) + +struct OStoreBTreeNodeData : public store::OStorePageData +{ + typedef OStorePageData base; + typedef OStoreBTreeNodeData self; + + typedef OStorePageGuard G; + typedef OStoreBTreeEntry T; + + /** Representation. + */ + G m_aGuard; + T m_pData[1]; + + /** type. + */ + static const sal_uInt32 theTypeId = STORE_MAGIC_BTREENODE; + + /** theSize. + */ + static const size_t theSize = sizeof(G); + static const sal_uInt16 thePageSize = base::theSize + self::theSize; + STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= self::thePageSize); + + /** capacity. + */ + sal_uInt16 capacity (void) const + { + return (store::ntohs(base::m_aDescr.m_nSize) - self::thePageSize); + } + + /** capacityCount (must be even). + */ + sal_uInt16 capacityCount (void) const + { + return sal_uInt16(capacity() / sizeof(T)); + } + + /** usage. + */ + sal_uInt16 usage (void) const + { + return (store::ntohs(base::m_aDescr.m_nUsed) - self::thePageSize); + } + + /** usageCount. + */ + sal_uInt16 usageCount (void) const + { + return sal_uInt16(usage() / sizeof(T)); + } + void usageCount (sal_uInt16 nCount) + { + size_t const nBytes = self::thePageSize + nCount * sizeof(T); + base::m_aDescr.m_nUsed = store::htons(sal::static_int_cast< sal_uInt16 >(nBytes)); + } + + /** Construction. + */ + explicit OStoreBTreeNodeData (sal_uInt16 nPageSize = self::thePageSize); + + /** 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_pData, capacity()); + m_aGuard.m_nCRC32 = store::htonl(nCRC32); + } + + /** verify (external representation). + */ + storeError verify() const + { + sal_uInt32 nCRC32 = 0; + nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); + nCRC32 = rtl_crc32 (nCRC32, m_pData, capacity()); + if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) + return store_E_InvalidChecksum; + else + return store_E_None; + } + + /** depth. + */ + sal_uInt32 depth (void) const + { + return store::ntohl(self::m_aGuard.m_nMagic); + } + void depth (sal_uInt32 nDepth) + { + self::m_aGuard.m_nMagic = store::htonl(nDepth); + } + + /** queryMerge. + */ + sal_Bool queryMerge (const self &rPageR) const + { + return ((usageCount() + rPageR.usageCount()) <= capacityCount()); + } + + /** querySplit. + */ + sal_Bool querySplit (void) const + { + return (!(usageCount() < capacityCount())); + } + + /** Operation. + */ + sal_uInt16 find (const T& t) const; + void insert (sal_uInt16 i, const T& t); + void remove (sal_uInt16 i); + +#if 0 /* NYI */ + /** merge (with right page). + */ + void merge (const self& rPageR); +#endif + + /** split (left half copied from right half of left page). + */ + void split (const self& rPageL); + + /** truncate (to n elements). + */ + void truncate (sal_uInt16 n); +}; + +/*======================================================================== + * + * OStoreBTreeNodeObject. + * + *======================================================================*/ +class OStoreBTreeNodeObject : public store::OStorePageObject +{ + typedef OStorePageObject base; + typedef OStoreBTreeNodeObject self; + typedef OStoreBTreeNodeData page; + + typedef OStoreBTreeEntry T; + +public: + /** Construction. + */ + explicit OStoreBTreeNodeObject (PageHolder const & rxPage = PageHolder()) + : OStorePageObject (rxPage) + {} + + /** External representation. + */ + virtual storeError guard (sal_uInt32 nAddr); + virtual storeError verify (sal_uInt32 nAddr) const; + + /** split. + * + * @param rxPageL [inout] left child to be split + */ + storeError split ( + sal_uInt16 nIndexL, + PageHolderObject< page > & rxPageL, + OStorePageBIOS & rBIOS); + + /** remove (down to leaf node, recursive). + */ + storeError remove ( + sal_uInt16 nIndexL, + OStoreBTreeEntry & rEntryL, + OStorePageBIOS & rBIOS); +}; + +/*======================================================================== + * + * OStoreBTreeRootObject. + * + *======================================================================*/ +class OStoreBTreeRootObject : public store::OStoreBTreeNodeObject +{ + typedef OStoreBTreeNodeObject base; + typedef OStoreBTreeNodeData page; + + typedef OStoreBTreeEntry T; + +public: + /** Construction. + */ + explicit OStoreBTreeRootObject (PageHolder const & rxPage = PageHolder()) + : OStoreBTreeNodeObject (rxPage) + {} + + storeError loadOrCreate ( + sal_uInt32 nAddr, + OStorePageBIOS & rBIOS); + + /** find_lookup (w/o split()). + * Precond: root node page loaded. + */ + storeError find_lookup ( + OStoreBTreeNodeObject & rNode, // [out] + sal_uInt16 & rIndex, // [out] + OStorePageKey const & rKey, + OStorePageBIOS & rBIOS); + + /** find_insert (possibly with split()). + * Precond: root node page loaded. + */ + storeError find_insert ( + OStoreBTreeNodeObject & rNode, + sal_uInt16 & rIndex, + OStorePageKey const & rKey, + OStorePageBIOS & rBIOS); + +private: + /** testInvariant. + * Precond: root node page loaded. + */ + bool testInvariant (char const * message); + + /** change (Root). + * + * @param rxPageL [out] prev. root (needs split) + */ + storeError change ( + PageHolderObject< page > & rxPageL, + OStorePageBIOS & rBIOS); +}; + +/*======================================================================== + * + * The End. + * + *======================================================================*/ + +} // namespace store + +#endif /* !_STORE_STORTREE_HXX */ |