Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
shared_index_cache.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstddef>
4#include <cstdint>
5#include <future>
6#include <mutex>
7#include <vector>
8
16
17namespace bb::avm2::tracegen {
18
19// A key that uniquely identifies a destination table index.
20// An index can be shared if both the outer destination selector and the destination columns match.
21struct IndexKey {
23 std::vector<ColumnAndShifts> dst_columns;
24
25 bool operator==(const IndexKey&) const = default;
27};
28
29// The index type: maps a hash of field element tuples to a row number.
30// The actual tuple values are verified during lookup using the TraceContainer.
32
33// A thread-safe cache for destination table indices.
34// Multiple lookup builders targeting the same destination table can share an index,
35// avoiding redundant computation and memory usage.
37 public:
38 SharedIndexCache() = default;
39
40 // Non-copyable and non-movable (due to std::mutex).
45
46 // Clear all cached indices. This should be called when the underlying trace changes.
47 void clear()
48 {
49 std::unique_lock lock(mutex_);
50 cache_.clear();
51 }
52
53 // Get or build an index for the given destination table.
54 // If the index already exists or is being built, this will wait for it and return a reference.
55 // If the index doesn't exist, the calling thread will build it using the provided build function.
56 const DstIndex& get_or_build(Column outer_dst_selector,
58 const TraceContainer& trace,
59 const std::function<DstIndex(const TraceContainer&)>& build_fn)
60 {
61 IndexKey key{ outer_dst_selector, { dst_columns.begin(), dst_columns.end() } };
62
63 std::unique_lock lock(mutex_);
64
65 auto it = cache_.find(key);
66 if (it != cache_.end()) {
67 // Index exists or is being built. Release lock before waiting.
68 auto future = it->second;
69 lock.unlock();
70 return *future.get();
71 }
72
73 // We are the first to request this index. Create a promise and store the future.
75 cache_[key] = promise->get_future().share();
76 lock.unlock();
77
78 // Build the index outside the lock.
79 try {
80 auto index = std::make_shared<DstIndex>(build_fn(trace));
81 promise->set_value(index);
82 return *index;
83 } catch (...) {
84 // Evict the failed entry so a subsequent get_or_build can retry rather than
85 // re-throwing the cached exception forever (and broadcasting it to all jobs
86 // that share this destination).
87 {
88 std::unique_lock lock(mutex_);
89 cache_.erase(key);
90 }
91 // Wake any threads already waiting on this future with the build error.
92 // Swallow any secondary failure here (e.g. promise_already_satisfied if
93 // set_value partially completed) so the original exception always
94 // propagates and we never leave waiters blocked.
95 try {
96 promise->set_exception(std::current_exception());
97 } catch (const std::exception& secondary) {
98 // NOLINTNEXTLINE(cppcoreguidelines-avoid-do-while): vinfo macro expands to do-while.
99 vinfo("SharedIndexCache: ignoring secondary failure in set_exception: ", secondary.what());
100 }
101 throw;
102 }
103 }
104
105 private:
106 std::mutex mutex_;
107 // The cache stores shared futures that resolve to shared pointers to the indices.
108 // Using shared_ptr ensures the index outlives all references to it.
110};
111
112} // namespace bb::avm2::tracegen
unordered_flat_map< IndexKey, std::shared_future< std::shared_ptr< DstIndex > > > cache_
SharedIndexCache & operator=(SharedIndexCache &&)=delete
SharedIndexCache & operator=(const SharedIndexCache &)=delete
SharedIndexCache(SharedIndexCache &&)=delete
const DstIndex & get_or_build(Column outer_dst_selector, std::span< const ColumnAndShifts > dst_columns, const TraceContainer &trace, const std::function< DstIndex(const TraceContainer &)> &build_fn)
SharedIndexCache(const SharedIndexCache &)=delete
#define vinfo(...)
Definition log.hpp:94
TestTraceContainer trace
unordered_flat_map< size_t, std::vector< uint32_t > > DstIndex
::ankerl::unordered_dense::map< Key, T > unordered_flat_map
Definition map.hpp:15
size_t hash_as_tuple(const Ts &... ts)
Definition utils.hpp:22
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
bool operator==(const IndexKey &) const =default
std::vector< ColumnAndShifts > dst_columns