LCOV - code coverage report
Current view: top level - store/source - storbios.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 247 390 63.3 %
Date: 2015-06-13 12:38:46 Functions: 43 53 81.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11