nss: upgrade to release 3.73
[LibreOffice.git] / store / source / storcach.cxx
blobcefd963813a6e15edcf8bc30ce719729918ad655
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
33 #include <memory>
34 #include <string.h>
36 using namespace store;
38 // Entry
40 namespace store {
41 struct Entry
43 // Representation
44 std::shared_ptr<PageData> m_xPage;
45 sal_uInt32 m_nOffset;
46 Entry * m_pNext;
48 // Allocation
49 static void * operator new (size_t, void * p) { return p; }
50 static void operator delete (void *, void *) {}
52 // Construction
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
60 namespace
63 class EntryCache
65 rtl_cache_type * m_entry_cache;
67 public:
68 static EntryCache & get();
70 Entry * create (std::shared_ptr<PageData> const & rxPage, sal_uInt32 nOffset);
72 void destroy (Entry * entry);
74 protected:
75 EntryCache();
76 ~EntryCache();
79 } // namespace
81 // EntryCache implementation
82 EntryCache & EntryCache::get()
84 static EntryCache g_entry_cache;
85 return g_entry_cache;
88 EntryCache::EntryCache()
90 m_entry_cache = rtl_cache_create (
91 "store_cache_entry_cache",
92 sizeof(Entry),
93 0, // objalign
94 nullptr, // constructor
95 nullptr, // destructor
96 nullptr, // reclaim
97 nullptr, // userarg
98 nullptr, // default source
99 0 // flags
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)
114 // construct
115 return new(pAddr) Entry (rxPage, nOffset);
117 return nullptr;
120 void EntryCache::destroy (Entry * entry)
122 if (entry != nullptr)
124 // destruct
125 entry->~Entry();
127 // return to cache
128 rtl_cache_free (m_entry_cache, entry);
132 // highbit():= log2() + 1 (complexity O(1))
133 static int highbit(std::size_t n)
135 int k = 1;
137 if (n == 0)
138 return 0;
139 if constexpr (sizeof(n) == 8)
141 if (n & 0xffffffff00000000)
143 k |= 32;
144 n >>= 32;
147 if (n & 0xffff0000)
149 k |= 16;
150 n >>= 16;
152 if (n & 0xff00)
154 k |= 8;
155 n >>= 8;
157 if (n & 0xf0)
159 k |= 4;
160 n >>= 4;
162 if (n & 0x0c)
164 k |= 2;
165 n >>= 2;
167 if (n & 0x02)
168 k++;
170 return k;
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),
179 m_hash_entries (0),
180 m_nHit (0),
181 m_nMissed (0)
183 static size_t const theSize = SAL_N_ELEMENTS(m_hash_table_0);
184 static_assert(theSize == theTableSize, "must be equal");
187 PageCache::~PageCache()
189 double s_x = 0.0;
190 std::size_t i, n = m_hash_size;
191 for (i = 0; i < n; i++)
193 int x = 0;
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];
201 x += 1;
203 s_x += double(x);
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)
224 return;
226 Entry ** old_table = m_hash_table;
227 std::size_t old_size = m_hash_size;
229 SAL_INFO(
230 "store",
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;
241 std::size_t i;
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;
251 curr = next;
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)
264 int lookups = 0;
265 while (entry != nullptr)
267 if (entry->m_nOffset == nOffset)
268 break;
270 lookups += 1;
271 entry = entry->m_pNext;
273 if (lookups > 2)
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)
277 continue;
278 if (new_size != m_hash_size)
279 rescale_Impl (new_size);
281 return entry;
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)
294 // Existing entry.
295 rxPage = entry->m_xPage;
297 // Update stats and leave.
298 m_nHit += 1;
299 return store_E_None;
302 // Cache miss. Update stats and leave.
303 m_nMissed += 1;
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)
327 // Insert new entry.
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.
333 m_hash_entries += 1;
334 return store_E_None;
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;
364 return store_E_None;
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)
380 // Existing entry.
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.
389 m_hash_entries -= 1;
390 return store_E_None;
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.
411 namespace store {
413 storeError
414 PageCache_createInstance (
415 rtl::Reference< store::PageCache > & rxCache,
416 sal_uInt16 nPageSize)
418 rxCache = new PageCache (nPageSize);
419 if (!rxCache.is())
420 return store_E_OutOfMemory;
422 return store_E_None;
425 } // namespace store
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */