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(Event::Dispatcher& dispatcher, FileSystemHttpCache& cache,
23
                    LookupRequest&& lookup)
24
92
      : dispatcher_(dispatcher), cache_(cache), key_(lookup.key()), lookup_(std::move(lookup)) {}
25

            
26
  // From LookupContext
27
  void getHeaders(LookupHeadersCallback&& cb) final;
28
  void getBody(const AdjustedByteRange& range, LookupBodyCallback&& cb) final;
29
  void getTrailers(LookupTrailersCallback&& cb) final;
30
  void onDestroy() final;
31
  // This shouldn't be necessary since onDestroy is supposed to always be called, but in some
32
  // tests it is not.
33
92
  ~FileLookupContext() override { onDestroy(); }
34

            
35
152
  const LookupRequest& lookup() const { return lookup_; }
36
53
  const Key& key() const { return key_; }
37
  bool workInProgress() const;
38
433
  Event::Dispatcher* dispatcher() const { return &dispatcher_; }
39

            
40
private:
41
  void tryOpenCacheFile();
42
  void doCacheMiss();
43
  void doCacheEntryInvalid();
44
  void getHeaderBlockFromFile();
45
  void getHeadersFromFile();
46
  void closeFileAndGetHeadersAgainWithNewVaryKey();
47

            
48
  // In the event that the cache failed to retrieve, remove the cache entry from the
49
  // cache so we don't keep repeating the same failure.
50
  void invalidateCacheEntry();
51

            
52
  std::string filepath();
53

            
54
  Event::Dispatcher& dispatcher_;
55

            
56
  // We can safely use a reference here, because the shared_ptr to a cache is guaranteed to outlive
57
  // all filters that use it.
58
  FileSystemHttpCache& cache_;
59

            
60
  AsyncFileHandle file_handle_;
61
  CancelFunction cancel_action_in_flight_;
62
  CacheFileFixedBlock header_block_;
63
  Key key_;
64

            
65
  LookupHeadersCallback lookup_headers_callback_;
66
  const LookupRequest lookup_;
67
};
68

            
69
// TODO(ravenblack): A CacheEntryInProgressReader should be implemented to prevent
70
// "thundering herd" problem.
71
//
72
// First the insert needs to be performed not by using the existing request but by
73
// issuing its own request[s], otherwise the first client to request a resource could
74
// provoke failure for any other clients sharing that data-stream, by closing its
75
// request before the cache population is completed.
76
//
77
// The plan is to make the entire cache insert happen "out of band", and to populate
78
// the cache with a CacheEntryInProgress object, allowing clients to stream from it in
79
// parallel.
80
//
81
// This may require intercepting at the initialization of LookupContext to trigger
82
// immediate "InProgress" cache insertion for any resource compatible with cache
83
// insertion, and the beginning of that out-of-band download - this way the original
84
// requester can be a sibling of any subsequent requester, whereas if we waited for
85
// the cache filter's insert path to be reached then the process would potentially be
86
// much more confusing (because we will never want a stream to be doing the inserting
87
// if we have an external task for that, and because there would be a race where two
88
// clients could get past the lookup before either creates an InsertContext).
89
//
90
// The current, early implementation simply allows requests to bypass the cache when
91
// the cache entry is in the process of being populated. It is therefore subject to
92
// the "thundering herd" problem.
93

            
94
} // namespace FileSystemHttpCache
95
} // namespace Cache
96
} // namespace HttpFilters
97
} // namespace Extensions
98
} // namespace Envoy