1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "storcach.hxx"
32 #include "sal/types.h"
33 #include "sal/macros.h"
34 #include "rtl/alloc.h"
35 #include "osl/diagnose.h"
37 #include "store/types.h"
39 #include "storbase.hxx"
41 #ifndef INCLUDED_STDDEF_H
43 #define INCLUDED_STDDEF_H
46 using namespace store
;
48 /*========================================================================
50 * PageCache (non-virtual interface) implementation.
52 *======================================================================*/
54 storeError
PageCache::lookupPageAt (PageHolder
& rxPage
, sal_uInt32 nOffset
)
56 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::lookupPageAt(): invalid Offset");
57 if (nOffset
== STORE_PAGE_NULL
)
58 return store_E_CantSeek
;
60 return lookupPageAt_Impl (rxPage
, nOffset
);
63 storeError
PageCache::insertPageAt (PageHolder
const & rxPage
, sal_uInt32 nOffset
)
65 // [SECURITY:ValInput]
66 PageData
const * pagedata
= rxPage
.get();
67 OSL_PRECOND(!(pagedata
== 0), "store::PageCache::insertPageAt(): invalid Page");
69 return store_E_InvalidParameter
;
71 sal_uInt32
const offset
= pagedata
->location();
72 OSL_PRECOND(!(nOffset
!= offset
), "store::PageCache::insertPageAt(): inconsistent Offset");
73 if (nOffset
!= offset
)
74 return store_E_InvalidParameter
;
76 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::insertPageAt(): invalid Offset");
77 if (nOffset
== STORE_PAGE_NULL
)
78 return store_E_CantSeek
;
80 return insertPageAt_Impl (rxPage
, nOffset
);
83 storeError
PageCache::updatePageAt (PageHolder
const & rxPage
, sal_uInt32 nOffset
)
85 // [SECURITY:ValInput]
86 PageData
const * pagedata
= rxPage
.get();
87 OSL_PRECOND(!(pagedata
== 0), "store::PageCache::updatePageAt(): invalid Page");
89 return store_E_InvalidParameter
;
91 sal_uInt32
const offset
= pagedata
->location();
92 OSL_PRECOND(!(nOffset
!= offset
), "store::PageCache::updatePageAt(): inconsistent Offset");
93 if (nOffset
!= offset
)
94 return store_E_InvalidParameter
;
96 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::updatePageAt(): invalid Offset");
97 if (nOffset
== STORE_PAGE_NULL
)
98 return store_E_CantSeek
;
100 return updatePageAt_Impl (rxPage
, nOffset
);
103 storeError
PageCache::removePageAt (sal_uInt32 nOffset
)
105 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::removePageAt(): invalid Offset");
106 if (nOffset
== STORE_PAGE_NULL
)
107 return store_E_CantSeek
;
109 return removePageAt_Impl (nOffset
);
112 /*========================================================================
116 *======================================================================*/
125 sal_uInt32 m_nOffset
;
130 static void * operator new (size_t, void * p
) { return p
; }
131 static void operator delete (void *, void *) {}
135 explicit Entry (PageHolder
const & rxPage
= PageHolder(), sal_uInt32 nOffset
= STORE_PAGE_NULL
)
136 : m_xPage(rxPage
), m_nOffset(nOffset
), m_pNext(0)
146 /*========================================================================
148 * EntryCache interface.
150 *======================================================================*/
156 rtl_cache_type
* m_entry_cache
;
159 static EntryCache
& get();
161 Entry
* create (PageHolder
const & rxPage
, sal_uInt32 nOffset
);
163 void destroy (Entry
* entry
);
172 /*========================================================================
174 * EntryCache implementation.
176 *======================================================================*/
178 EntryCache
& EntryCache::get()
180 static EntryCache g_entry_cache
;
181 return g_entry_cache
;
184 EntryCache::EntryCache()
186 m_entry_cache
= rtl_cache_create (
187 "store_cache_entry_cache",
199 EntryCache::~EntryCache()
201 rtl_cache_destroy (m_entry_cache
), m_entry_cache
= 0;
204 Entry
* EntryCache::create (PageHolder
const & rxPage
, sal_uInt32 nOffset
)
206 void * pAddr
= rtl_cache_alloc (m_entry_cache
);
210 return new(pAddr
) Entry (rxPage
, nOffset
);
215 void EntryCache::destroy (Entry
* entry
)
223 rtl_cache_free (m_entry_cache
, entry
);
227 /*========================================================================
229 * highbit():= log2() + 1 (complexity O(1))
231 *======================================================================*/
232 static int highbit(sal_Size n
)
238 #if SAL_TYPES_SIZEOFLONG == 8
239 if (n
& 0xffffffff00000000ul
)
256 /*========================================================================
258 * PageCache_Impl implementation.
260 *======================================================================*/
264 class PageCache_Impl
:
265 public store::OStoreObject
,
266 public store::PageCache
270 static size_t const theTableSize
= 32;
271 STORE_STATIC_ASSERT(STORE_IMPL_ISP2(theTableSize
));
273 Entry
** m_hash_table
;
274 Entry
* m_hash_table_0
[theTableSize
];
277 size_t const m_page_shift
;
279 size_t m_hash_entries
; // total number of entries in table.
283 inline int hash_Impl(sal_uInt32 a
, size_t s
, size_t q
, size_t m
)
285 return ((((a
) + ((a
) >> (s
)) + ((a
) >> ((s
) << 1))) >> (q
)) & (m
));
287 inline int hash_index_Impl (sal_uInt32 nOffset
)
289 return hash_Impl(nOffset
, m_hash_shift
, m_page_shift
, m_hash_size
- 1);
292 Entry
* lookup_Impl (Entry
* entry
, sal_uInt32 nOffset
);
293 void rescale_Impl (sal_Size new_size
);
295 /** PageCache Implementation.
297 virtual storeError
lookupPageAt_Impl (
301 virtual storeError
insertPageAt_Impl (
302 PageHolder
const & rxPage
,
305 virtual storeError
updatePageAt_Impl (
306 PageHolder
const & rxPage
,
309 virtual storeError
removePageAt_Impl (
314 PageCache_Impl (PageCache_Impl
const &);
315 PageCache_Impl
& operator= (PageCache_Impl
const &);
320 explicit PageCache_Impl (sal_uInt16 nPageSize
);
322 /** Delegate multiple inherited IReference.
324 virtual oslInterlockedCount SAL_CALL
acquire();
325 virtual oslInterlockedCount SAL_CALL
release();
330 virtual ~PageCache_Impl (void);
335 PageCache_Impl::PageCache_Impl (sal_uInt16 nPageSize
)
336 : m_hash_table (m_hash_table_0
),
337 m_hash_size (theTableSize
),
338 m_hash_shift (highbit(m_hash_size
) - 1),
339 m_page_shift (highbit(nPageSize
) - 1),
344 static size_t const theSize
= SAL_N_ELEMENTS(m_hash_table_0
);
345 STORE_STATIC_ASSERT(theSize
== theTableSize
);
346 memset(m_hash_table_0
, 0, sizeof(m_hash_table_0
));
349 PageCache_Impl::~PageCache_Impl()
352 sal_Size i
, n
= m_hash_size
;
353 for (i
= 0; i
< n
; i
++)
356 Entry
* entry
= m_hash_table
[i
];
359 m_hash_table
[i
] = entry
->m_pNext
, entry
->m_pNext
= 0;
360 EntryCache::get().destroy (entry
);
361 entry
= m_hash_table
[i
];
366 double ave
= s_x
/ double(n
);
367 OSL_TRACE("ave hash chain length: %g", ave
);
370 if (m_hash_table
!= m_hash_table_0
)
372 rtl_freeMemory (m_hash_table
);
373 m_hash_table
= m_hash_table_0
;
374 m_hash_size
= theTableSize
;
375 m_hash_shift
= highbit(m_hash_size
) - 1;
377 OSL_TRACE("Hits: %u, Misses: %u", m_nHit
, m_nMissed
);
380 oslInterlockedCount
PageCache_Impl::acquire()
382 return OStoreObject::acquire();
385 oslInterlockedCount
PageCache_Impl::release()
387 return OStoreObject::release();
390 void PageCache_Impl::rescale_Impl (sal_Size new_size
)
392 sal_Size new_bytes
= new_size
* sizeof(Entry
*);
393 Entry
** new_table
= (Entry
**)(rtl_allocateMemory(new_bytes
));
397 Entry
** old_table
= m_hash_table
;
398 sal_Size old_size
= m_hash_size
;
400 OSL_TRACE("ave chain length: %u, total entries: %u [old_size: %u, new_size: %u]",
401 m_hash_entries
>> m_hash_shift
, m_hash_entries
, old_size
, new_size
);
403 memset (new_table
, 0, new_bytes
);
405 m_hash_table
= new_table
;
406 m_hash_size
= new_size
;
407 m_hash_shift
= highbit(m_hash_size
) - 1;
410 for (i
= 0; i
< old_size
; i
++)
412 Entry
* curr
= old_table
[i
];
415 Entry
* next
= curr
->m_pNext
;
416 int index
= hash_index_Impl(curr
->m_nOffset
);
417 curr
->m_pNext
= m_hash_table
[index
], m_hash_table
[index
] = curr
;
422 if (old_table
!= m_hash_table_0
)
425 rtl_freeMemory (old_table
);
430 Entry
* PageCache_Impl::lookup_Impl (Entry
* entry
, sal_uInt32 nOffset
)
432 register int lookups
= 0;
435 if (entry
->m_nOffset
== nOffset
)
439 entry
= entry
->m_pNext
;
443 sal_Size new_size
= m_hash_size
, ave
= m_hash_entries
>> m_hash_shift
;
444 for (; ave
> 4; new_size
*= 2, ave
/= 2)
446 if (new_size
!= m_hash_size
)
447 rescale_Impl (new_size
);
452 storeError
PageCache_Impl::lookupPageAt_Impl (
456 int index
= hash_index_Impl(nOffset
);
457 Entry
const * entry
= lookup_Impl (m_hash_table
[index
], nOffset
);
461 rxPage
= entry
->m_xPage
;
463 // Update stats and leave.
468 // Cache miss. Update stats and leave.
470 return store_E_NotExists
;
473 storeError
PageCache_Impl::insertPageAt_Impl (
474 PageHolder
const & rxPage
,
477 Entry
* entry
= EntryCache::get().create (rxPage
, nOffset
);
481 int index
= hash_index_Impl(nOffset
);
482 entry
->m_pNext
= m_hash_table
[index
], m_hash_table
[index
] = entry
;
484 // Update stats and leave.
488 return store_E_OutOfMemory
;
491 storeError
PageCache_Impl::updatePageAt_Impl (
492 PageHolder
const & rxPage
,
495 int index
= hash_index_Impl(nOffset
);
496 Entry
* entry
= lookup_Impl (m_hash_table
[index
], nOffset
);
499 // Update existing entry.
500 entry
->m_xPage
= rxPage
;
502 // Update stats and leave. // m_nUpdHit += 1;
505 return insertPageAt_Impl (rxPage
, nOffset
);
508 storeError
PageCache_Impl::removePageAt_Impl (
511 Entry
** ppEntry
= &(m_hash_table
[hash_index_Impl(nOffset
)]);
512 while (*ppEntry
!= 0)
514 if ((*ppEntry
)->m_nOffset
== nOffset
)
517 Entry
* entry
= (*ppEntry
);
519 // Dequeue and destroy entry.
520 (*ppEntry
) = entry
->m_pNext
, entry
->m_pNext
= 0;
521 EntryCache::get().destroy (entry
);
523 // Update stats and leave.
527 ppEntry
= &((*ppEntry
)->m_pNext
);
529 return store_E_NotExists
;
532 /*========================================================================
534 * Old OStorePageCache implementation.
536 * (two-way association (sorted address array, LRU chain)).
537 * (external OStorePageData representation).
539 *======================================================================*/
541 /*========================================================================
543 * PageCache factory implementation.
545 *======================================================================*/
549 PageCache_createInstance (
550 rtl::Reference
< store::PageCache
> & rxCache
,
551 sal_uInt16 nPageSize
)
553 rxCache
= new PageCache_Impl (nPageSize
);
555 return store_E_OutOfMemory
;
562 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */