KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sharded_cache.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef SHARDED_CACHE_H
21#define SHARDED_CACHE_H
22
23#if defined (__MINGW32__)
24#ifdef BS_THREAD_POOL_NATIVE_EXTENSIONS
25 // needed to avoid some undefined in wx in a few dialogs on MINGW
26 // due to some includes in thread_pool.h (especially windows.h)
27 // this is mainly due to vars/functions name colliding with some defines in windows.h
28 #if 1
29 // Works fine but include a lot of not needed files
30 #include <wx/wx.h>
31 #endif
32#endif
33#endif
34
35#include <array>
36#include <shared_mutex>
37#include <unordered_map>
38
39#include <thread_pool.h>
40
51template <typename KEY, typename VALUE, std::size_t SHARDS = 256>
53{
54public:
56 bool Get( const KEY& aKey, VALUE& aValue ) const
57 {
58 const SHARD& shard = shardFor( aKey );
59 std::shared_lock<std::shared_mutex> lock( shard.mutex );
60
61 auto it = shard.map.find( aKey );
62
63 if( it == shard.map.end() )
64 return false;
65
66 aValue = it->second;
67 return true;
68 }
69
70 void Set( const KEY& aKey, const VALUE& aValue )
71 {
72 SHARD& shard = shardFor( aKey );
73 std::unique_lock<std::shared_mutex> lock( shard.mutex );
74
75 shard.map[aKey] = aValue;
76 }
77
78 void Clear()
79 {
80 // Clearing a node-based map frees every entry individually. A dense board with
81 // heavy custom rules can accumulate hundreds of millions of predicate-cache entries,
82 // and that serial deallocation otherwise stalls DRC re-initialization for tens of
83 // seconds. The shards are independent, so fan their clears across the worker pool
84 // once the cache is large enough to outweigh the scheduling overhead.
86 {
87 for( SHARD& shard : m_shards )
88 {
89 std::unique_lock<std::shared_mutex> lock( shard.mutex );
90 shard.map.clear();
91 }
92
93 return;
94 }
95
97
98 tp.submit_loop( std::size_t( 0 ), SHARDS,
99 [this]( std::size_t aShard )
100 {
101 std::unique_lock<std::shared_mutex> lock( m_shards[aShard].mutex );
102 m_shards[aShard].map.clear();
103 },
104 SHARDS ).wait();
105 }
106
107 bool Empty() const
108 {
109 for( const SHARD& shard : m_shards )
110 {
111 std::shared_lock<std::shared_mutex> lock( shard.mutex );
112
113 if( !shard.map.empty() )
114 return false;
115 }
116
117 return true;
118 }
119
120private:
122 static constexpr std::size_t PARALLEL_CLEAR_THRESHOLD = 100000;
123
125 std::size_t Size() const
126 {
127 std::size_t total = 0;
128
129 for( const SHARD& shard : m_shards )
130 {
131 std::shared_lock<std::shared_mutex> lock( shard.mutex );
132 total += shard.map.size();
133 }
134
135 return total;
136 }
137
138 struct SHARD
139 {
140 mutable std::shared_mutex mutex;
141 std::unordered_map<KEY, VALUE> map;
142 };
143
144 SHARD& shardFor( const KEY& aKey )
145 {
146 return m_shards[std::hash<KEY>{}( aKey ) % SHARDS];
147 }
148
149 const SHARD& shardFor( const KEY& aKey ) const
150 {
151 return m_shards[std::hash<KEY>{}( aKey ) % SHARDS];
152 }
153
154 std::array<SHARD, SHARDS> m_shards;
155};
156
157#endif // SHARDED_CACHE_H
A concurrent key/value cache split into independently locked shards.
bool Empty() const
const SHARD & shardFor(const KEY &aKey) const
std::array< SHARD, SHARDS > m_shards
bool Get(const KEY &aKey, VALUE &aValue) const
Look up a key. Returns false on a miss and leaves aValue untouched.
std::size_t Size() const
Only Clear() needs this; an exact concurrent size has no sound external use, so private.
void Set(const KEY &aKey, const VALUE &aValue)
SHARD & shardFor(const KEY &aKey)
static constexpr std::size_t PARALLEL_CLEAR_THRESHOLD
Entry count above which Clear() fans its per-shard deallocation across the worker pool.
std::unordered_map< KEY, VALUE > map
std::shared_mutex mutex
@ VALUE
Field Value of part, i.e. "3.3K".
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
static thread_pool * tp
BS::priority_thread_pool thread_pool
Definition thread_pool.h:27