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

Generated by: LCOV version 1.10