Line data Source code
1 : #pragma once 2 : 3 : #include <memory> 4 : 5 : #include "source/extensions/common/async_files/async_file_handle.h" 6 : #include "source/extensions/filters/http/cache/http_cache.h" 7 : #include "source/extensions/http/cache/file_system_http_cache/cache_file_fixed_block.h" 8 : 9 : namespace Envoy { 10 : namespace Extensions { 11 : namespace HttpFilters { 12 : namespace Cache { 13 : namespace FileSystemHttpCache { 14 : 15 : class FileSystemHttpCache; 16 : 17 : using Envoy::Extensions::Common::AsyncFiles::AsyncFileHandle; 18 : using Envoy::Extensions::Common::AsyncFiles::CancelFunction; 19 : 20 : class FileLookupContext : public LookupContext { 21 : public: 22 : FileLookupContext(FileSystemHttpCache& cache, LookupRequest&& lookup) 23 0 : : cache_(cache), key_(lookup.key()), lookup_(std::move(lookup)) {} 24 : 25 : // From LookupContext 26 : void getHeaders(LookupHeadersCallback&& cb) final; 27 : void getBody(const AdjustedByteRange& range, LookupBodyCallback&& cb) final; 28 : void getTrailers(LookupTrailersCallback&& cb) final; 29 : void onDestroy() final; 30 : // This shouldn't be necessary since onDestroy is supposed to always be called, but in some 31 : // tests it is not. 32 0 : ~FileLookupContext() override { onDestroy(); } 33 : 34 0 : const LookupRequest& lookup() const { return lookup_; } 35 0 : const Key& key() const { return key_; } 36 : bool workInProgress() const; 37 : 38 : private: 39 : void getHeadersWithLock(LookupHeadersCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); 40 : 41 : // In the event that the cache failed to retrieve, remove the cache entry from the 42 : // cache so we don't keep repeating the same failure. 43 : void invalidateCacheEntry() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); 44 : 45 : std::string filepath() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); 46 : 47 : // We can safely use a reference here, because the shared_ptr to a cache is guaranteed to outlive 48 : // all filters that use it. 49 : FileSystemHttpCache& cache_; 50 : 51 : // File actions may be initiated in the file thread or the filter thread, and cancelled or 52 : // completed from either, therefore must be guarded by a mutex. 53 : absl::Mutex mu_; 54 : AsyncFileHandle file_handle_ ABSL_GUARDED_BY(mu_); 55 : CancelFunction cancel_action_in_flight_ ABSL_GUARDED_BY(mu_); 56 : CacheFileFixedBlock header_block_ ABSL_GUARDED_BY(mu_); 57 : Key key_ ABSL_GUARDED_BY(mu_); 58 : 59 : const LookupRequest lookup_; 60 : }; 61 : 62 : // TODO(ravenblack): A CacheEntryInProgressReader should be implemented to prevent 63 : // "thundering herd" problem. 64 : // 65 : // First the insert needs to be performed not by using the existing request but by 66 : // issuing its own request[s], otherwise the first client to request a resource could 67 : // provoke failure for any other clients sharing that data-stream, by closing its 68 : // request before the cache population is completed. 69 : // 70 : // The plan is to make the entire cache insert happen "out of band", and to populate 71 : // the cache with a CacheEntryInProgress object, allowing clients to stream from it in 72 : // parallel. 73 : // 74 : // This may require intercepting at the initialization of LookupContext to trigger 75 : // immediate "InProgress" cache insertion for any resource compatible with cache 76 : // insertion, and the beginning of that out-of-band download - this way the original 77 : // requester can be a sibling of any subsequent requester, whereas if we waited for 78 : // the cache filter's insert path to be reached then the process would potentially be 79 : // much more confusing (because we will never want a stream to be doing the inserting 80 : // if we have an external task for that, and because there would be a race where two 81 : // clients could get past the lookup before either creates an InsertContext). 82 : // 83 : // The current, early implementation simply allows requests to bypass the cache when 84 : // the cache entry is in the process of being populated. It is therefore subject to 85 : // the "thundering herd" problem. 86 : 87 : } // namespace FileSystemHttpCache 88 : } // namespace Cache 89 : } // namespace HttpFilters 90 : } // namespace Extensions 91 : } // namespace Envoy