LCOV - code coverage report
Current view: top level - store/source - storbios.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 247 390 63.3 %
Date: 2014-11-03 Functions: 43 53 81.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "sal/config.h"
      21             : 
      22             : #include "boost/static_assert.hpp"
      23             : 
      24             : #include "storbios.hxx"
      25             : 
      26             : #include "sal/types.h"
      27             : #include "sal/macros.h"
      28             : #include "sal/log.hxx"
      29             : 
      30             : #include "rtl/alloc.h"
      31             : #include "rtl/ref.hxx"
      32             : 
      33             : #include "osl/diagnose.h"
      34             : #include "osl/mutex.hxx"
      35             : 
      36             : #include "store/types.h"
      37             : #include "object.hxx"
      38             : #include "lockbyte.hxx"
      39             : #include "storcach.hxx"
      40             : 
      41             : using namespace store;
      42             : 
      43             : /*========================================================================
      44             :  *
      45             :  * OStoreSuperBlock.
      46             :  *
      47             :  *======================================================================*/
      48             : #define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
      49             : 
      50         316 : struct OStoreSuperBlock
      51             : {
      52             :     typedef OStorePageGuard      G;
      53             :     typedef OStorePageDescriptor D;
      54             :     typedef OStorePageLink       L;
      55             : 
      56             :     /** Representation.
      57             :      */
      58             :     G          m_aGuard;
      59             :     D          m_aDescr;
      60             :     sal_uInt32 m_nMarked;
      61             :     L          m_aMarked;
      62             :     sal_uInt32 m_nUnused;
      63             :     L          m_aUnused;
      64             : 
      65             :     /** theSize.
      66             :      */
      67             :     static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32));
      68             : 
      69             :     /** Construction.
      70             :      */
      71         600 :     explicit OStoreSuperBlock (sal_uInt16 nPageSize)
      72             :         : m_aGuard  (STORE_MAGIC_SUPERBLOCK),
      73             :           m_aDescr  (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
      74         600 :           m_nMarked (store::htonl(0)),
      75             :           m_aMarked (0),
      76         600 :           m_nUnused (store::htonl(0)),
      77        1800 :           m_aUnused (0)
      78         600 :     {}
      79             : 
      80             :     /** Comparison.
      81             :      */
      82        2472 :     bool operator== (const OStoreSuperBlock & rhs) const
      83             :     {
      84        4944 :         return ((m_aGuard  == rhs.m_aGuard ) &&
      85        4944 :                 (m_aDescr  == rhs.m_aDescr ) &&
      86        4944 :                 (m_nMarked == rhs.m_nMarked) &&
      87        4944 :                 (m_aMarked == rhs.m_aMarked) &&
      88        7416 :                 (m_nUnused == rhs.m_nUnused) &&
      89        4944 :                 (m_aUnused == rhs.m_aUnused)    );
      90             :     }
      91             : 
      92             :     /** unused(Count|Head|Insert|Remove|Reset).
      93             :      */
      94          20 :     sal_uInt32 unusedCount (void) const
      95             :     {
      96          20 :         return store::ntohl(m_nUnused);
      97             :     }
      98        2472 :     const L& unusedHead (void) const
      99             :     {
     100        2472 :         return m_aUnused;
     101             :     }
     102          20 :     void unusedInsert (const L& rLink)
     103             :     {
     104          20 :         sal_uInt32 nUnused = unusedCount();
     105          20 :         m_nUnused = store::htonl(nUnused + 1);
     106          20 :         m_aUnused = rLink;
     107          20 :     }
     108           0 :     void unusedRemove (const L& rLink)
     109             :     {
     110           0 :         sal_uInt32 nUnused = unusedCount();
     111           0 :         m_nUnused = store::htonl(nUnused - 1);
     112           0 :         m_aUnused = rLink;
     113           0 :     }
     114           0 :     void unusedReset (void)
     115             :     {
     116           0 :         m_nUnused = store::htonl(0);
     117           0 :         m_aUnused = L(0);
     118           0 :     }
     119             : 
     120             :     /** guard (external representation).
     121             :      */
     122         316 :     void guard()
     123             :     {
     124         316 :         sal_uInt32 nCRC32 = 0;
     125         316 :         nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
     126         316 :         nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
     127         316 :         m_aGuard.m_nCRC32 = store::htonl(nCRC32);
     128         316 :     }
     129             : 
     130             :     /** verify (external representation).
     131             :      */
     132        4944 :     storeError verify() const
     133             :     {
     134        4944 :         sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
     135        4944 :         if (nMagic != STORE_MAGIC_SUPERBLOCK)
     136           0 :             return store_E_WrongFormat;
     137             : 
     138        4944 :         sal_uInt32 nCRC32 = 0;
     139        4944 :         nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
     140        4944 :         nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
     141        4944 :         if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
     142           0 :             return store_E_InvalidChecksum;
     143             :         else
     144        4944 :             return store_E_None;
     145             :     }
     146             : };
     147             : 
     148             : /*========================================================================
     149             :  *
     150             :  * SuperBlockPage interface.
     151             :  *
     152             :  *======================================================================*/
     153             : namespace store
     154             : {
     155             : 
     156             : struct SuperBlockPage
     157             : {
     158             :     typedef OStoreSuperBlock SuperBlock;
     159             : 
     160             :     /** Representation.
     161             :      */
     162             :     SuperBlock m_aSuperOne;
     163             :     SuperBlock m_aSuperTwo;
     164             : 
     165             :     /** theSize.
     166             :      */
     167             :     static const size_t     theSize     = 2 * SuperBlock::theSize;
     168             :     static const sal_uInt16 thePageSize = theSize;
     169             :     BOOST_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize);
     170             : 
     171             :     /** Allocation.
     172             :      */
     173           4 :     static void * operator new (size_t n)
     174             :     {
     175           4 :         return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
     176             :     }
     177         892 :     static void operator delete (void * p)
     178             :     {
     179         892 :         rtl_freeMemory (p);
     180         892 :     }
     181             : 
     182         296 :     static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize)
     183             :     {
     184         296 :         return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
     185             :     }
     186             :     static void operator delete (void * p, SAL_UNUSED_PARAMETER sal_uInt16)
     187             :     {
     188             :         rtl_freeMemory (p);
     189             :     }
     190             : 
     191             :     /** Construction.
     192             :      */
     193         300 :     explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
     194             :         : m_aSuperOne(nPageSize),
     195         300 :           m_aSuperTwo(nPageSize)
     196         300 :     {}
     197             : 
     198             :     /** save.
     199             :      */
     200         316 :     storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
     201             :     {
     202         316 :         m_aSuperOne.guard();
     203         316 :         m_aSuperTwo = m_aSuperOne;
     204         316 :         return rBIOS.write (0, this, nSize);
     205             :     }
     206             : 
     207             :     /** Page allocation.
     208             :      */
     209             :     storeError unusedHead (
     210             :         OStorePageBIOS & rBIOS,
     211             :         PageData &       rPageHead);
     212             : 
     213             :     storeError unusedPop (
     214             :         OStorePageBIOS & rBIOS,
     215             :         PageData const & rPageHead);
     216             : 
     217             :     storeError unusedPush (
     218             :         OStorePageBIOS & rBIOS,
     219             :         sal_uInt32       nAddr);
     220             : 
     221             :     /** verify (with repair).
     222             :      */
     223             :     storeError verify (OStorePageBIOS & rBIOS);
     224             : };
     225             : 
     226             : } // namespace store
     227             : 
     228             : /*========================================================================
     229             :  *
     230             :  * SuperBlockPage implementation.
     231             :  *
     232             :  *======================================================================*/
     233             : /*
     234             :  * unusedHead(): get freelist head (alloc page, step 1).
     235             :  */
     236        2452 : storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
     237             : {
     238        2452 :     storeError eErrCode = verify (rBIOS);
     239        2452 :     if (eErrCode != store_E_None)
     240           0 :         return eErrCode;
     241             : 
     242             :     // Check freelist head.
     243        2452 :     OStorePageLink const aListHead (m_aSuperOne.unusedHead());
     244        2452 :     if (aListHead.location() == 0)
     245             :     {
     246             :         // Freelist empty, see SuperBlock::ctor().
     247        2452 :         rPageHead.location (STORE_PAGE_NULL);
     248        2452 :         return store_E_None;
     249             :     }
     250             : 
     251             :     // Load PageHead.
     252           0 :     eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
     253           0 :     if (eErrCode != store_E_None)
     254           0 :         return eErrCode;
     255             : 
     256           0 :     eErrCode = rPageHead.verify (aListHead.location());
     257           0 :     if (eErrCode != store_E_None)
     258           0 :         return eErrCode;
     259             : 
     260             :     // Verify page is unused.
     261           0 :     sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
     262           0 :     if (nAddr == STORE_PAGE_NULL)
     263             :     {
     264             :         SAL_WARN("store", "store::SuperBlock::unusedHead(): page not free");
     265             : 
     266             :         // Page in use.
     267           0 :         rPageHead.location (STORE_PAGE_NULL);
     268             : 
     269             :         // Recovery: Reset freelist to empty.
     270           0 :         m_aSuperOne.unusedReset();
     271           0 :         eErrCode = save (rBIOS);
     272             :     }
     273           0 :     return eErrCode;
     274             : }
     275             : 
     276             : /*
     277             :  * unusedPop(): pop freelist head (alloc page, step 2).
     278             :  */
     279           0 : storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
     280             : {
     281           0 :     sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
     282             :     OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
     283           0 :     if (nAddr == STORE_PAGE_NULL)
     284           0 :         return store_E_CantSeek;
     285             : 
     286             :     // Pop from FreeList.
     287           0 :     OStorePageLink const aListHead (nAddr);
     288           0 :     m_aSuperOne.unusedRemove (aListHead);
     289           0 :     return save (rBIOS);
     290             : }
     291             : 
     292             : /*
     293             :  * unusedPush(): push new freelist head.
     294             :  */
     295          20 : storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
     296             : {
     297          20 :     storeError eErrCode = verify (rBIOS);
     298          20 :     if (eErrCode != store_E_None)
     299           0 :         return eErrCode;
     300             : 
     301          20 :     PageData aPageHead;
     302          20 :     eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
     303          20 :     if (eErrCode != store_E_None)
     304           0 :         return eErrCode;
     305             : 
     306          20 :     eErrCode = aPageHead.verify (nAddr);
     307          20 :     if (eErrCode != store_E_None)
     308           0 :         return eErrCode;
     309             : 
     310          20 :     aPageHead.m_aUnused = m_aSuperOne.unusedHead();
     311          20 :     aPageHead.guard (nAddr);
     312             : 
     313          20 :     eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
     314          20 :     if (eErrCode != store_E_None)
     315           0 :         return eErrCode;
     316             : 
     317          20 :     OStorePageLink const aListHead (nAddr);
     318          20 :     m_aSuperOne.unusedInsert(aListHead);
     319          20 :     return save (rBIOS);
     320             : }
     321             : 
     322             : /*
     323             :  * verify (with repair).
     324             :  */
     325        2472 : storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS)
     326             : {
     327             :     // Verify 1st copy.
     328        2472 :     storeError eErrCode = m_aSuperOne.verify();
     329        2472 :     if (eErrCode == store_E_None)
     330             :     {
     331             :         // Ok. Verify 2nd copy.
     332        2472 :         eErrCode = m_aSuperTwo.verify();
     333        2472 :         if (eErrCode == store_E_None)
     334             :         {
     335             :             // Ok. Ensure identical copies (1st copy wins).
     336        2472 :             if (!(m_aSuperOne == m_aSuperTwo))
     337             :             {
     338             :                 // Different. Replace 2nd copy with 1st copy.
     339           0 :                 m_aSuperTwo = m_aSuperOne;
     340             : 
     341             :                 // Write back.
     342           0 :                 if (rBIOS.isWriteable())
     343           0 :                     eErrCode = rBIOS.write (0, this, theSize);
     344             :                 else
     345           0 :                     eErrCode = store_E_None;
     346             :             }
     347             :         }
     348             :         else
     349             :         {
     350             :             // Failure. Replace 2nd copy with 1st copy.
     351           0 :             m_aSuperTwo = m_aSuperOne;
     352             : 
     353             :             // Write back.
     354           0 :             if (rBIOS.isWriteable())
     355           0 :                 eErrCode = rBIOS.write (0, this, theSize);
     356             :             else
     357           0 :                 eErrCode = store_E_None;
     358             :         }
     359             :     }
     360             :     else
     361             :     {
     362             :         // Failure. Verify 2nd copy.
     363           0 :         eErrCode = m_aSuperTwo.verify();
     364           0 :         if (eErrCode == store_E_None)
     365             :         {
     366             :             // Ok. Replace 1st copy with 2nd copy.
     367           0 :             m_aSuperOne = m_aSuperTwo;
     368             : 
     369             :             // Write back.
     370           0 :             if (rBIOS.isWriteable())
     371           0 :                 eErrCode = rBIOS.write (0, this, theSize);
     372             :             else
     373           0 :                 eErrCode = store_E_None;
     374             :         }
     375             :         else
     376             :         {
     377             :             // Double Failure.
     378             :             OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.");
     379             :         }
     380             :     }
     381             : 
     382             :     // Done.
     383        2472 :     return eErrCode;
     384             : }
     385             : 
     386             : /*========================================================================
     387             :  *
     388             :  * OStorePageBIOS::Ace implementation.
     389             :  *
     390             :  *======================================================================*/
     391         300 : OStorePageBIOS::Ace::Ace()
     392         300 :   : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
     393         300 : {}
     394             : 
     395         296 : OStorePageBIOS::Ace::~Ace()
     396             : {
     397         296 :   m_next->m_prev = m_prev, m_prev->m_next = m_next;
     398         296 : }
     399             : 
     400             : int
     401         568 : SAL_CALL OStorePageBIOS::Ace::constructor (
     402             :     void * obj, SAL_UNUSED_PARAMETER void * /* arg */)
     403             : {
     404         568 :   Ace * ace = static_cast<Ace*>(obj);
     405         568 :   ace->m_next = ace->m_prev = ace;
     406         568 :   return 1;
     407             : }
     408             : 
     409             : OStorePageBIOS::Ace *
     410        5320 : OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
     411             : {
     412             :   OStorePageBIOS::Ace * entry;
     413        5484 :   for (entry = head->m_next; entry != head; entry = entry->m_next)
     414             :   {
     415        2824 :     if (entry->m_addr >= addr)
     416        2660 :       return entry;
     417             :   }
     418        2660 :   return head;
     419             : }
     420             : 
     421             : void
     422        2660 : OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
     423             : {
     424             :   // insert entry at queue tail (before head).
     425        2660 :   entry->m_next = head;
     426        2660 :   entry->m_prev = head->m_prev;
     427        2660 :   head->m_prev = entry;
     428        2660 :   entry->m_prev->m_next = entry;
     429        2660 : }
     430             : 
     431             : /*========================================================================
     432             :  *
     433             :  * OStorePageBIOS::AceCache interface.
     434             :  *
     435             :  *======================================================================*/
     436             : namespace store
     437             : {
     438             : 
     439             : class OStorePageBIOS::AceCache
     440             : {
     441             :   rtl_cache_type * m_ace_cache;
     442             : 
     443             : public:
     444             :   static AceCache & get();
     445             : 
     446             :   OStorePageBIOS::Ace *
     447             :   create (sal_uInt32 addr, sal_uInt32 used = 1);
     448             : 
     449             :   void
     450             :   destroy (OStorePageBIOS::Ace * ace);
     451             : 
     452             : protected:
     453             :   AceCache();
     454             :   ~AceCache();
     455             : };
     456             : 
     457             : } // namespace store
     458             : 
     459             : /*========================================================================
     460             :  *
     461             :  * OStorePageBIOS::AceCache implementation.
     462             :  *
     463             :  *======================================================================*/
     464             : extern "C"  typedef  int (SAL_CALL * ace_constructor_type)(void*,void*);
     465             : 
     466             : OStorePageBIOS::AceCache &
     467        5320 : OStorePageBIOS::AceCache::get()
     468             : {
     469        5320 :   static AceCache g_ace_cache;
     470        5320 :   return g_ace_cache;
     471             : }
     472             : 
     473         292 : OStorePageBIOS::AceCache::AceCache()
     474             : {
     475             :   m_ace_cache = rtl_cache_create (
     476             :     "store_ace_cache",
     477             :     sizeof (OStorePageBIOS::Ace),
     478             :     0, // objalign
     479             :    reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor),
     480             :     0, // destructor,
     481             :     0, // reclaim,
     482             :     0, // userarg,
     483             :     0, // default source,
     484             :     0  // flags
     485         292 :     );
     486         292 : }
     487             : 
     488         292 : OStorePageBIOS::AceCache::~AceCache()
     489             : {
     490         292 :   rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
     491         292 : }
     492             : 
     493             : OStorePageBIOS::Ace *
     494        2660 : OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
     495             : {
     496        2660 :   Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
     497        2660 :   if (ace != 0)
     498             :   {
     499             :     // verify invariant state.
     500             :     OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
     501             : 
     502             :     // initialize.
     503        2660 :     ace->m_addr = addr;
     504        2660 :     ace->m_used = used;
     505             :   }
     506        2660 :   return ace;
     507             : }
     508             : 
     509             : void
     510        2660 : OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
     511             : {
     512        2660 :   if (ace != 0)
     513             :   {
     514             :     // remove from queue (if any).
     515        2660 :     ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
     516             : 
     517             :     // restore invariant state.
     518        2660 :     ace->m_next = ace->m_prev = ace;
     519             : 
     520             :     // return to cache.
     521        2660 :     rtl_cache_free (m_ace_cache, ace);
     522             :   }
     523        2660 : }
     524             : 
     525             : /*========================================================================
     526             :  *
     527             :  * OStorePageBIOS implementation.
     528             :  *
     529             :  *======================================================================*/
     530             : /*
     531             :  * OStorePageBIOS.
     532             :  */
     533         300 : OStorePageBIOS::OStorePageBIOS (void)
     534             :     : m_xLockBytes (NULL),
     535             :       m_pSuper     (NULL),
     536         300 :       m_bWriteable (false)
     537             : {
     538         300 : }
     539             : 
     540             : /*
     541             :  * ~OStorePageBIOS.
     542             :  */
     543         592 : OStorePageBIOS::~OStorePageBIOS (void)
     544             : {
     545         296 :     cleanup_Impl();
     546         296 : }
     547             : 
     548             : /*
     549             :  * initialize.
     550             :  * Precond: none.
     551             :  */
     552         300 : storeError OStorePageBIOS::initialize (
     553             :     ILockBytes *    pLockBytes,
     554             :     storeAccessMode eAccessMode,
     555             :     sal_uInt16 &    rnPageSize)
     556             : {
     557             :     // Acquire exclusive access.
     558         300 :     osl::MutexGuard aGuard (m_aMutex);
     559             : 
     560             :     // Initialize.
     561         300 :     storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
     562         300 :     if (eErrCode != store_E_None)
     563             :     {
     564             :         // Cleanup.
     565           4 :         cleanup_Impl();
     566             :     }
     567         300 :     return eErrCode;
     568             : }
     569             : 
     570             : /*
     571             :  * initialize_Impl.
     572             :  * Internal: Precond: exclusive access.
     573             :  */
     574         300 : storeError OStorePageBIOS::initialize_Impl (
     575             :     ILockBytes *    pLockBytes,
     576             :     storeAccessMode eAccessMode,
     577             :     sal_uInt16 &    rnPageSize)
     578             : {
     579             :     // Cleanup.
     580         300 :     cleanup_Impl();
     581             : 
     582             :     // Initialize.
     583         300 :     m_xLockBytes = pLockBytes;
     584         300 :     if (!m_xLockBytes.is())
     585           0 :         return store_E_InvalidParameter;
     586         300 :     m_bWriteable = (eAccessMode != store_AccessReadOnly);
     587             : 
     588             :     // Check access mode.
     589         300 :     storeError eErrCode = store_E_None;
     590         300 :     if (eAccessMode != store_AccessCreate)
     591             :     {
     592             :         // Load SuperBlock page.
     593           4 :         if ((m_pSuper = new SuperBlockPage()) == 0)
     594           0 :             return store_E_OutOfMemory;
     595             : 
     596           4 :         eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
     597           4 :         if (eErrCode == store_E_None)
     598             :         {
     599             :             // Verify SuperBlock page (with repair).
     600           0 :             eErrCode = m_pSuper->verify (*this);
     601             :         }
     602             :     }
     603             :     else
     604             :     {
     605             :         // Truncate to zero length.
     606         296 :         eErrCode = m_xLockBytes->setSize(0);
     607         296 :         if (eErrCode != store_E_None)
     608           0 :             return eErrCode;
     609             : 
     610             :         // Mark as not existing.
     611         296 :         eErrCode = store_E_NotExists;
     612             :     }
     613             : 
     614         300 :     if (eErrCode != store_E_None)
     615             :     {
     616             :         // Check reason.
     617         300 :         if (eErrCode != store_E_NotExists)
     618           0 :             return eErrCode;
     619             : 
     620             :         // Check mode.
     621         300 :         if (eAccessMode == store_AccessReadOnly)
     622           4 :             return store_E_NotExists;
     623         296 :         if (eAccessMode == store_AccessReadWrite)
     624           0 :             return store_E_NotExists;
     625             : 
     626             :         // Check PageSize.
     627         296 :         if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
     628           0 :             return store_E_InvalidParameter;
     629         296 :         rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
     630             : 
     631             :         // Create initial page (w/ SuperBlock).
     632         296 :         if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
     633           0 :             return store_E_OutOfMemory;
     634         296 :         eErrCode = m_pSuper->save (*this, rnPageSize);
     635             :     }
     636         296 :     if (eErrCode == store_E_None)
     637             :     {
     638             :         // Obtain page size.
     639         296 :         rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
     640             : 
     641             :         // Create page allocator.
     642         296 :         eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
     643         296 :         if (eErrCode != store_E_None)
     644           0 :             return eErrCode;
     645             : 
     646             :         // Create page cache.
     647         296 :         eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
     648             :     }
     649         296 :     return eErrCode;
     650             : }
     651             : 
     652             : /*
     653             :  * cleanup_Impl.
     654             :  * Internal: Precond: exclusive access.
     655             :  */
     656         892 : void OStorePageBIOS::cleanup_Impl()
     657             : {
     658             :     // Check referer count.
     659         892 :     if (m_ace_head.m_used > 0)
     660             :     {
     661             :         // Report remaining referer count.
     662             :         OSL_TRACE("store::PageBIOS::cleanup_Impl(): referer count: %d", m_ace_head.m_used);
     663           0 :         for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next)
     664             :         {
     665           0 :             m_ace_head.m_used -= ace->m_used;
     666           0 :             AceCache::get().destroy (ace);
     667             :         }
     668             :         OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::cleanup_Impl(): logic error");
     669             :     }
     670             : 
     671             :     // Release SuperBlock page.
     672         892 :     delete m_pSuper, m_pSuper = 0;
     673             : 
     674             :     // Release PageCache.
     675         892 :     m_xCache.clear();
     676             : 
     677             :     // Release PageAllocator.
     678         892 :     m_xAllocator.clear();
     679             : 
     680             :     // Release LockBytes.
     681         892 :     m_xLockBytes.clear();
     682         892 : }
     683             : 
     684             : /*
     685             :  * read.
     686             :  * Low Level: Precond: initialized, exclusive access.
     687             :  */
     688          24 : storeError OStorePageBIOS::read (
     689             :     sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
     690             : {
     691             :     // Check precond.
     692          24 :     if (!m_xLockBytes.is())
     693           0 :         return store_E_InvalidAccess;
     694             : 
     695             :     // Read Data.
     696          24 :     return m_xLockBytes->readAt (nAddr, pData, nSize);
     697             : }
     698             : 
     699             : /*
     700             :  * write.
     701             :  * Low Level: Precond: initialized, writeable, exclusive access.
     702             :  */
     703         336 : storeError OStorePageBIOS::write (
     704             :     sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
     705             : {
     706             :     // Check precond.
     707         336 :     if (!m_xLockBytes.is())
     708           0 :         return store_E_InvalidAccess;
     709         336 :     if (!m_bWriteable)
     710           0 :         return store_E_AccessViolation;
     711             : 
     712             :     // Write Data.
     713         336 :     return m_xLockBytes->writeAt (nAddr, pData, nSize);
     714             : }
     715             : 
     716             : /*
     717             :  * acquirePage.
     718             :  * Precond: initialized.
     719             :  */
     720        2660 : storeError OStorePageBIOS::acquirePage (
     721             :     const OStorePageDescriptor& rDescr, storeAccessMode eMode)
     722             : {
     723             :     // Acquire exclusive access.
     724        2660 :     osl::MutexGuard aGuard (m_aMutex);
     725             : 
     726             :     // Check precond.
     727        2660 :     if (!m_xLockBytes.is())
     728           0 :         return store_E_InvalidAccess;
     729             : 
     730             :     // Check access mode.
     731        2660 :     if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
     732           0 :         return store_E_AccessViolation;
     733             : 
     734             :     // Find access control list entry.
     735        2660 :     Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
     736        2660 :     if (ace->m_addr == rDescr.m_nAddr)
     737             :     {
     738             :       // Acquire existing entry (with ShareDenyWrite).
     739           0 :       if (eMode == store_AccessReadOnly)
     740           0 :         ace->m_used += 1;
     741             :       else
     742           0 :         return store_E_AccessViolation;
     743             :     }
     744             :     else
     745             :     {
     746             :       // Insert new entry.
     747        2660 :       Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1);
     748        2660 :       if (!entry)
     749           0 :         return store_E_OutOfMemory;
     750        2660 :       Ace::insert (ace, entry);
     751             :     }
     752             : 
     753             :     // Increment total referer count and finish.
     754        2660 :     m_ace_head.m_used += 1;
     755        2660 :     return store_E_None;
     756             : }
     757             : 
     758             : /*
     759             :  * releasePage.
     760             :  * Precond: initialized.
     761             :  */
     762        2660 : storeError OStorePageBIOS::releasePage (const OStorePageDescriptor& rDescr)
     763             : {
     764             :     // Acquire exclusive access.
     765        2660 :     osl::MutexGuard aGuard (m_aMutex);
     766             : 
     767             :     // Check precond.
     768        2660 :     if (!m_xLockBytes.is())
     769           0 :         return store_E_InvalidAccess;
     770             : 
     771             :     // Find access control list entry.
     772        2660 :     Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
     773        2660 :     if (ace->m_addr != rDescr.m_nAddr)
     774           0 :       return store_E_NotExists;
     775             : 
     776             :     // Release existing entry.
     777        2660 :     if (ace->m_used > 1)
     778           0 :       ace->m_used -= 1;
     779             :     else
     780        2660 :       AceCache::get().destroy (ace);
     781             : 
     782             :     // Decrement total referer count and finish.
     783        2660 :     m_ace_head.m_used -= 1;
     784        2660 :     return store_E_None;
     785             : }
     786             : 
     787             : /*
     788             :  * getRefererCount.
     789             :  * Precond: none.
     790             :  */
     791           0 : sal_uInt32 OStorePageBIOS::getRefererCount (void)
     792             : {
     793             :     // Acquire exclusive access.
     794           0 :     osl::MutexGuard aGuard (m_aMutex);
     795             : 
     796             :     // Obtain total referer count.
     797           0 :     return m_ace_head.m_used;
     798             : }
     799             : 
     800             : /*
     801             :  * allocate.
     802             :  * Precond: initialized, writeable.
     803             :  */
     804        2452 : storeError OStorePageBIOS::allocate (
     805             :     OStorePageObject& rPage, Allocation eAlloc)
     806             : {
     807             :     // Acquire exclusive access.
     808        2452 :     osl::MutexGuard aGuard (m_aMutex);
     809             : 
     810             :     // Check precond.
     811        2452 :     if (!m_xLockBytes.is())
     812           0 :         return store_E_InvalidAccess;
     813        2452 :     if (!m_bWriteable)
     814           0 :         return store_E_AccessViolation;
     815             : 
     816             :     // Check allocation type.
     817        2452 :     storeError eErrCode = store_E_None;
     818        2452 :     if (eAlloc != ALLOCATE_EOF)
     819             :     {
     820             :         // Try freelist head.
     821        2452 :         PageData aPageHead;
     822        2452 :         eErrCode = m_pSuper->unusedHead (*this, aPageHead);
     823        2452 :         if (eErrCode != store_E_None)
     824           0 :             return eErrCode;
     825             : 
     826        2452 :         sal_uInt32 const nAddr = aPageHead.location();
     827        2452 :         if (nAddr != STORE_PAGE_NULL)
     828             :         {
     829             :             // Save page.
     830           0 :             eErrCode = saveObjectAt_Impl (rPage, nAddr);
     831           0 :             if (eErrCode != store_E_None)
     832           0 :                 return eErrCode;
     833             : 
     834             :             // Pop freelist head and finish.
     835           0 :             return m_pSuper->unusedPop (*this, aPageHead);
     836             :         }
     837             :     }
     838             : 
     839             :     // Allocate from EOF. Determine current size.
     840        2452 :     sal_uInt32 nSize = STORE_PAGE_NULL;
     841        2452 :     eErrCode = m_xLockBytes->getSize (nSize);
     842        2452 :     if (eErrCode != store_E_None)
     843           0 :         return eErrCode;
     844             : 
     845             :     // Save page at current EOF.
     846        2452 :     return saveObjectAt_Impl (rPage, nSize);
     847             : }
     848             : 
     849             : /*
     850             :  * free.
     851             :  * Precond: initialized, writeable.
     852             :  */
     853          20 : storeError OStorePageBIOS::free (sal_uInt32 nAddr)
     854             : {
     855             :     // Acquire exclusive access.
     856          20 :     osl::MutexGuard aGuard (m_aMutex);
     857             : 
     858             :     // Check precond.
     859          20 :     if (!m_xLockBytes.is())
     860           0 :         return store_E_InvalidAccess;
     861          20 :     if (!m_bWriteable)
     862           0 :         return store_E_AccessViolation;
     863             : 
     864             :     // Invalidate cache.
     865          20 :     (void) m_xCache->removePageAt (nAddr);
     866             : 
     867             :     // Push onto freelist.
     868          20 :     return m_pSuper->unusedPush (*this, nAddr);
     869             : }
     870             : 
     871             : /*
     872             :  * loadObjectAt.
     873             :  * Precond: initialized, readable.
     874             :  */
     875        1122 : storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
     876             : {
     877             :     // Acquire exclusive access.
     878        1122 :     osl::MutexGuard aGuard (m_aMutex);
     879             : 
     880             :     // Check precond.
     881        1122 :     if (!m_xLockBytes.is())
     882           0 :         return store_E_InvalidAccess;
     883             : 
     884        1122 :     return loadObjectAt_Impl (rPage, nAddr);
     885             : }
     886             : 
     887             : /*
     888             :  * loadObjectAt_Impl.
     889             :  * Internal: Precond: initialized, readable, exclusive access.
     890             :  */
     891        1122 : storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
     892             : {
     893        1122 :     storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
     894        1122 :     if (eErrCode != store_E_NotExists)
     895         826 :         return eErrCode;
     896             : 
     897             :     // Read page.
     898         296 :     eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
     899         296 :     if (eErrCode != store_E_None)
     900         296 :         return eErrCode;
     901             : 
     902             :     // Verify page.
     903           0 :     eErrCode = rPage.verify (nAddr);
     904           0 :     if (eErrCode != store_E_None)
     905           0 :         return eErrCode;
     906             : 
     907             :     // Mark page as clean.
     908           0 :     rPage.clean();
     909             : 
     910             :     // Cache page.
     911           0 :     return m_xCache->insertPageAt (rPage.get(), nAddr);
     912             : }
     913             : 
     914             : /*
     915             :  * saveObjectAt.
     916             :  * Precond: initialized, writeable.
     917             :  */
     918        3028 : storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
     919             : {
     920             :     // Acquire exclusive access.
     921        3028 :     osl::MutexGuard aGuard (m_aMutex);
     922             : 
     923             :     // Check precond.
     924        3028 :     if (!m_xLockBytes.is())
     925           0 :         return store_E_InvalidAccess;
     926        3028 :     if (!m_bWriteable)
     927           0 :         return store_E_AccessViolation;
     928             : 
     929             :     // Save Page.
     930        3028 :     return saveObjectAt_Impl (rPage, nAddr);
     931             : }
     932             : 
     933             : /*
     934             :  * saveObjectAt_Impl.
     935             :  * Internal: Precond: initialized, writeable, exclusive access.
     936             :  */
     937        5480 : storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
     938             : {
     939             :     // Guard page (incl. set location).
     940        5480 :     storeError eErrCode = rPage.guard (nAddr);
     941        5480 :     if (eErrCode != store_E_None)
     942           0 :         return eErrCode;
     943             : 
     944             :     // Write page.
     945        5480 :     eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
     946        5480 :     if (eErrCode != store_E_None)
     947           0 :         return eErrCode;
     948             : 
     949             :     // Mark page as clean.
     950        5480 :     rPage.clean();
     951             : 
     952             :     // Cache page.
     953        5480 :     return m_xCache->updatePageAt (rPage.get(), nAddr);
     954             : }
     955             : 
     956             : /*
     957             :  * close.
     958             :  * Precond: none.
     959             :  */
     960         292 : storeError OStorePageBIOS::close()
     961             : {
     962             :     // Acquire exclusive access.
     963         292 :     osl::MutexGuard aGuard (m_aMutex);
     964             : 
     965             :     // Cleanup.
     966         292 :     cleanup_Impl();
     967             : 
     968             :     // Done.
     969         292 :     return store_E_None;
     970             : }
     971             : 
     972             : /*
     973             :  * flush.
     974             :  * Precond: initialized.
     975             :  */
     976           4 : storeError OStorePageBIOS::flush (void)
     977             : {
     978             :     // Acquire exclusive access.
     979           4 :     osl::MutexGuard aGuard (m_aMutex);
     980             : 
     981             :     // Check precond.
     982           4 :     if (!m_xLockBytes.is())
     983           0 :         return store_E_InvalidAccess;
     984             : 
     985             :     // Flush LockBytes and finish.
     986           4 :     return m_xLockBytes->flush();
     987             : }
     988             : 
     989             : /*
     990             :  * size.
     991             :  * Precond: initialized.
     992             :  */
     993           0 : storeError OStorePageBIOS::size (sal_uInt32 &rnSize)
     994             : {
     995             :     // Acquire exclusive access.
     996           0 :     osl::MutexGuard aGuard (m_aMutex);
     997             : 
     998             :     // Initialize [out] param.
     999           0 :     rnSize = 0;
    1000             : 
    1001             :     // Check precond.
    1002           0 :     if (!m_xLockBytes.is())
    1003           0 :         return store_E_InvalidAccess;
    1004             : 
    1005             :     // Obtain LockBytes size.
    1006           0 :     return m_xLockBytes->getSize (rnSize);
    1007             : }
    1008             : 
    1009             : /*
    1010             :  * scanBegin.
    1011             :  * Precond: initialized.
    1012             :  */
    1013           0 : storeError OStorePageBIOS::scanBegin (
    1014             :     ScanContext &rCtx, sal_uInt32 nMagic)
    1015             : {
    1016             :     // Acquire exclusive access.
    1017           0 :     osl::MutexGuard aGuard (m_aMutex);
    1018             : 
    1019             :     // Initialize [out] param.
    1020           0 :     rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0);
    1021           0 :     rCtx.m_nSize  = 0;
    1022           0 :     rCtx.m_nMagic = nMagic;
    1023             : 
    1024             :     // Check precond.
    1025           0 :     if (!m_xLockBytes.is())
    1026           0 :         return store_E_InvalidAccess;
    1027             : 
    1028             :     // Check SuperBlock page.
    1029           0 :     storeError eErrCode = m_pSuper->verify (*this);
    1030           0 :     if (eErrCode != store_E_None)
    1031             :     {
    1032             :         // Damaged. Determine page size (NYI).
    1033             :         OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n");
    1034           0 :         return eErrCode;
    1035             :     }
    1036             : 
    1037             :     // Setup Context descriptor.
    1038           0 :     rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr;
    1039           0 :     rCtx.m_aDescr.m_nSize = store::ntohs(rCtx.m_aDescr.m_nSize);
    1040           0 :     rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize;
    1041             : 
    1042             :     // Setup Context size.
    1043           0 :     eErrCode = size (rCtx.m_nSize);
    1044           0 :     if (eErrCode != store_E_None)
    1045           0 :         rCtx.m_nSize = ((sal_uInt32)(~0));
    1046             : 
    1047             :     // Done.
    1048           0 :     return store_E_None;
    1049             : }
    1050             : 
    1051             : /*
    1052             :  * scanNext.
    1053             :  * Precond: initialized.
    1054             :  */
    1055           0 : storeError OStorePageBIOS::scanNext (
    1056             :     ScanContext &rCtx, OStorePageObject &rPage)
    1057             : {
    1058             :     // Acquire exclusive access.
    1059           0 :     osl::MutexGuard aGuard (m_aMutex);
    1060             : 
    1061             :     // Check precond.
    1062           0 :     if (!m_xLockBytes.is())
    1063           0 :         return store_E_InvalidAccess;
    1064             : 
    1065             :     // Setup PageHead.
    1066           0 :     PageData aPageHead;
    1067             : 
    1068             :     // Check context.
    1069           0 :     while (rCtx.isValid())
    1070             :     {
    1071             :         // Assign next location.
    1072           0 :         sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr;
    1073           0 :         rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
    1074             : 
    1075             :         // Read PageHead.
    1076           0 :         storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize);
    1077           0 :         if (eErrCode != store_E_None)
    1078           0 :             continue;
    1079             : 
    1080             :         // Verify PageHead.
    1081           0 :         eErrCode = aPageHead.verify (nAddr);
    1082           0 :         if (eErrCode != store_E_None)
    1083           0 :             continue;
    1084             : 
    1085             :         // Check PageHead Magic number.
    1086           0 :         if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic)
    1087           0 :             continue;
    1088             : 
    1089             :         // Check PageHead Unused link.
    1090           0 :         if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL)
    1091           0 :             continue;
    1092             : 
    1093             :         // Load page.
    1094           0 :         eErrCode = loadObjectAt_Impl (rPage, nAddr);
    1095           0 :         if (eErrCode != store_E_None)
    1096           0 :             continue;
    1097             : 
    1098             :         // Deliver page.
    1099           0 :         return store_E_None;
    1100             :     }
    1101             : 
    1102             :     // Done.
    1103           0 :     return store_E_CantSeek;
    1104             : }
    1105             : 
    1106             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10