1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include "storcach.hxx"
24 #include <sal/log.hxx>
25 #include <sal/types.h>
26 #include <sal/macros.h>
27 #include <rtl/alloc.h>
28 #include <osl/diagnose.h>
30 #include <store/types.h>
31 #include "storbase.hxx"
36 using namespace store
;
44 std::shared_ptr
<PageData
> m_xPage
;
49 static void * operator new (size_t, void * p
) { return p
; }
50 static void operator delete (void *, void *) {}
53 explicit Entry (std::shared_ptr
<PageData
> const & rxPage
, sal_uInt32 nOffset
)
54 : m_xPage(rxPage
), m_nOffset(nOffset
), m_pNext(nullptr)
59 // EntryCache interface
65 rtl_cache_type
* m_entry_cache
;
68 static EntryCache
& get();
70 Entry
* create (std::shared_ptr
<PageData
> const & rxPage
, sal_uInt32 nOffset
);
72 void destroy (Entry
* entry
);
81 // EntryCache implementation
82 EntryCache
& EntryCache::get()
84 static EntryCache g_entry_cache
;
88 EntryCache::EntryCache()
90 m_entry_cache
= rtl_cache_create (
91 "store_cache_entry_cache",
94 nullptr, // constructor
95 nullptr, // destructor
98 nullptr, // default source
103 EntryCache::~EntryCache()
105 rtl_cache_destroy (m_entry_cache
);
106 m_entry_cache
= nullptr;
109 Entry
* EntryCache::create (std::shared_ptr
<PageData
> const & rxPage
, sal_uInt32 nOffset
)
111 void * pAddr
= rtl_cache_alloc (m_entry_cache
);
112 if (pAddr
!= nullptr)
115 return new(pAddr
) Entry (rxPage
, nOffset
);
120 void EntryCache::destroy (Entry
* entry
)
122 if (entry
!= nullptr)
128 rtl_cache_free (m_entry_cache
, entry
);
132 // highbit():= log2() + 1 (complexity O(1))
133 static int highbit(std::size_t n
)
139 if constexpr (sizeof(n
) == 8)
141 if (n
& 0xffffffff00000000)
174 PageCache::PageCache (sal_uInt16 nPageSize
)
175 : m_hash_table (m_hash_table_0
),
176 m_hash_size (theTableSize
),
177 m_hash_shift (highbit(m_hash_size
) - 1),
178 m_page_shift (highbit(nPageSize
) - 1),
183 static size_t const theSize
= SAL_N_ELEMENTS(m_hash_table_0
);
184 static_assert(theSize
== theTableSize
, "must be equal");
187 PageCache::~PageCache()
190 std::size_t i
, n
= m_hash_size
;
191 for (i
= 0; i
< n
; i
++)
194 Entry
* entry
= m_hash_table
[i
];
195 while (entry
!= nullptr)
197 m_hash_table
[i
] = entry
->m_pNext
;
198 entry
->m_pNext
= nullptr;
199 EntryCache::get().destroy (entry
);
200 entry
= m_hash_table
[i
];
205 double ave
= s_x
/ double(n
);
206 SAL_INFO("store", "avg hash chain length: " << ave
);
208 if (m_hash_table
!= m_hash_table_0
)
210 std::free (m_hash_table
);
211 m_hash_table
= m_hash_table_0
;
212 m_hash_size
= theTableSize
;
213 m_hash_shift
= highbit(m_hash_size
) - 1;
215 SAL_INFO("store", "Hits: " << m_nHit
<< ", Misses: " << m_nMissed
);
218 void PageCache::rescale_Impl (std::size_t new_size
)
220 std::size_t new_bytes
= new_size
* sizeof(Entry
*);
221 Entry
** new_table
= static_cast<Entry
**>(std::malloc(new_bytes
));
223 if (new_table
== nullptr)
226 Entry
** old_table
= m_hash_table
;
227 std::size_t old_size
= m_hash_size
;
231 "ave chain length: " << (m_hash_entries
>> m_hash_shift
)
232 << ", total entries: " << m_hash_entries
<< " [old_size: "
233 << old_size
<< " new_size: " << new_size
<< "]");
235 memset (new_table
, 0, new_bytes
);
237 m_hash_table
= new_table
;
238 m_hash_size
= new_size
;
239 m_hash_shift
= highbit(m_hash_size
) - 1;
242 for (i
= 0; i
< old_size
; i
++)
244 Entry
* curr
= old_table
[i
];
245 while (curr
!= nullptr)
247 Entry
* next
= curr
->m_pNext
;
248 int index
= hash_index_Impl(curr
->m_nOffset
);
249 curr
->m_pNext
= m_hash_table
[index
];
250 m_hash_table
[index
] = curr
;
253 old_table
[i
] = nullptr;
255 if (old_table
!= m_hash_table_0
)
258 std::free (old_table
);
262 Entry
* PageCache::lookup_Impl (Entry
* entry
, sal_uInt32 nOffset
)
265 while (entry
!= nullptr)
267 if (entry
->m_nOffset
== nOffset
)
271 entry
= entry
->m_pNext
;
275 std::size_t new_size
= m_hash_size
, ave
= m_hash_entries
>> m_hash_shift
;
276 for (; ave
> 4; new_size
*= 2, ave
/= 2)
278 if (new_size
!= m_hash_size
)
279 rescale_Impl (new_size
);
284 storeError
PageCache::lookupPageAt (std::shared_ptr
<PageData
> & rxPage
, sal_uInt32 nOffset
)
286 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::lookupPageAt(): invalid Offset");
287 if (nOffset
== STORE_PAGE_NULL
)
288 return store_E_CantSeek
;
290 int index
= hash_index_Impl(nOffset
);
291 Entry
const * entry
= lookup_Impl (m_hash_table
[index
], nOffset
);
292 if (entry
!= nullptr)
295 rxPage
= entry
->m_xPage
;
297 // Update stats and leave.
302 // Cache miss. Update stats and leave.
304 return store_E_NotExists
;
307 storeError
PageCache::insertPageAt (std::shared_ptr
<PageData
> const & rxPage
, sal_uInt32 nOffset
)
309 // [SECURITY:ValInput]
310 PageData
const * pagedata
= rxPage
.get();
311 OSL_PRECOND(!(pagedata
== nullptr), "store::PageCache::insertPageAt(): invalid Page");
312 if (pagedata
== nullptr)
313 return store_E_InvalidParameter
;
315 sal_uInt32
const offset
= pagedata
->location();
316 OSL_PRECOND(!(nOffset
!= offset
), "store::PageCache::insertPageAt(): inconsistent Offset");
317 if (nOffset
!= offset
)
318 return store_E_InvalidParameter
;
320 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::insertPageAt(): invalid Offset");
321 if (nOffset
== STORE_PAGE_NULL
)
322 return store_E_CantSeek
;
324 Entry
* entry
= EntryCache::get().create (rxPage
, nOffset
);
325 if (entry
!= nullptr)
328 int index
= hash_index_Impl(nOffset
);
329 entry
->m_pNext
= m_hash_table
[index
];
330 m_hash_table
[index
] = entry
;
332 // Update stats and leave.
336 return store_E_OutOfMemory
;
339 storeError
PageCache::updatePageAt (std::shared_ptr
<PageData
> const & rxPage
, sal_uInt32 nOffset
)
341 // [SECURITY:ValInput]
342 PageData
const * pagedata
= rxPage
.get();
343 OSL_PRECOND(!(pagedata
== nullptr), "store::PageCache::updatePageAt(): invalid Page");
344 if (pagedata
== nullptr)
345 return store_E_InvalidParameter
;
347 sal_uInt32
const offset
= pagedata
->location();
348 OSL_PRECOND(!(nOffset
!= offset
), "store::PageCache::updatePageAt(): inconsistent Offset");
349 if (nOffset
!= offset
)
350 return store_E_InvalidParameter
;
352 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::updatePageAt(): invalid Offset");
353 if (nOffset
== STORE_PAGE_NULL
)
354 return store_E_CantSeek
;
356 int index
= hash_index_Impl(nOffset
);
357 Entry
* entry
= lookup_Impl (m_hash_table
[index
], nOffset
);
358 if (entry
!= nullptr)
360 // Update existing entry.
361 entry
->m_xPage
= rxPage
;
363 // Update stats and leave. // m_nUpdHit += 1;
366 return insertPageAt (rxPage
, nOffset
);
369 storeError
PageCache::removePageAt (sal_uInt32 nOffset
)
371 OSL_PRECOND(!(nOffset
== STORE_PAGE_NULL
), "store::PageCache::removePageAt(): invalid Offset");
372 if (nOffset
== STORE_PAGE_NULL
)
373 return store_E_CantSeek
;
375 Entry
** ppEntry
= &(m_hash_table
[hash_index_Impl(nOffset
)]);
376 while (*ppEntry
!= nullptr)
378 if ((*ppEntry
)->m_nOffset
== nOffset
)
381 Entry
* entry
= *ppEntry
;
383 // Dequeue and destroy entry.
384 (*ppEntry
) = entry
->m_pNext
;
385 entry
->m_pNext
= nullptr;
386 EntryCache::get().destroy (entry
);
388 // Update stats and leave.
392 ppEntry
= &((*ppEntry
)->m_pNext
);
394 return store_E_NotExists
;
399 * Old OStorePageCache implementation.
401 * (two-way association (sorted address array, LRU chain)).
402 * (external PageData representation).
408 * PageCache factory implementation.
414 PageCache_createInstance (
415 rtl::Reference
< store::PageCache
> & rxCache
,
416 sal_uInt16 nPageSize
)
418 rxCache
= new PageCache (nPageSize
);
420 return store_E_OutOfMemory
;
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */