| 351 | |
| 352 | template <typename KeyT, typename IndexLookupT> |
| 353 | BlockCache::LookupData BlockCache::lookupInternal(const KeyT& key, |
| 354 | IndexLookupT&& indexLookup) { |
| 355 | constexpr bool kIsHashedKey = std::is_same_v<KeyT, HashedKey>; |
| 356 | auto start = getSteadyClock(); |
| 357 | SCOPE_EXIT { |
| 358 | lookupLatency_.trackValue(toMicros(getSteadyClock() - start).count()); |
| 359 | }; |
| 360 | |
| 361 | auto retryIndex = (regionManager_.readAllowedDuringReclaim() ? 1 : 0); |
| 362 | Index::LookupResult lr; |
| 363 | RelAddress addrEnd; |
| 364 | LookupData ld; |
| 365 | RegionDescriptor desc{OpenStatus::Retry}; |
| 366 | |
| 367 | do { |
| 368 | auto seqNumber = regionManager_.getSeqNumber(); |
| 369 | lr = indexLookup(key); |
| 370 | if (!lr.found()) { |
| 371 | lookupCount_.inc(); |
| 372 | ld.status_ = Status::NotFound; |
| 373 | return ld; |
| 374 | } |
| 375 | // If relative address has offset 0, the entry actually belongs to the |
| 376 | // previous region (this is address of its end). To compensate for this, we |
| 377 | // subtract 1 before conversion and add after to relative address. |
| 378 | addrEnd = decodeRelAddress(lr.address()); |
| 379 | // Between acquiring @seqNumber and @openForRead, reclaim may start. There |
| 380 | // are two options what can happen in @openForRead: |
| 381 | // - Reclaim in progress and open will fail because access mask |
| 382 | // disables both read and write (Only when read is not allowed during |
| 383 | // reclaim) |
| 384 | // - Reclaim finished and reclaimed victim was released/reset. Sequence |
| 385 | // number increased with that and open will fail because of sequence number |
| 386 | // check. (This means sequence number will be increased when we finish |
| 387 | // reclaim.) |
| 388 | desc = regionManager_.openForRead(addrEnd.rid(), seqNumber); |
| 389 | // If we get OpenStatus::Retry when read is allowed during reclaim, it means |
| 390 | // reclaim has finished and reclaimed victim was reset/released (checked by |
| 391 | // SeqNumber). Index should had been updated in this case (to the new |
| 392 | // location or as removed). So we need to lookup index again. |
| 393 | // |
| 394 | // In case read is NOT allowed during reclaim, there's no chance that this |
| 395 | // situation is resolved by looking up the index again. So we'll follow the |
| 396 | // old logic (just returning retry below) |
| 397 | } while (desc.status() == OpenStatus::Retry && retryIndex-- > 0); |
| 398 | |
| 399 | std::optional<HashedKey> expected; |
| 400 | if constexpr (kIsHashedKey) { |
| 401 | expected = key; |
| 402 | } |
| 403 | |
| 404 | switch (desc.status()) { |
| 405 | case OpenStatus::Ready: { |
| 406 | SCOPE_EXIT { regionManager_.close(std::move(desc)); }; |
| 407 | readEntry(desc, ld, addrEnd, decodeSizeHint(lr.sizeHint()), expected); |
| 408 | if (FOLLY_UNLIKELY(ld.status_ == Status::DeviceError)) { |
| 409 | // Remove this item from index so no future lookup will ever attempt to |
| 410 | // read it. If the address still matches and the item is removed, reclaim |
nothing calls this directly
no test coverage detected