xref: /aosp_15_r20/external/cronet/net/disk_cache/simple/simple_index.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_DISK_CACHE_SIMPLE_SIMPLE_INDEX_H_
6 #define NET_DISK_CACHE_SIMPLE_SIMPLE_INDEX_H_
7 
8 #include <stdint.h>
9 
10 #include <list>
11 #include <memory>
12 #include <unordered_map>
13 #include <unordered_set>
14 #include <vector>
15 
16 #include "base/functional/callback.h"
17 #include "base/gtest_prod_util.h"
18 #include "base/memory/raw_ptr.h"
19 #include "base/memory/scoped_refptr.h"
20 #include "base/memory/weak_ptr.h"
21 #include "base/numerics/safe_conversions.h"
22 #include "base/sequence_checker.h"
23 #include "base/task/sequenced_task_runner.h"
24 #include "base/time/time.h"
25 #include "base/timer/timer.h"
26 #include "build/build_config.h"
27 #include "net/base/cache_type.h"
28 #include "net/base/completion_once_callback.h"
29 #include "net/base/net_errors.h"
30 #include "net/base/net_export.h"
31 #include "net/disk_cache/disk_cache.h"
32 
33 #if BUILDFLAG(IS_ANDROID)
34 #include "base/android/application_status_listener.h"
35 #endif
36 
37 namespace base {
38 class Pickle;
39 class PickleIterator;
40 }
41 
42 namespace disk_cache {
43 
44 class BackendCleanupTracker;
45 class SimpleIndexDelegate;
46 class SimpleIndexFile;
47 struct SimpleIndexLoadResult;
48 
49 class NET_EXPORT_PRIVATE EntryMetadata {
50  public:
51   EntryMetadata();
52   EntryMetadata(base::Time last_used_time,
53                 base::StrictNumeric<uint32_t> entry_size);
54   EntryMetadata(int32_t trailer_prefetch_size,
55                 base::StrictNumeric<uint32_t> entry_size);
56 
57   base::Time GetLastUsedTime() const;
58   void SetLastUsedTime(const base::Time& last_used_time);
59 
60   int32_t GetTrailerPrefetchSize() const;
61   void SetTrailerPrefetchSize(int32_t size);
62 
RawTimeForSorting()63   uint32_t RawTimeForSorting() const {
64     return last_used_time_seconds_since_epoch_;
65   }
66 
67   uint32_t GetEntrySize() const;
68   void SetEntrySize(base::StrictNumeric<uint32_t> entry_size);
69 
GetInMemoryData()70   uint8_t GetInMemoryData() const { return in_memory_data_; }
SetInMemoryData(uint8_t val)71   void SetInMemoryData(uint8_t val) { in_memory_data_ = val; }
72 
73   // Serialize the data into the provided pickle.
74   void Serialize(net::CacheType cache_type, base::Pickle* pickle) const;
75   bool Deserialize(net::CacheType cache_type,
76                    base::PickleIterator* it,
77                    bool has_entry_in_memory_data,
78                    bool app_cache_has_trailer_prefetch_size);
79 
GetLowerEpsilonForTimeComparisons()80   static base::TimeDelta GetLowerEpsilonForTimeComparisons() {
81     return base::Seconds(1);
82   }
GetUpperEpsilonForTimeComparisons()83   static base::TimeDelta GetUpperEpsilonForTimeComparisons() {
84     return base::TimeDelta();
85   }
86 
87   static const int kOnDiskSizeBytes = 16;
88 
89  private:
90   friend class SimpleIndexFileTest;
91   FRIEND_TEST_ALL_PREFIXES(SimpleIndexFileTest, ReadV8Format);
92   FRIEND_TEST_ALL_PREFIXES(SimpleIndexFileTest, ReadV8FormatAppCache);
93 
94   // There are tens of thousands of instances of EntryMetadata in memory, so the
95   // size of each entry matters.  Even when the values used to set these members
96   // are originally calculated as >32-bit types, the actual necessary size for
97   // each shouldn't exceed 32 bits, so we use 32-bit types here.
98 
99   // In most modes we track the last access time in order to support automatic
100   // eviction. In APP_CACHE mode, however, eviction is disabled. Instead of
101   // storing the access time in APP_CACHE mode we instead store a hint about
102   // how much entry file trailer should be prefetched when its opened.
103   union {
104     uint32_t last_used_time_seconds_since_epoch_;
105     int32_t trailer_prefetch_size_;  // in bytes
106   };
107 
108   uint32_t entry_size_256b_chunks_ : 24;  // in 256-byte blocks, rounded up.
109   uint32_t in_memory_data_ : 8;
110 };
111 static_assert(sizeof(EntryMetadata) == 8, "incorrect metadata size");
112 
113 // This class is not Thread-safe.
114 class NET_EXPORT_PRIVATE SimpleIndex
115     : public base::SupportsWeakPtr<SimpleIndex> {
116  public:
117   // Used in histograms. Please only add entries at the end.
118   enum IndexInitMethod {
119     INITIALIZE_METHOD_RECOVERED = 0,
120     INITIALIZE_METHOD_LOADED = 1,
121     INITIALIZE_METHOD_NEWCACHE = 2,
122     INITIALIZE_METHOD_MAX = 3,
123   };
124   // Used in histograms. Please only add entries at the end.
125   enum IndexWriteToDiskReason {
126     INDEX_WRITE_REASON_SHUTDOWN = 0,
127     INDEX_WRITE_REASON_STARTUP_MERGE = 1,
128     INDEX_WRITE_REASON_IDLE = 2,
129     INDEX_WRITE_REASON_ANDROID_STOPPED = 3,
130     INDEX_WRITE_REASON_MAX = 4,
131   };
132 
133   typedef std::vector<uint64_t> HashList;
134 
135   SimpleIndex(const scoped_refptr<base::SequencedTaskRunner>& task_runner,
136               scoped_refptr<BackendCleanupTracker> cleanup_tracker,
137               SimpleIndexDelegate* delegate,
138               net::CacheType cache_type,
139               std::unique_ptr<SimpleIndexFile> simple_index_file);
140 
141   virtual ~SimpleIndex();
142 
143   void Initialize(base::Time cache_mtime);
144 
145   void SetMaxSize(uint64_t max_bytes);
max_size()146   uint64_t max_size() const { return max_size_; }
147 
148   void Insert(uint64_t entry_hash);
149   void Remove(uint64_t entry_hash);
150 
151   // Check whether the index has the entry given the hash of its key.
152   bool Has(uint64_t entry_hash) const;
153 
154   // Update the last used time of the entry with the given key and return true
155   // iff the entry exist in the index.
156   bool UseIfExists(uint64_t entry_hash);
157 
158   uint8_t GetEntryInMemoryData(uint64_t entry_hash) const;
159   void SetEntryInMemoryData(uint64_t entry_hash, uint8_t value);
160 
161   void WriteToDisk(IndexWriteToDiskReason reason);
162 
163   int32_t GetTrailerPrefetchSize(uint64_t entry_hash) const;
164   void SetTrailerPrefetchSize(uint64_t entry_hash, int32_t size);
165 
166   // Update the size (in bytes) of an entry, in the metadata stored in the
167   // index. This should be the total disk-file size including all streams of the
168   // entry.
169   bool UpdateEntrySize(uint64_t entry_hash,
170                        base::StrictNumeric<uint32_t> entry_size);
171 
172   using EntrySet = std::unordered_map<uint64_t, EntryMetadata>;
173 
174   // Insert an entry in the given set if there is not already entry present.
175   // Returns true if the set was modified.
176   static bool InsertInEntrySet(uint64_t entry_hash,
177                                const EntryMetadata& entry_metadata,
178                                EntrySet* entry_set);
179 
180   // For use in tests only. Updates cache_size_, but will not start evictions
181   // or adjust index writing time. Requires entry to not already be in the set.
182   void InsertEntryForTesting(uint64_t entry_hash,
183                              const EntryMetadata& entry_metadata);
184 
185   // Executes the |callback| when the index is ready. Allows multiple callbacks.
186   // Never synchronous.
187   void ExecuteWhenReady(net::CompletionOnceCallback callback);
188 
189   // Returns entries from the index that have last accessed time matching the
190   // range between |initial_time| and |end_time| where open intervals are
191   // possible according to the definition given in |DoomEntriesBetween()| in the
192   // disk cache backend interface.
193   //
194   // Access times are not updated in net::APP_CACHE mode.  GetEntriesBetween()
195   // should only be called with null times indicating the full range when in
196   // this mode.
197   std::unique_ptr<HashList> GetEntriesBetween(const base::Time initial_time,
198                                               const base::Time end_time);
199 
200   // Returns the list of all entries key hash.
201   std::unique_ptr<HashList> GetAllHashes();
202 
203   // Returns number of indexed entries.
204   int32_t GetEntryCount() const;
205 
206   // Returns the size of the entire cache in bytes. Can only be called after the
207   // index has been initialized.
208   uint64_t GetCacheSize() const;
209 
210   // Returns the size of the cache entries accessed between |initial_time| and
211   // |end_time| in bytes. Can only be called after the index has been
212   // initialized.
213   uint64_t GetCacheSizeBetween(const base::Time initial_time,
214                                const base::Time end_time) const;
215 
216   // Returns whether the index has been initialized yet.
initialized()217   bool initialized() const { return initialized_; }
218 
init_method()219   IndexInitMethod init_method() const { return init_method_; }
220 
221   // Returns base::Time() if hash not known.
222   base::Time GetLastUsedTime(uint64_t entry_hash);
223   void SetLastUsedTimeForTest(uint64_t entry_hash, const base::Time last_used);
224 
225 #if BUILDFLAG(IS_ANDROID)
set_app_status_listener_getter(ApplicationStatusListenerGetter app_status_listener_getter)226   void set_app_status_listener_getter(
227       ApplicationStatusListenerGetter app_status_listener_getter) {
228     app_status_listener_getter_ = app_status_listener_getter;
229   }
230 #endif
231 
232   // Return true if a pending disk write has been scheduled from
233   // PostponeWritingToDisk().
234   bool HasPendingWrite() const;
235 
236  private:
237   friend class SimpleIndexTest;
238   FRIEND_TEST_ALL_PREFIXES(SimpleIndexTest, IndexSizeCorrectOnMerge);
239   FRIEND_TEST_ALL_PREFIXES(SimpleIndexTest, DiskWriteQueued);
240   FRIEND_TEST_ALL_PREFIXES(SimpleIndexTest, DiskWriteExecuted);
241   FRIEND_TEST_ALL_PREFIXES(SimpleIndexTest, DiskWritePostponed);
242   FRIEND_TEST_ALL_PREFIXES(SimpleIndexAppCacheTest, DiskWriteQueued);
243   FRIEND_TEST_ALL_PREFIXES(SimpleIndexCodeCacheTest, DisableEvictBySize);
244   FRIEND_TEST_ALL_PREFIXES(SimpleIndexCodeCacheTest, EnableEvictBySize);
245 
246   void StartEvictionIfNeeded();
247   void EvictionDone(int result);
248 
249   void PostponeWritingToDisk();
250 
251   // Update the size of the entry pointed to by the given iterator.  Return
252   // true if the new size actually results in a change.
253   bool UpdateEntryIteratorSize(EntrySet::iterator* it,
254                                base::StrictNumeric<uint32_t> entry_size);
255 
256   // Must run on IO Thread.
257   void MergeInitializingSet(std::unique_ptr<SimpleIndexLoadResult> load_result);
258 
259 #if BUILDFLAG(IS_ANDROID)
260   void OnApplicationStateChange(base::android::ApplicationState state);
261 
262   std::unique_ptr<base::android::ApplicationStatusListener>
263       owned_app_status_listener_;
264   ApplicationStatusListenerGetter app_status_listener_getter_;
265 #endif
266 
267   scoped_refptr<BackendCleanupTracker> cleanup_tracker_;
268 
269   // The owner of |this| must ensure the |delegate_| outlives |this|.
270   raw_ptr<SimpleIndexDelegate> delegate_;
271 
272   EntrySet entries_set_;
273 
274   const net::CacheType cache_type_;
275   uint64_t cache_size_ = 0;  // Total cache storage size in bytes.
276   uint64_t max_size_ = 0;
277   uint64_t high_watermark_ = 0;
278   uint64_t low_watermark_ = 0;
279   bool eviction_in_progress_ = false;
280   base::TimeTicks eviction_start_time_;
281 
282   // This stores all the entry_hash of entries that are removed during
283   // initialization.
284   std::unordered_set<uint64_t> removed_entries_;
285   bool initialized_ = false;
286   IndexInitMethod init_method_ = INITIALIZE_METHOD_MAX;
287 
288   std::unique_ptr<SimpleIndexFile> index_file_;
289 
290   scoped_refptr<base::SequencedTaskRunner> task_runner_;
291 
292   // All nonstatic SimpleEntryImpl methods should always be called on its
293   // creation sequance, in all cases. |sequence_checker_| documents and
294   // enforces this.
295   SEQUENCE_CHECKER(sequence_checker_);
296 
297   base::OneShotTimer write_to_disk_timer_;
298   base::RepeatingClosure write_to_disk_cb_;
299 
300   typedef std::list<net::CompletionOnceCallback> CallbackList;
301   CallbackList to_run_when_initialized_;
302 
303   // Set to true when the app is on the background. When the app is in the
304   // background we can write the index much more frequently, to insure fresh
305   // index on next startup.
306   bool app_on_background_ = false;
307 };
308 
309 }  // namespace disk_cache
310 
311 #endif  // NET_DISK_CACHE_SIMPLE_SIMPLE_INDEX_H_
312