|
25 | 25 | #include <bit> |
26 | 26 |
|
27 | 27 | #include "cost.hpp" |
28 | | -#include "score.hpp" |
29 | 28 | #include "utils/bitset.hpp" |
30 | 29 |
|
| 30 | +#include <absl/synchronization/mutex.h> |
| 31 | + |
31 | 32 | namespace irs { |
32 | 33 |
|
33 | 34 | // Bitset expecting doc iterator to be able only to move forward. |
@@ -178,65 +179,73 @@ class lazy_filter_bitset_iterator : public doc_iterator, |
178 | 179 |
|
179 | 180 | struct proxy_query_cache { |
180 | 181 | proxy_query_cache(IResourceManager& memory, filter::ptr&& ptr) noexcept |
181 | | - : readers_{Alloc{memory}}, real_filter_(std::move(ptr)) {} |
| 182 | + : real_filter_{std::move(ptr)}, readers_{Alloc{memory}} {} |
182 | 183 |
|
183 | 184 | using Alloc = ManagedTypedAllocator< |
184 | 185 | std::pair<const SubReader* const, std::unique_ptr<lazy_filter_bitset>>>; |
185 | 186 |
|
| 187 | + filter::ptr real_filter_; |
| 188 | + filter::prepared::ptr real_filter_prepared_; |
| 189 | + absl::Mutex readers_lock_; |
186 | 190 | absl::flat_hash_map< |
187 | 191 | const SubReader*, std::unique_ptr<lazy_filter_bitset>, |
188 | 192 | absl::container_internal::hash_default_hash<const SubReader*>, |
189 | 193 | absl::container_internal::hash_default_eq<const SubReader*>, Alloc> |
190 | 194 | readers_; |
191 | | - filter::prepared::ptr prepared_real_filter_; |
192 | | - filter::ptr real_filter_; |
193 | 195 | }; |
194 | 196 |
|
195 | 197 | class proxy_query : public filter::prepared { |
196 | 198 | public: |
197 | | - explicit proxy_query(proxy_filter::cache_ptr cache) : cache_(cache) { |
198 | | - IRS_ASSERT(cache_->prepared_real_filter_); |
| 199 | + explicit proxy_query(proxy_filter::cache_ptr cache) : cache_{cache} { |
| 200 | + IRS_ASSERT(cache_->real_filter_prepared_); |
199 | 201 | } |
200 | 202 |
|
201 | 203 | doc_iterator::ptr execute(const ExecutionContext& ctx) const final { |
202 | | - // first try to find segment in cache. |
203 | | - [[maybe_unused]] auto& [_, cached] = |
204 | | - *cache_->readers_.emplace(&ctx.segment, nullptr).first; |
205 | | - |
206 | | - if (!cached) { |
207 | | - cached = std::make_unique<lazy_filter_bitset>( |
208 | | - ctx, *cache_->prepared_real_filter_); |
| 204 | + auto* cache_bitset = [&]() -> lazy_filter_bitset* { |
| 205 | + absl::ReaderMutexLock lock{&cache_->readers_lock_}; |
| 206 | + auto it = cache_->readers_.find(&ctx.segment); |
| 207 | + if (it != cache_->readers_.end()) { |
| 208 | + return it->second.get(); |
| 209 | + } |
| 210 | + return nullptr; |
| 211 | + }(); |
| 212 | + if (!cache_bitset) { |
| 213 | + auto bitset = std::make_unique<lazy_filter_bitset>( |
| 214 | + ctx, *cache_->real_filter_prepared_); |
| 215 | + cache_bitset = bitset.get(); |
| 216 | + absl::WriterMutexLock lock{&cache_->readers_lock_}; |
| 217 | + IRS_ASSERT(!cache_->readers_.contains(&ctx.segment)); |
| 218 | + cache_->readers_.emplace(&ctx.segment, std::move(bitset)); |
209 | 219 | } |
210 | | - |
211 | | - IRS_ASSERT(cached); |
212 | 220 | return memory::make_tracked<lazy_filter_bitset_iterator>(ctx.memory, |
213 | | - *cached); |
| 221 | + *cache_bitset); |
214 | 222 | } |
215 | 223 |
|
216 | 224 | void visit(const SubReader&, PreparedStateVisitor&, score_t) const final { |
217 | 225 | // No terms to visit |
218 | 226 | } |
219 | 227 |
|
220 | 228 | private: |
221 | | - mutable proxy_filter::cache_ptr cache_; |
| 229 | + proxy_filter::cache_ptr cache_; |
222 | 230 | }; |
223 | 231 |
|
224 | 232 | filter::prepared::ptr proxy_filter::prepare(const PrepareContext& ctx) const { |
225 | | - if (!cache_ || !cache_->real_filter_ || !ctx.scorers.empty()) { |
226 | | - // Currently we do not support caching scores. |
227 | | - // Proxy filter should not be used with scorers! |
228 | | - IRS_ASSERT(false); |
| 233 | + // Currently we do not support caching scores. |
| 234 | + // Proxy filter should not be used with scorers! |
| 235 | + IRS_ASSERT(ctx.scorers.empty()); |
| 236 | + if (!cache_ || !ctx.scorers.empty()) { |
229 | 237 | return filter::prepared::empty(); |
230 | 238 | } |
231 | | - if (!cache_->prepared_real_filter_) { |
232 | | - cache_->prepared_real_filter_ = cache_->real_filter_->prepare(ctx); |
| 239 | + if (!cache_->real_filter_prepared_) { |
| 240 | + cache_->real_filter_prepared_ = cache_->real_filter_->prepare(ctx); |
| 241 | + cache_->real_filter_.reset(); |
233 | 242 | } |
234 | 243 | return memory::make_tracked<proxy_query>(ctx.memory, cache_); |
235 | 244 | } |
236 | 245 |
|
237 | 246 | filter& proxy_filter::cache_filter(IResourceManager& memory, |
238 | | - filter::ptr&& ptr) { |
239 | | - cache_ = std::make_shared<proxy_query_cache>(memory, std::move(ptr)); |
| 247 | + filter::ptr&& real) { |
| 248 | + cache_ = std::make_shared<proxy_query_cache>(memory, std::move(real)); |
240 | 249 | IRS_ASSERT(cache_->real_filter_); |
241 | 250 | return *cache_->real_filter_; |
242 | 251 | } |
|
0 commit comments