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
15
16namespace bb::avm2::tracegen {
17
18// A key that uniquely identifies a destination table index.
19// An index can be shared if both the outer destination selector and the destination columns match.
20struct IndexKey {
22 std::vector<ColumnAndShifts> dst_columns;
23
24 bool operator==(const IndexKey&) const = default;
26};
27
28// The index type: maps a hash of field element tuples to a row number.
29// The actual tuple values are verified during lookup using the TraceContainer.
31
32// A thread-safe cache for destination table indices.
33// Multiple lookup builders targeting the same destination table can share an index,
34// avoiding redundant computation and memory usage.
36 public:
37 SharedIndexCache() = default;
38
39 // Non-copyable and non-movable (due to std::mutex).
44
45 // Clear all cached indices. This should be called when the underlying trace changes.
46 void clear()
47 {
48 std::unique_lock lock(mutex_);
49 cache_.clear();
50 }
51
52 // Get or build an index for the given destination table.
53 // If the index already exists or is being built, this will wait for it and return a reference.
54 // If the index doesn't exist, the calling thread will build it using the provided build function.
55 const DstIndex& get_or_build(Column outer_dst_selector,
57 const TraceContainer& trace,
58 std::function<DstIndex(const TraceContainer&)> build_fn)
59 {
60 IndexKey key{ outer_dst_selector, { dst_columns.begin(), dst_columns.end() } };
61
62 std::unique_lock lock(mutex_);
63
64 auto it = cache_.find(key);
65 if (it != cache_.end()) {
66 // Index exists or is being built. Release lock before waiting.
67 auto future = it->second;
68 lock.unlock();
69 return *future.get();
70 }
71
72 // We are the first to request this index. Create a promise and store the future.
74 cache_[key] = promise->get_future().share();
75 lock.unlock();
76
77 // Build the index outside the lock.
78 try {
79 auto index = std::make_shared<DstIndex>(build_fn(trace));
80 promise->set_value(index);
81 return *index;
82 } catch (...) {
83 promise->set_exception(std::current_exception());
84 throw;
85 }
86 }
87
88 private:
89 std::mutex mutex_;
90 // The cache stores shared futures that resolve to shared pointers to the indices.
91 // Using shared_ptr ensures the index outlives all references to it.
93};
94
95} // namespace bb::avm2::tracegen
unordered_flat_map< IndexKey, std::shared_future< std::shared_ptr< DstIndex > > > cache_
const DstIndex & get_or_build(Column outer_dst_selector, std::span< const ColumnAndShifts > dst_columns, const TraceContainer &trace, std::function< DstIndex(const TraceContainer &)> build_fn)
SharedIndexCache & operator=(SharedIndexCache &&)=delete
SharedIndexCache & operator=(const SharedIndexCache &)=delete
SharedIndexCache(SharedIndexCache &&)=delete
SharedIndexCache(const SharedIndexCache &)=delete
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