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

Generated by: LCOV version 1.10