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#include <array>
24#include <shared_mutex>
25#include <unordered_map>
26
27#include <thread_pool.h>
28
39template <typename KEY, typename VALUE, std::size_t SHARDS = 256>
41{
42public:
44 bool Get( const KEY& aKey, VALUE& aValue ) const
45 {
46 const SHARD& shard = shardFor( aKey );
47 std::shared_lock<std::shared_mutex> lock( shard.mutex );
48
49 auto it = shard.map.find( aKey );
50
51 if( it == shard.map.end() )
52 return false;
53
54 aValue = it->second;
55 return true;
56 }
57
58 void Set( const KEY& aKey, const VALUE& aValue )
59 {
60 SHARD& shard = shardFor( aKey );
61 std::unique_lock<std::shared_mutex> lock( shard.mutex );
62
63 shard.map[aKey] = aValue;
64 }
65
66 void Clear()
67 {
68 // Clearing a node-based map frees every entry individually. A dense board with
69 // heavy custom rules can accumulate hundreds of millions of predicate-cache entries,
70 // and that serial deallocation otherwise stalls DRC re-initialization for tens of
71 // seconds. The shards are independent, so fan their clears across the worker pool
72 // once the cache is large enough to outweigh the scheduling overhead.
74 {
75 for( SHARD& shard : m_shards )
76 {
77 std::unique_lock<std::shared_mutex> lock( shard.mutex );
78 shard.map.clear();
79 }
80
81 return;
82 }
83
85
86 tp.submit_loop( std::size_t( 0 ), SHARDS,
87 [this]( std::size_t aShard )
88 {
89 std::unique_lock<std::shared_mutex> lock( m_shards[aShard].mutex );
90 m_shards[aShard].map.clear();
91 },
92 SHARDS ).wait();
93 }
94
95 bool Empty() const
96 {
97 for( const SHARD& shard : m_shards )
98 {
99 std::shared_lock<std::shared_mutex> lock( shard.mutex );
100
101 if( !shard.map.empty() )
102 return false;
103 }
104
105 return true;
106 }
107
108private:
110 static constexpr std::size_t PARALLEL_CLEAR_THRESHOLD = 100000;
111
113 std::size_t Size() const
114 {
115 std::size_t total = 0;
116
117 for( const SHARD& shard : m_shards )
118 {
119 std::shared_lock<std::shared_mutex> lock( shard.mutex );
120 total += shard.map.size();
121 }
122
123 return total;
124 }
125
126 struct SHARD
127 {
128 mutable std::shared_mutex mutex;
129 std::unordered_map<KEY, VALUE> map;
130 };
131
132 SHARD& shardFor( const KEY& aKey )
133 {
134 return m_shards[std::hash<KEY>{}( aKey ) % SHARDS];
135 }
136
137 const SHARD& shardFor( const KEY& aKey ) const
138 {
139 return m_shards[std::hash<KEY>{}( aKey ) % SHARDS];
140 }
141
142 std::array<SHARD, SHARDS> m_shards;
143};
144
145#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