LCOV - code coverage report
Current view: top level - source/extensions/http/cache/file_system_http_cache - lookup_context.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 165 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 17 0.0 %

          Line data    Source code
       1             : #include "source/extensions/http/cache/file_system_http_cache/lookup_context.h"
       2             : 
       3             : #include "source/extensions/http/cache/file_system_http_cache/cache_file_header.pb.h"
       4             : #include "source/extensions/http/cache/file_system_http_cache/cache_file_header_proto_util.h"
       5             : #include "source/extensions/http/cache/file_system_http_cache/file_system_http_cache.h"
       6             : 
       7             : #include "cache_file_fixed_block.h"
       8             : 
       9             : namespace Envoy {
      10             : namespace Extensions {
      11             : namespace HttpFilters {
      12             : namespace Cache {
      13             : namespace FileSystemHttpCache {
      14             : 
      15           0 : std::string FileLookupContext::filepath() {
      16           0 :   return absl::StrCat(cache_.cachePath(), cache_.generateFilename(key_));
      17           0 : }
      18             : 
      19           0 : bool FileLookupContext::workInProgress() const { return cache_.workInProgress(key()); }
      20             : 
      21           0 : void FileLookupContext::getHeaders(LookupHeadersCallback&& cb) {
      22             :   // TODO(ravenblack): Consider adding a memory cache check here for uncacheable keys, to save
      23             :   // on the repeated filesystem hit. Capture some performance metrics to see if it's worth it.
      24             :   // If migrating to "shared stream" implementation, this question answers itself.
      25           0 :   absl::MutexLock lock(&mu_);
      26           0 :   getHeadersWithLock(std::move(cb));
      27           0 : }
      28             : 
      29           0 : void FileLookupContext::getHeadersWithLock(LookupHeadersCallback cb) {
      30           0 :   mu_.AssertHeld();
      31           0 :   cancel_action_in_flight_ = cache_.asyncFileManager()->openExistingFile(
      32           0 :       filepath(), Common::AsyncFiles::AsyncFileManager::Mode::ReadOnly,
      33           0 :       [this, cb](absl::StatusOr<AsyncFileHandle> open_result) {
      34           0 :         absl::MutexLock lock(&mu_);
      35           0 :         cancel_action_in_flight_ = nullptr;
      36           0 :         if (!open_result.ok()) {
      37           0 :           cache_.stats().cache_miss_.inc();
      38           0 :           cb(LookupResult{});
      39           0 :           return;
      40           0 :         }
      41           0 :         ASSERT(!file_handle_);
      42           0 :         file_handle_ = std::move(open_result.value());
      43           0 :         auto queued = file_handle_->read(
      44           0 :             0, CacheFileFixedBlock::size(),
      45           0 :             [this, cb](absl::StatusOr<Buffer::InstancePtr> read_result) {
      46           0 :               absl::MutexLock lock(&mu_);
      47           0 :               cancel_action_in_flight_ = nullptr;
      48           0 :               if (!read_result.ok() ||
      49           0 :                   read_result.value()->length() != CacheFileFixedBlock::size()) {
      50           0 :                 invalidateCacheEntry();
      51           0 :                 cache_.stats().cache_miss_.inc();
      52           0 :                 cb(LookupResult{});
      53           0 :                 return;
      54           0 :               }
      55           0 :               header_block_.populateFromStringView(read_result.value()->toString());
      56           0 :               if (!header_block_.isValid()) {
      57           0 :                 invalidateCacheEntry();
      58           0 :                 cache_.stats().cache_miss_.inc();
      59           0 :                 cb(LookupResult{});
      60           0 :                 return;
      61           0 :               }
      62           0 :               auto queued = file_handle_->read(
      63           0 :                   header_block_.offsetToHeaders(), header_block_.headerSize(),
      64           0 :                   [this, cb](absl::StatusOr<Buffer::InstancePtr> read_result) {
      65           0 :                     absl::MutexLock lock(&mu_);
      66           0 :                     cancel_action_in_flight_ = nullptr;
      67           0 :                     if (!read_result.ok() ||
      68           0 :                         read_result.value()->length() != header_block_.headerSize()) {
      69           0 :                       invalidateCacheEntry();
      70           0 :                       cache_.stats().cache_miss_.inc();
      71           0 :                       cb(LookupResult{});
      72           0 :                       return;
      73           0 :                     }
      74           0 :                     auto header_proto = makeCacheFileHeaderProto(*read_result.value());
      75           0 :                     if (header_proto.headers_size() == 1 &&
      76           0 :                         header_proto.headers().at(0).key() == "vary") {
      77           0 :                       auto maybe_vary_key = cache_.makeVaryKey(
      78           0 :                           key_, lookup().varyAllowList(),
      79           0 :                           absl::StrSplit(header_proto.headers().at(0).value(), ','),
      80           0 :                           lookup().requestHeaders());
      81           0 :                       if (!maybe_vary_key.has_value()) {
      82           0 :                         cache_.stats().cache_miss_.inc();
      83           0 :                         cb(LookupResult{});
      84           0 :                         return;
      85           0 :                       }
      86           0 :                       key_ = maybe_vary_key.value();
      87           0 :                       auto fh = std::move(file_handle_);
      88           0 :                       file_handle_ = nullptr;
      89             :                       // It should be possible to cancel close, to make this safe.
      90             :                       // (it should still close the file, but cancel the callback.)
      91           0 :                       auto queued = fh->close([this, cb](absl::Status) {
      92           0 :                         absl::MutexLock lock(&mu_);
      93             :                         // Restart getHeaders with the new key.
      94           0 :                         return getHeadersWithLock(cb);
      95           0 :                       });
      96           0 :                       ASSERT(queued.ok(), queued.ToString());
      97           0 :                       return;
      98           0 :                     }
      99           0 :                     cache_.stats().cache_hit_.inc();
     100           0 :                     cb(lookup().makeLookupResult(
     101           0 :                         headersFromHeaderProto(header_proto), metadataFromHeaderProto(header_proto),
     102           0 :                         header_block_.bodySize(), header_block_.trailerSize() > 0));
     103           0 :                   });
     104           0 :               ASSERT(queued.ok(), queued.status().ToString());
     105           0 :               cancel_action_in_flight_ = queued.value();
     106           0 :             });
     107           0 :         ASSERT(queued.ok(), queued.status().ToString());
     108           0 :         cancel_action_in_flight_ = queued.value();
     109           0 :       });
     110           0 : }
     111             : 
     112           0 : void FileLookupContext::invalidateCacheEntry() {
     113           0 :   cache_.asyncFileManager()->stat(
     114           0 :       filepath(), [file = filepath(),
     115           0 :                    cache = cache_.shared_from_this()](absl::StatusOr<struct stat> stat_result) {
     116           0 :         size_t file_size = 0;
     117           0 :         if (stat_result.ok()) {
     118           0 :           file_size = stat_result.value().st_size;
     119           0 :         }
     120           0 :         cache->asyncFileManager()->unlink(file, [cache, file_size](absl::Status unlink_result) {
     121           0 :           if (unlink_result.ok()) {
     122           0 :             cache->trackFileRemoved(file_size);
     123           0 :           }
     124           0 :         });
     125           0 :       });
     126           0 : }
     127             : 
     128           0 : void FileLookupContext::getBody(const AdjustedByteRange& range, LookupBodyCallback&& cb) {
     129           0 :   absl::MutexLock lock(&mu_);
     130           0 :   ASSERT(!cancel_action_in_flight_);
     131           0 :   auto queued = file_handle_->read(
     132           0 :       header_block_.offsetToBody() + range.begin(), range.length(),
     133           0 :       [this, cb, range](absl::StatusOr<Buffer::InstancePtr> read_result) {
     134           0 :         absl::MutexLock lock(&mu_);
     135           0 :         cancel_action_in_flight_ = nullptr;
     136           0 :         if (!read_result.ok() || read_result.value()->length() != range.length()) {
     137           0 :           invalidateCacheEntry();
     138             :           // Calling callback with nullptr fails the request.
     139           0 :           cb(nullptr);
     140           0 :           return;
     141           0 :         }
     142           0 :         cb(std::move(read_result.value()));
     143           0 :       });
     144           0 :   ASSERT(queued.ok(), queued.status().ToString());
     145           0 :   cancel_action_in_flight_ = queued.value();
     146           0 : }
     147             : 
     148           0 : void FileLookupContext::getTrailers(LookupTrailersCallback&& cb) {
     149           0 :   ASSERT(cb);
     150           0 :   absl::MutexLock lock(&mu_);
     151           0 :   ASSERT(!cancel_action_in_flight_);
     152           0 :   auto queued = file_handle_->read(header_block_.offsetToTrailers(), header_block_.trailerSize(),
     153           0 :                                    [this, cb](absl::StatusOr<Buffer::InstancePtr> read_result) {
     154           0 :                                      absl::MutexLock lock(&mu_);
     155           0 :                                      cancel_action_in_flight_ = nullptr;
     156           0 :                                      if (!read_result.ok() || read_result.value()->length() !=
     157           0 :                                                                   header_block_.trailerSize()) {
     158           0 :                                        invalidateCacheEntry();
     159             :                                        // There is no failure response for getTrailers, so we just
     160             :                                        // say there were no trailers in the event of this failure.
     161           0 :                                        cb(Http::ResponseTrailerMapImpl::create());
     162           0 :                                        return;
     163           0 :                                      }
     164           0 :                                      CacheFileTrailer trailer;
     165           0 :                                      trailer.ParseFromString(read_result.value()->toString());
     166           0 :                                      cb(trailersFromTrailerProto(trailer));
     167           0 :                                    });
     168           0 :   ASSERT(queued.ok(), queued.status().ToString());
     169           0 :   cancel_action_in_flight_ = queued.value();
     170           0 : }
     171             : 
     172           0 : void FileLookupContext::onDestroy() {
     173           0 :   CancelFunction cancel;
     174           0 :   {
     175           0 :     absl::MutexLock lock(&mu_);
     176           0 :     cancel = std::move(cancel_action_in_flight_);
     177           0 :     cancel_action_in_flight_ = nullptr;
     178           0 :   }
     179           0 :   while (cancel) {
     180             :     // We mustn't hold the lock while calling cancel, as it can potentially wait for
     181             :     // a callback to complete, and the callback might take the lock.
     182           0 :     cancel();
     183           0 :     {
     184             :       // It's possible that while calling cancel, another action was started - if
     185             :       // that happened, we must cancel that one too!
     186           0 :       absl::MutexLock lock(&mu_);
     187           0 :       cancel = std::move(cancel_action_in_flight_);
     188           0 :       cancel_action_in_flight_ = nullptr;
     189           0 :     }
     190           0 :   }
     191           0 :   {
     192           0 :     absl::MutexLock lock(&mu_);
     193           0 :     if (file_handle_) {
     194           0 :       auto status = file_handle_->close([](absl::Status) {});
     195           0 :       ASSERT(status.ok(), status.ToString());
     196           0 :       file_handle_ = nullptr;
     197           0 :     }
     198           0 :   }
     199           0 : }
     200             : 
     201             : } // namespace FileSystemHttpCache
     202             : } // namespace Cache
     203             : } // namespace HttpFilters
     204             : } // namespace Extensions
     205             : } // namespace Envoy

Generated by: LCOV version 1.15