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