LCOV - code coverage report
Current view: top level - libreoffice/store/source - storcach.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 161 176 91.5 %
Date: 2012-12-27 Functions: 27 28 96.4 %
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 "storcach.hxx"
      22             : 
      23             : #include "sal/types.h"
      24             : #include "sal/macros.h"
      25             : #include "rtl/alloc.h"
      26             : #include "osl/diagnose.h"
      27             : 
      28             : #include "store/types.h"
      29             : #include "object.hxx"
      30             : #include "storbase.hxx"
      31             : 
      32             : #include <stddef.h>
      33             : 
      34             : using namespace store;
      35             : 
      36             : /*========================================================================
      37             :  *
      38             :  * PageCache (non-virtual interface) implementation.
      39             :  *
      40             :  *======================================================================*/
      41             : 
      42     2465449 : storeError PageCache::lookupPageAt (PageHolder & rxPage, sal_uInt32 nOffset)
      43             : {
      44             :     OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::lookupPageAt(): invalid Offset");
      45     2465449 :     if (nOffset == STORE_PAGE_NULL)
      46           0 :         return store_E_CantSeek;
      47             : 
      48     2465449 :     return lookupPageAt_Impl (rxPage, nOffset);
      49             : }
      50             : 
      51      189723 : storeError PageCache::insertPageAt (PageHolder const & rxPage, sal_uInt32 nOffset)
      52             : {
      53             :     // [SECURITY:ValInput]
      54      189723 :     PageData const * pagedata = rxPage.get();
      55             :     OSL_PRECOND(!(pagedata == 0), "store::PageCache::insertPageAt(): invalid Page");
      56      189723 :     if (pagedata == 0)
      57           0 :         return store_E_InvalidParameter;
      58             : 
      59      189723 :     sal_uInt32 const offset = pagedata->location();
      60             :     OSL_PRECOND(!(nOffset != offset), "store::PageCache::insertPageAt(): inconsistent Offset");
      61      189723 :     if (nOffset != offset)
      62           0 :         return store_E_InvalidParameter;
      63             : 
      64             :     OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::insertPageAt(): invalid Offset");
      65      189723 :     if (nOffset == STORE_PAGE_NULL)
      66           0 :         return store_E_CantSeek;
      67             : 
      68      189723 :     return insertPageAt_Impl (rxPage, nOffset);
      69             : }
      70             : 
      71      272807 : storeError PageCache::updatePageAt (PageHolder const & rxPage, sal_uInt32 nOffset)
      72             : {
      73             :     // [SECURITY:ValInput]
      74      272807 :     PageData const * pagedata = rxPage.get();
      75             :     OSL_PRECOND(!(pagedata == 0), "store::PageCache::updatePageAt(): invalid Page");
      76      272807 :     if (pagedata == 0)
      77           0 :         return store_E_InvalidParameter;
      78             : 
      79      272807 :     sal_uInt32 const offset = pagedata->location();
      80             :     OSL_PRECOND(!(nOffset != offset), "store::PageCache::updatePageAt(): inconsistent Offset");
      81      272807 :     if (nOffset != offset)
      82           0 :         return store_E_InvalidParameter;
      83             : 
      84             :     OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::updatePageAt(): invalid Offset");
      85      272807 :     if (nOffset == STORE_PAGE_NULL)
      86           0 :         return store_E_CantSeek;
      87             : 
      88      272807 :     return updatePageAt_Impl (rxPage, nOffset);
      89             : }
      90             : 
      91           8 : storeError PageCache::removePageAt (sal_uInt32 nOffset)
      92             : {
      93             :     OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::PageCache::removePageAt(): invalid Offset");
      94           8 :     if (nOffset == STORE_PAGE_NULL)
      95           0 :         return store_E_CantSeek;
      96             : 
      97           8 :     return removePageAt_Impl (nOffset);
      98             : }
      99             : 
     100             : /*========================================================================
     101             :  *
     102             :  * Entry.
     103             :  *
     104             :  *======================================================================*/
     105             : namespace
     106             : {
     107             : 
     108             : struct Entry
     109             : {
     110             :     /** Representation.
     111             :      */
     112             :     PageHolder m_xPage;
     113             :     sal_uInt32 m_nOffset;
     114             :     Entry *    m_pNext;
     115             : 
     116             :     /** Allocation.
     117             :      */
     118      297445 :     static void * operator new (size_t, void * p) { return p; }
     119           0 :     static void   operator delete (void *, void *) {}
     120             : 
     121             :     /** Construction.
     122             :      */
     123      297445 :     explicit Entry (PageHolder const & rxPage = PageHolder(), sal_uInt32 nOffset = STORE_PAGE_NULL)
     124      297445 :         : m_xPage(rxPage), m_nOffset(nOffset), m_pNext(0)
     125      297445 :     {}
     126             : 
     127             :     /** Destruction.
     128             :      */
     129      234175 :     ~Entry() {}
     130             : };
     131             : 
     132             : } // namespace
     133             : 
     134             : /*========================================================================
     135             :  *
     136             :  * EntryCache interface.
     137             :  *
     138             :  *======================================================================*/
     139             : namespace
     140             : {
     141             : 
     142             : class EntryCache
     143             : {
     144             :     rtl_cache_type * m_entry_cache;
     145             : 
     146             : public:
     147             :     static EntryCache & get();
     148             : 
     149             :     Entry * create (PageHolder const & rxPage, sal_uInt32 nOffset);
     150             : 
     151             :     void destroy (Entry * entry);
     152             : 
     153             : protected:
     154             :     EntryCache();
     155             :     ~EntryCache();
     156             : };
     157             : 
     158             : } // namespace
     159             : 
     160             : /*========================================================================
     161             :  *
     162             :  * EntryCache implementation.
     163             :  *
     164             :  *======================================================================*/
     165             : 
     166      531620 : EntryCache & EntryCache::get()
     167             : {
     168      531620 :     static EntryCache g_entry_cache;
     169      531620 :     return g_entry_cache;
     170             : }
     171             : 
     172         422 : EntryCache::EntryCache()
     173             : {
     174             :     m_entry_cache = rtl_cache_create (
     175             :         "store_cache_entry_cache",
     176             :         sizeof(Entry),
     177             :         0, // objalign
     178             :         0, // constructor
     179             :         0, // destructor
     180             :         0, // reclaim
     181             :         0, // userarg
     182             :         0, // default source
     183             :         0  // flags
     184         422 :         );
     185         422 : }
     186             : 
     187         422 : EntryCache::~EntryCache()
     188             : {
     189         422 :     rtl_cache_destroy (m_entry_cache), m_entry_cache = 0;
     190         422 : }
     191             : 
     192      297445 : Entry * EntryCache::create (PageHolder const & rxPage, sal_uInt32 nOffset)
     193             : {
     194      297445 :     void * pAddr = rtl_cache_alloc (m_entry_cache);
     195      297445 :     if (pAddr != 0)
     196             :     {
     197             :         // construct.
     198      297445 :         return new(pAddr) Entry (rxPage, nOffset);
     199             :     }
     200           0 :     return 0;
     201             : }
     202             : 
     203      234175 : void EntryCache::destroy (Entry * entry)
     204             : {
     205      234175 :     if (entry != 0)
     206             :     {
     207             :         // destruct.
     208      234175 :         entry->~Entry();
     209             : 
     210             :         // return to cache.
     211      234175 :         rtl_cache_free (m_entry_cache, entry);
     212             :     }
     213      234175 : }
     214             : 
     215             : /*========================================================================
     216             :  *
     217             :  * highbit():= log2() + 1 (complexity O(1))
     218             :  *
     219             :  *======================================================================*/
     220       21665 : static int highbit(sal_Size n)
     221             : {
     222       21665 :     register int k = 1;
     223             : 
     224       21665 :     if (n == 0)
     225           0 :         return (0);
     226             : #if SAL_TYPES_SIZEOFLONG == 8
     227             :     if (n & 0xffffffff00000000ul)
     228             :         k |= 32, n >>= 32;
     229             : #endif
     230       21665 :     if (n & 0xffff0000)
     231           0 :         k |= 16, n >>= 16;
     232       21665 :     if (n & 0xff00)
     233       10806 :         k |= 8, n >>= 8;
     234       21665 :     if (n & 0xf0)
     235       10867 :         k |= 4, n >>= 4;
     236       21665 :     if (n & 0x0c)
     237         121 :         k |= 2, n >>= 2;
     238       21665 :     if (n & 0x02)
     239       21550 :         k++;
     240             : 
     241       21665 :     return (k);
     242             : }
     243             : 
     244             : /*========================================================================
     245             :  *
     246             :  * PageCache_Impl implementation.
     247             :  *
     248             :  *======================================================================*/
     249             : namespace store
     250             : {
     251             : 
     252             : class PageCache_Impl :
     253             :     public store::OStoreObject,
     254             :     public store::PageCache
     255             : {
     256             :     /** Representation.
     257             :      */
     258             :     static size_t const theTableSize = 32;
     259             :     STORE_STATIC_ASSERT(STORE_IMPL_ISP2(theTableSize));
     260             : 
     261             :     Entry **     m_hash_table;
     262             :     Entry *      m_hash_table_0[theTableSize];
     263             :     size_t       m_hash_size;
     264             :     size_t       m_hash_shift;
     265             :     size_t const m_page_shift;
     266             : 
     267             :     size_t       m_hash_entries; // total number of entries in table.
     268             :     size_t       m_nHit;
     269             :     size_t       m_nMissed;
     270             : 
     271     3255553 :     inline int hash_Impl(sal_uInt32 a, size_t s, size_t q, size_t m)
     272             :     {
     273     3255553 :         return ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m));
     274             :     }
     275     3255553 :     inline int hash_index_Impl (sal_uInt32 nOffset)
     276             :     {
     277     3255553 :         return hash_Impl(nOffset, m_hash_shift, m_page_shift, m_hash_size - 1);
     278             :     }
     279             : 
     280             :     Entry * lookup_Impl (Entry * entry, sal_uInt32 nOffset);
     281             :     void rescale_Impl (sal_Size new_size);
     282             : 
     283             :     /** PageCache Implementation.
     284             :      */
     285             :     virtual storeError lookupPageAt_Impl (
     286             :         PageHolder & rxPage,
     287             :         sal_uInt32   nOffset);
     288             : 
     289             :     virtual storeError insertPageAt_Impl (
     290             :         PageHolder const & rxPage,
     291             :         sal_uInt32         nOffset);
     292             : 
     293             :     virtual storeError updatePageAt_Impl (
     294             :         PageHolder const & rxPage,
     295             :         sal_uInt32         nOffset);
     296             : 
     297             :     virtual storeError removePageAt_Impl (
     298             :         sal_uInt32 nOffset);
     299             : 
     300             :     /** Not implemented.
     301             :      */
     302             :     PageCache_Impl (PageCache_Impl const &);
     303             :     PageCache_Impl & operator= (PageCache_Impl const &);
     304             : 
     305             : public:
     306             :     /** Construction.
     307             :      */
     308             :     explicit PageCache_Impl (sal_uInt16 nPageSize);
     309             : 
     310             :     /** Delegate multiple inherited IReference.
     311             :      */
     312             :     virtual oslInterlockedCount SAL_CALL acquire();
     313             :     virtual oslInterlockedCount SAL_CALL release();
     314             : 
     315             : protected:
     316             :     /** Destruction.
     317             :      */
     318             :     virtual ~PageCache_Impl (void);
     319             : };
     320             : 
     321             : } // namespace store
     322             : 
     323       10724 : PageCache_Impl::PageCache_Impl (sal_uInt16 nPageSize)
     324             :     : m_hash_table   (m_hash_table_0),
     325             :       m_hash_size    (theTableSize),
     326       10724 :       m_hash_shift   (highbit(m_hash_size) - 1),
     327       10724 :       m_page_shift   (highbit(nPageSize) - 1),
     328             :       m_hash_entries (0),
     329             :       m_nHit         (0),
     330       32172 :       m_nMissed      (0)
     331             : {
     332             :     static size_t const theSize = SAL_N_ELEMENTS(m_hash_table_0);
     333             :     STORE_STATIC_ASSERT(theSize == theTableSize);
     334       10724 :     memset(m_hash_table_0, 0, sizeof(m_hash_table_0));
     335       10724 : }
     336             : 
     337       31383 : PageCache_Impl::~PageCache_Impl()
     338             : {
     339       10461 :     double s_x = 0.0;
     340       10461 :     sal_Size i, n = m_hash_size;
     341      371709 :     for (i = 0; i < n; i++)
     342             :     {
     343      361248 :         int x = 0;
     344      361248 :         Entry * entry = m_hash_table[i];
     345      956663 :         while (entry != 0)
     346             :         {
     347      234167 :             m_hash_table[i] = entry->m_pNext, entry->m_pNext = 0;
     348      234167 :             EntryCache::get().destroy (entry);
     349      234167 :             entry = m_hash_table[i];
     350      234167 :             x += 1;
     351             :         }
     352      361248 :         s_x  += double(x);
     353             :     }
     354       10461 :     double ave = s_x / double(n);
     355             :     OSL_TRACE("ave hash chain length: %g", ave);
     356             :     (void) ave;
     357             : 
     358       10461 :     if (m_hash_table != m_hash_table_0)
     359             :     {
     360          32 :         rtl_freeMemory (m_hash_table);
     361          32 :         m_hash_table = m_hash_table_0;
     362          32 :         m_hash_size  = theTableSize;
     363          32 :         m_hash_shift = highbit(m_hash_size) - 1;
     364             :     }
     365             :     OSL_TRACE("Hits: %u, Misses: %u", m_nHit, m_nMissed);
     366       20922 : }
     367             : 
     368       10724 : oslInterlockedCount PageCache_Impl::acquire()
     369             : {
     370       10724 :     return OStoreObject::acquire();
     371             : }
     372             : 
     373       10461 : oslInterlockedCount PageCache_Impl::release()
     374             : {
     375       10461 :     return OStoreObject::release();
     376             : }
     377             : 
     378         185 : void PageCache_Impl::rescale_Impl (sal_Size new_size)
     379             : {
     380         185 :     sal_Size new_bytes = new_size * sizeof(Entry*);
     381         185 :     Entry ** new_table = (Entry**)(rtl_allocateMemory(new_bytes));
     382             : 
     383         185 :     if (new_table != 0)
     384             :     {
     385         185 :         Entry ** old_table = m_hash_table;
     386         185 :         sal_Size old_size  = m_hash_size;
     387             : 
     388             :         OSL_TRACE("ave chain length: %u, total entries: %u [old_size: %u, new_size: %u]",
     389             :                   m_hash_entries >> m_hash_shift, m_hash_entries, old_size, new_size);
     390             : 
     391         185 :         memset (new_table, 0, new_bytes);
     392             : 
     393         185 :         m_hash_table = new_table;
     394         185 :         m_hash_size  = new_size;
     395         185 :         m_hash_shift = highbit(m_hash_size) - 1;
     396             : 
     397             :         sal_Size i;
     398       44153 :         for (i = 0; i < old_size; i++)
     399             :         {
     400       43968 :             Entry * curr = old_table[i];
     401      307780 :             while (curr != 0)
     402             :             {
     403      219844 :                 Entry * next = curr->m_pNext;
     404      219844 :                 int index = hash_index_Impl(curr->m_nOffset);
     405      219844 :                 curr->m_pNext = m_hash_table[index], m_hash_table[index] = curr;
     406      219844 :                 curr = next;
     407             :             }
     408       43968 :             old_table[i] = 0;
     409             :         }
     410         185 :         if (old_table != m_hash_table_0)
     411             :         {
     412             :             //
     413         125 :             rtl_freeMemory (old_table);
     414             :         }
     415             :     }
     416         185 : }
     417             : 
     418     2738256 : Entry * PageCache_Impl::lookup_Impl (Entry * entry, sal_uInt32 nOffset)
     419             : {
     420     2738256 :     register int lookups = 0;
     421     9549039 :     while (entry != 0)
     422             :     {
     423     6508140 :         if (entry->m_nOffset == nOffset)
     424     2435613 :             break;
     425             : 
     426     4072527 :         lookups += 1;
     427     4072527 :         entry = entry->m_pNext;
     428             :     }
     429     2738256 :     if (lookups > 2)
     430             :     {
     431      693894 :         sal_Size new_size = m_hash_size, ave = m_hash_entries >> m_hash_shift;
     432      694079 :         for (; ave > 4; new_size *= 2, ave /= 2)
     433         185 :             continue;
     434      693894 :         if (new_size != m_hash_size)
     435         185 :             rescale_Impl (new_size);
     436             :     }
     437     2738256 :     return entry;
     438             : }
     439             : 
     440     2465449 : storeError PageCache_Impl::lookupPageAt_Impl (
     441             :     PageHolder & rxPage,
     442             :     sal_uInt32   nOffset)
     443             : {
     444     2465449 :     int index = hash_index_Impl(nOffset);
     445     2465449 :     Entry const * entry = lookup_Impl (m_hash_table[index], nOffset);
     446     2465449 :     if (entry != 0)
     447             :     {
     448             :         // Existing entry.
     449     2270528 :         rxPage = entry->m_xPage;
     450             : 
     451             :         // Update stats and leave.
     452     2270528 :         m_nHit += 1;
     453     2270528 :         return store_E_None;
     454             :     }
     455             : 
     456             :     // Cache miss. Update stats and leave.
     457      194921 :     m_nMissed += 1;
     458      194921 :     return store_E_NotExists;
     459             : }
     460             : 
     461      297445 : storeError PageCache_Impl::insertPageAt_Impl (
     462             :     PageHolder const & rxPage,
     463             :     sal_uInt32         nOffset)
     464             : {
     465      297445 :     Entry * entry = EntryCache::get().create (rxPage, nOffset);
     466      297445 :     if (entry != 0)
     467             :     {
     468             :         // Insert new entry.
     469      297445 :         int index = hash_index_Impl(nOffset);
     470      297445 :         entry->m_pNext = m_hash_table[index], m_hash_table[index] = entry;
     471             : 
     472             :         // Update stats and leave.
     473      297445 :         m_hash_entries += 1;
     474      297445 :         return store_E_None;
     475             :     }
     476           0 :     return store_E_OutOfMemory;
     477             : }
     478             : 
     479      272807 : storeError PageCache_Impl::updatePageAt_Impl (
     480             :     PageHolder const & rxPage,
     481             :     sal_uInt32         nOffset)
     482             : {
     483      272807 :     int index = hash_index_Impl(nOffset);
     484      272807 :     Entry *  entry  = lookup_Impl (m_hash_table[index], nOffset);
     485      272807 :     if (entry != 0)
     486             :     {
     487             :         // Update existing entry.
     488      165085 :         entry->m_xPage = rxPage;
     489             : 
     490             :         // Update stats and leave. // m_nUpdHit += 1;
     491      165085 :         return store_E_None;
     492             :     }
     493      107722 :     return insertPageAt_Impl (rxPage, nOffset);
     494             : }
     495             : 
     496           8 : storeError PageCache_Impl::removePageAt_Impl (
     497             :     sal_uInt32 nOffset)
     498             : {
     499           8 :     Entry ** ppEntry = &(m_hash_table[hash_index_Impl(nOffset)]);
     500          25 :     while (*ppEntry != 0)
     501             :     {
     502          17 :         if ((*ppEntry)->m_nOffset == nOffset)
     503             :         {
     504             :             // Existing entry.
     505           8 :             Entry * entry = (*ppEntry);
     506             : 
     507             :             // Dequeue and destroy entry.
     508           8 :             (*ppEntry) = entry->m_pNext, entry->m_pNext = 0;
     509           8 :             EntryCache::get().destroy (entry);
     510             : 
     511             :             // Update stats and leave.
     512           8 :             m_hash_entries -= 1;
     513           8 :             return store_E_None;
     514             :         }
     515           9 :         ppEntry = &((*ppEntry)->m_pNext);
     516             :     }
     517           0 :     return store_E_NotExists;
     518             : }
     519             : 
     520             : /*========================================================================
     521             :  *
     522             :  * Old OStorePageCache implementation.
     523             :  *
     524             :  * (two-way association (sorted address array, LRU chain)).
     525             :  * (external OStorePageData representation).
     526             :  *
     527             :  *======================================================================*/
     528             : 
     529             : /*========================================================================
     530             :  *
     531             :  * PageCache factory implementation.
     532             :  *
     533             :  *======================================================================*/
     534             : namespace store {
     535             : 
     536             : storeError
     537       10724 : PageCache_createInstance (
     538             :     rtl::Reference< store::PageCache > & rxCache,
     539             :     sal_uInt16                           nPageSize)
     540             : {
     541       10724 :     rxCache = new PageCache_Impl (nPageSize);
     542       10724 :     if (!rxCache.is())
     543           0 :         return store_E_OutOfMemory;
     544             : 
     545       10724 :     return store_E_None;
     546             : }
     547             : 
     548             : } // namespace store
     549             : 
     550             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10