1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: storcach.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_store.hxx"
34 #include "storcach.hxx"
36 #include "sal/types.h"
37 #include "rtl/alloc.h"
38 #include "osl/diagnose.h"
40 #include "store/types.h"
42 #include "storbase.hxx"
44 #ifndef INCLUDED_STDDEF_H
46 #define INCLUDED_STDDEF_H
49 using namespace store
;
51 /*========================================================================
53 * PageCache (non-virtual interface) implementation.
55 *======================================================================*/
57 storeError
PageCache::lookupPageAt (PageHolder
& rxPage
, sal_uInt32 nOffset
)
59 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::lookupPageAt(): invalid Offset");
60 if (nOffset
== STORE_PAGE_NULL
)
61 return store_E_CantSeek
;
63 return lookupPageAt_Impl (rxPage
, nOffset
);
66 storeError
PageCache::insertPageAt (PageHolder
const & rxPage
, sal_uInt32 nOffset
)
68 // [SECURITY:ValInput]
69 PageData
const * pagedata
= rxPage
.get();
70 OSL_PRECOND(!(pagedata
== 0), "store::PageCache::insertPageAt(): invalid Page");
72 return store_E_InvalidParameter
;
74 sal_uInt32
const offset
= pagedata
->location();
75 OSL_PRECOND(!(nOffset
!= offset
), "store::PageCache::insertPageAt(): inconsistent Offset");
76 if (nOffset
!= offset
)
77 return store_E_InvalidParameter
;
79 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::insertPageAt(): invalid Offset");
80 if (nOffset
== STORE_PAGE_NULL
)
81 return store_E_CantSeek
;
83 return insertPageAt_Impl (rxPage
, nOffset
);
86 storeError
PageCache::updatePageAt (PageHolder
const & rxPage
, sal_uInt32 nOffset
)
88 // [SECURITY:ValInput]
89 PageData
const * pagedata
= rxPage
.get();
90 OSL_PRECOND(!(pagedata
== 0), "store::PageCache::updatePageAt(): invalid Page");
92 return store_E_InvalidParameter
;
94 sal_uInt32
const offset
= pagedata
->location();
95 OSL_PRECOND(!(nOffset
!= offset
), "store::PageCache::updatePageAt(): inconsistent Offset");
96 if (nOffset
!= offset
)
97 return store_E_InvalidParameter
;
99 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::updatePageAt(): invalid Offset");
100 if (nOffset
== STORE_PAGE_NULL
)
101 return store_E_CantSeek
;
103 return updatePageAt_Impl (rxPage
, nOffset
);
106 storeError
PageCache::removePageAt (sal_uInt32 nOffset
)
108 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::removePageAt(): invalid Offset");
109 if (nOffset
== STORE_PAGE_NULL
)
110 return store_E_CantSeek
;
112 return removePageAt_Impl (nOffset
);
115 /*========================================================================
119 *======================================================================*/
128 sal_uInt32 m_nOffset
;
133 static void * operator new (size_t, void * p
) { return p
; }
134 static void operator delete (void *, void *) {}
138 explicit Entry (PageHolder
const & rxPage
= PageHolder(), sal_uInt32 nOffset
= STORE_PAGE_NULL
)
139 : m_xPage(rxPage
), m_nOffset(nOffset
), m_pNext(0)
149 /*========================================================================
151 * EntryCache interface.
153 *======================================================================*/
159 rtl_cache_type
* m_entry_cache
;
162 static EntryCache
& get();
164 Entry
* create (PageHolder
const & rxPage
, sal_uInt32 nOffset
);
166 void destroy (Entry
* entry
);
175 /*========================================================================
177 * EntryCache implementation.
179 *======================================================================*/
181 EntryCache
& EntryCache::get()
183 static EntryCache g_entry_cache
;
184 return g_entry_cache
;
187 EntryCache::EntryCache()
189 m_entry_cache
= rtl_cache_create (
190 "store_cache_entry_cache",
202 EntryCache::~EntryCache()
204 rtl_cache_destroy (m_entry_cache
), m_entry_cache
= 0;
207 Entry
* EntryCache::create (PageHolder
const & rxPage
, sal_uInt32 nOffset
)
209 void * pAddr
= rtl_cache_alloc (m_entry_cache
);
213 return new(pAddr
) Entry (rxPage
, nOffset
);
218 void EntryCache::destroy (Entry
* entry
)
226 rtl_cache_free (m_entry_cache
, entry
);
230 /*========================================================================
232 * highbit():= log2() + 1 (complexity O(1))
234 *======================================================================*/
235 static int highbit(sal_Size n
)
241 #if SAL_TYPES_SIZEOFLONG == 8
242 if (n
& 0xffffffff00000000ul
)
259 /*========================================================================
261 * PageCache_Impl implementation.
263 *======================================================================*/
267 class PageCache_Impl
:
268 public store::OStoreObject
,
269 public store::PageCache
273 static size_t const theTableSize
= 32;
274 STORE_STATIC_ASSERT(STORE_IMPL_ISP2(theTableSize
));
276 Entry
** m_hash_table
;
277 Entry
* m_hash_table_0
[theTableSize
];
280 size_t const m_page_shift
;
282 size_t m_hash_entries
; // total number of entries in table.
286 inline int hash_Impl(sal_uInt32 a
, size_t s
, size_t q
, size_t m
)
288 return ((((a
) + ((a
) >> (s
)) + ((a
) >> ((s
) << 1))) >> (q
)) & (m
));
290 inline int hash_index_Impl (sal_uInt32 nOffset
)
292 return hash_Impl(nOffset
, m_hash_shift
, m_page_shift
, m_hash_size
- 1);
295 Entry
* lookup_Impl (Entry
* entry
, sal_uInt32 nOffset
);
296 void rescale_Impl (sal_Size new_size
);
298 /** PageCache Implementation.
300 virtual storeError
lookupPageAt_Impl (
304 virtual storeError
insertPageAt_Impl (
305 PageHolder
const & rxPage
,
308 virtual storeError
updatePageAt_Impl (
309 PageHolder
const & rxPage
,
312 virtual storeError
removePageAt_Impl (
317 PageCache_Impl (PageCache_Impl
const &);
318 PageCache_Impl
& operator= (PageCache_Impl
const &);
323 explicit PageCache_Impl (sal_uInt16 nPageSize
);
325 /** Delegate multiple inherited IReference.
327 virtual oslInterlockedCount SAL_CALL
acquire();
328 virtual oslInterlockedCount SAL_CALL
release();
333 virtual ~PageCache_Impl (void);
338 PageCache_Impl::PageCache_Impl (sal_uInt16 nPageSize
)
339 : m_hash_table (m_hash_table_0
),
340 m_hash_size (theTableSize
),
341 m_hash_shift (highbit(m_hash_size
) - 1),
342 m_page_shift (highbit(nPageSize
) - 1),
347 static size_t const theSize
= sizeof(m_hash_table_0
) / sizeof(m_hash_table_0
[0]);
348 STORE_STATIC_ASSERT(theSize
== theTableSize
);
349 memset(m_hash_table_0
, 0, sizeof(m_hash_table_0
));
352 PageCache_Impl::~PageCache_Impl()
354 double s_x
= 0.0, s_xx
= 0.0;
355 sal_Size i
, n
= m_hash_size
;
356 for (i
= 0; i
< n
; i
++)
359 Entry
* entry
= m_hash_table
[i
];
362 m_hash_table
[i
] = entry
->m_pNext
, entry
->m_pNext
= 0;
363 EntryCache::get().destroy (entry
);
364 entry
= m_hash_table
[i
];
368 s_xx
+= double(x
) * double(x
);
370 double ave
= s_x
/ double(n
);
371 OSL_TRACE("ave hash chain length: %g", ave
);
374 if (m_hash_table
!= m_hash_table_0
)
376 rtl_freeMemory (m_hash_table
);
377 m_hash_table
= m_hash_table_0
;
378 m_hash_size
= theTableSize
;
379 m_hash_shift
= highbit(m_hash_size
) - 1;
381 OSL_TRACE("Hits: %u, Misses: %u", m_nHit
, m_nMissed
);
384 oslInterlockedCount
PageCache_Impl::acquire()
386 return OStoreObject::acquire();
389 oslInterlockedCount
PageCache_Impl::release()
391 return OStoreObject::release();
394 void PageCache_Impl::rescale_Impl (sal_Size new_size
)
396 sal_Size new_bytes
= new_size
* sizeof(Entry
*);
397 Entry
** new_table
= (Entry
**)(rtl_allocateMemory(new_bytes
));
401 Entry
** old_table
= m_hash_table
;
402 sal_Size old_size
= m_hash_size
;
404 OSL_TRACE("ave chain length: %u, total entries: %u [old_size: %u, new_size: %u]",
405 m_hash_entries
>> m_hash_shift
, m_hash_entries
, old_size
, new_size
);
407 memset (new_table
, 0, new_bytes
);
409 m_hash_table
= new_table
;
410 m_hash_size
= new_size
;
411 m_hash_shift
= highbit(m_hash_size
) - 1;
414 for (i
= 0; i
< old_size
; i
++)
416 Entry
* curr
= old_table
[i
];
419 Entry
* next
= curr
->m_pNext
;
420 int index
= hash_index_Impl(curr
->m_nOffset
);
421 curr
->m_pNext
= m_hash_table
[index
], m_hash_table
[index
] = curr
;
426 if (old_table
!= m_hash_table_0
)
429 rtl_freeMemory (old_table
);
434 Entry
* PageCache_Impl::lookup_Impl (Entry
* entry
, sal_uInt32 nOffset
)
436 register int lookups
= 0;
439 if (entry
->m_nOffset
== nOffset
)
443 entry
= entry
->m_pNext
;
447 sal_Size new_size
= m_hash_size
, ave
= m_hash_entries
>> m_hash_shift
;
448 for (; ave
> 4; new_size
*= 2, ave
/= 2)
450 if (new_size
!= m_hash_size
)
451 rescale_Impl (new_size
);
456 storeError
PageCache_Impl::lookupPageAt_Impl (
460 int index
= hash_index_Impl(nOffset
);
461 Entry
const * entry
= lookup_Impl (m_hash_table
[index
], nOffset
);
465 rxPage
= entry
->m_xPage
;
467 // Update stats and leave.
472 // Cache miss. Update stats and leave.
474 return store_E_NotExists
;
477 storeError
PageCache_Impl::insertPageAt_Impl (
478 PageHolder
const & rxPage
,
481 Entry
* entry
= EntryCache::get().create (rxPage
, nOffset
);
485 int index
= hash_index_Impl(nOffset
);
486 entry
->m_pNext
= m_hash_table
[index
], m_hash_table
[index
] = entry
;
488 // Update stats and leave.
492 return store_E_OutOfMemory
;
495 storeError
PageCache_Impl::updatePageAt_Impl (
496 PageHolder
const & rxPage
,
499 int index
= hash_index_Impl(nOffset
);
500 Entry
* entry
= lookup_Impl (m_hash_table
[index
], nOffset
);
503 // Update existing entry.
504 entry
->m_xPage
= rxPage
;
506 // Update stats and leave. // m_nUpdHit += 1;
509 return insertPageAt_Impl (rxPage
, nOffset
);
512 storeError
PageCache_Impl::removePageAt_Impl (
515 Entry
** ppEntry
= &(m_hash_table
[hash_index_Impl(nOffset
)]);
516 while (*ppEntry
!= 0)
518 if ((*ppEntry
)->m_nOffset
== nOffset
)
521 Entry
* entry
= (*ppEntry
);
523 // Dequeue and destroy entry.
524 (*ppEntry
) = entry
->m_pNext
, entry
->m_pNext
= 0;
525 EntryCache::get().destroy (entry
);
527 // Update stats and leave.
531 ppEntry
= &((*ppEntry
)->m_pNext
);
533 return store_E_NotExists
;
536 /*========================================================================
538 * Old OStorePageCache implementation.
540 * (two-way association (sorted address array, LRU chain)).
541 * (external OStorePageData representation).
543 *======================================================================*/
545 /*========================================================================
547 * PageCache factory implementation.
549 *======================================================================*/
553 PageCache_createInstance (
554 rtl::Reference
< store::PageCache
> & rxCache
,
555 sal_uInt16 nPageSize
)
557 rxCache
= new PageCache_Impl (nPageSize
);
559 return store_E_OutOfMemory
;