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_ENTRY_IMPL_H_ 6 #define NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_IMPL_H_ 7 8 #include <stdint.h> 9 10 #include <memory> 11 #include <optional> 12 #include <string> 13 14 #include "base/containers/queue.h" 15 #include "base/files/file_path.h" 16 #include "base/memory/raw_ptr.h" 17 #include "base/memory/ref_counted.h" 18 #include "base/sequence_checker.h" 19 #include "base/time/time.h" 20 #include "net/base/cache_type.h" 21 #include "net/base/net_export.h" 22 #include "net/base/request_priority.h" 23 #include "net/disk_cache/disk_cache.h" 24 #include "net/disk_cache/simple/post_operation_waiter.h" 25 #include "net/disk_cache/simple/simple_entry_format.h" 26 #include "net/disk_cache/simple/simple_entry_operation.h" 27 #include "net/disk_cache/simple/simple_synchronous_entry.h" 28 #include "net/log/net_log_event_type.h" 29 #include "net/log/net_log_with_source.h" 30 31 namespace base { 32 class TaskRunner; 33 } 34 35 namespace net { 36 class GrowableIOBuffer; 37 class IOBuffer; 38 class NetLog; 39 class PrioritizedTaskRunner; 40 } 41 42 namespace disk_cache { 43 44 class BackendCleanupTracker; 45 class SimpleBackendImpl; 46 class SimpleEntryStat; 47 class SimpleFileTracker; 48 class SimpleSynchronousEntry; 49 struct SimpleEntryCreationResults; 50 51 // SimpleEntryImpl is the source task_runner interface to an entry in the very 52 // simple disk cache. It proxies for the SimpleSynchronousEntry, which performs 53 // IO on the worker thread. 54 class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry, 55 public base::RefCounted<SimpleEntryImpl> { 56 friend class base::RefCounted<SimpleEntryImpl>; 57 public: 58 enum OperationsMode { 59 NON_OPTIMISTIC_OPERATIONS, 60 OPTIMISTIC_OPERATIONS, 61 }; 62 63 // The Backend provides an |ActiveEntryProxy| instance to this entry when it 64 // is active, meaning it's the canonical entry for this |entry_hash_|. The 65 // entry can make itself inactive by deleting its proxy. 66 class ActiveEntryProxy { 67 public: 68 virtual ~ActiveEntryProxy() = 0; 69 }; 70 71 SimpleEntryImpl( 72 net::CacheType cache_type, 73 const base::FilePath& path, 74 scoped_refptr<BackendCleanupTracker> cleanup_tracker, 75 uint64_t entry_hash, 76 OperationsMode operations_mode, 77 SimpleBackendImpl* backend, 78 SimpleFileTracker* file_tracker, 79 scoped_refptr<BackendFileOperationsFactory> file_operations_factory, 80 net::NetLog* net_log, 81 uint32_t entry_priority); 82 83 void SetActiveEntryProxy( 84 std::unique_ptr<ActiveEntryProxy> active_entry_proxy); 85 86 // Adds another reader/writer to this entry, if possible. 87 EntryResult OpenEntry(EntryResultCallback callback); 88 89 // Creates this entry, if possible. 90 EntryResult CreateEntry(EntryResultCallback callback); 91 92 // Opens an existing entry or creates a new one. 93 EntryResult OpenOrCreateEntry(EntryResultCallback callback); 94 95 // Identical to Backend::Doom() except that it accepts a 96 // CompletionOnceCallback. 97 net::Error DoomEntry(CompletionOnceCallback callback); 98 key()99 const std::optional<std::string>& key() const { return key_; } entry_hash()100 uint64_t entry_hash() const { return entry_hash_; } 101 102 // The key is not a constructor parameter to the SimpleEntryImpl, because 103 // during cache iteration, it's necessary to open entries by their hash 104 // alone. In that case, the SimpleSynchronousEntry will read the key from disk 105 // and it will be set. 106 void SetKey(const std::string& key); 107 108 // SetCreatePendingDoom() should be called before CreateEntry() if the 109 // creation should suceed optimistically but not do any I/O until 110 // NotifyDoomBeforeCreateComplete() is called. 111 void SetCreatePendingDoom(); 112 void NotifyDoomBeforeCreateComplete(); 113 114 // From Entry: 115 void Doom() override; 116 void Close() override; 117 // This is only used as a public API, not internally. 118 std::string GetKey() const override; 119 // GetLastUsed() should not be called in net::APP_CACHE mode since the times 120 // are not updated. 121 base::Time GetLastUsed() const override; 122 base::Time GetLastModified() const override; 123 int32_t GetDataSize(int index) const override; 124 int ReadData(int stream_index, 125 int offset, 126 net::IOBuffer* buf, 127 int buf_len, 128 CompletionOnceCallback callback) override; 129 int WriteData(int stream_index, 130 int offset, 131 net::IOBuffer* buf, 132 int buf_len, 133 CompletionOnceCallback callback, 134 bool truncate) override; 135 int ReadSparseData(int64_t offset, 136 net::IOBuffer* buf, 137 int buf_len, 138 CompletionOnceCallback callback) override; 139 int WriteSparseData(int64_t offset, 140 net::IOBuffer* buf, 141 int buf_len, 142 CompletionOnceCallback callback) override; 143 RangeResult GetAvailableRange(int64_t offset, 144 int len, 145 RangeResultCallback callback) override; 146 bool CouldBeSparse() const override; 147 void CancelSparseIO() override; 148 net::Error ReadyForSparseIO(CompletionOnceCallback callback) override; 149 void SetLastUsedTimeForTest(base::Time time) override; 150 151 // Changes the entry's priority in its TaskRunner. 152 void SetPriority(uint32_t entry_priority); 153 154 private: 155 class ScopedOperationRunner; 156 friend class ScopedOperationRunner; 157 158 enum State { 159 // The state immediately after construction, but before |synchronous_entry_| 160 // has been assigned. This is the state at construction, and is one of the 161 // two states (along with failure) one can destruct an entry in. 162 STATE_UNINITIALIZED, 163 164 // This entry is available for regular IO. 165 STATE_READY, 166 167 // IO is currently in flight, operations must wait for completion before 168 // launching. 169 STATE_IO_PENDING, 170 171 // A failure occurred in the current or previous operation. All operations 172 // after that must fail, until we receive a Close(). 173 STATE_FAILURE, 174 }; 175 176 enum DoomState { 177 // No attempt to doom the entry has been made. 178 DOOM_NONE, 179 180 // We have moved ourselves to |entries_pending_doom_| and have queued an 181 // operation to actually update the disk, but haven't completed it yet. 182 DOOM_QUEUED, 183 184 // The disk has been updated. This corresponds to the state where we 185 // are in neither |entries_pending_doom_| nor |active_entries_|. 186 DOOM_COMPLETED, 187 }; 188 189 ~SimpleEntryImpl() override; 190 191 // Must be used to invoke a client-provided completion callback for an 192 // operation initiated through the backend (e.g. create, open, doom) so that 193 // clients don't get notified after they deleted the backend (which they would 194 // not expect). 195 void PostClientCallback(CompletionOnceCallback callback, int result); 196 void PostClientCallback(EntryResultCallback callback, EntryResult result); 197 198 // Clears entry state enough to prepare it for re-use. This will generally 199 // put it back into STATE_UNINITIALIZED, except if the entry is doomed and 200 // therefore disconnected from ownership of corresponding filename, in which 201 // case it will be put into STATE_FAILURE. 202 void ResetEntry(); 203 204 // Adjust ownership before return of this entry to a user of the API. 205 // Increments the user count. 206 void ReturnEntryToCaller(); 207 208 // Like above, but for asynchronous return after the event loop runs again, 209 // also invoking the callback per the usual net convention. 210 // The return is cancelled if the backend is deleted in the interim. 211 void ReturnEntryToCallerAsync(bool is_open, EntryResultCallback callback); 212 213 // Portion of the above that runs off the event loop. 214 void FinishReturnEntryToCallerAsync(bool is_open, 215 EntryResultCallback callback); 216 217 // Remove |this| from the Backend and the index, either because 218 // SimpleSynchronousEntry has detected an error or because we are about to 219 // be dooming it ourselves and want it to be tracked in 220 // |entries_pending_doom_| instead. 221 void MarkAsDoomed(DoomState doom_state); 222 223 // Runs the next operation in the queue, if any and if there is no other 224 // operation running at the moment. 225 // WARNING: May delete |this|, as an operation in the queue can contain 226 // the last reference. 227 void RunNextOperationIfNeeded(); 228 229 void OpenEntryInternal(SimpleEntryOperation::EntryResultState result_state, 230 EntryResultCallback callback); 231 232 void CreateEntryInternal(SimpleEntryOperation::EntryResultState result_state, 233 EntryResultCallback callback); 234 235 void OpenOrCreateEntryInternal( 236 OpenEntryIndexEnum index_state, 237 SimpleEntryOperation::EntryResultState result_state, 238 EntryResultCallback callback); 239 240 void CloseInternal(); 241 242 int ReadDataInternal(bool sync_possible, 243 int index, 244 int offset, 245 net::IOBuffer* buf, 246 int buf_len, 247 CompletionOnceCallback callback); 248 249 void WriteDataInternal(int index, 250 int offset, 251 net::IOBuffer* buf, 252 int buf_len, 253 CompletionOnceCallback callback, 254 bool truncate); 255 256 void ReadSparseDataInternal(int64_t sparse_offset, 257 net::IOBuffer* buf, 258 int buf_len, 259 CompletionOnceCallback callback); 260 261 void WriteSparseDataInternal(int64_t sparse_offset, 262 net::IOBuffer* buf, 263 int buf_len, 264 CompletionOnceCallback callback); 265 266 void GetAvailableRangeInternal(int64_t sparse_offset, 267 int len, 268 RangeResultCallback callback); 269 270 void DoomEntryInternal(CompletionOnceCallback callback); 271 272 // Called after a SimpleSynchronousEntry has completed CreateEntry() or 273 // OpenEntry(). If |in_results| is used to denote whether that was successful, 274 // Posts either the produced entry or an error code to |completion_callback|. 275 void CreationOperationComplete( 276 SimpleEntryOperation::EntryResultState result_state, 277 EntryResultCallback completion_callback, 278 const base::TimeTicks& start_time, 279 const base::Time index_last_used_time, 280 std::unique_ptr<SimpleEntryCreationResults> in_results, 281 net::NetLogEventType end_event_type); 282 283 // Called after we've closed and written the EOF record to our entry. Until 284 // this point it hasn't been safe to OpenEntry() the same entry, but from this 285 // point it is. 286 void CloseOperationComplete( 287 std::unique_ptr<SimpleEntryCloseResults> in_results); 288 289 // Internal utility method used by other completion methods. 290 // Updaties state and dooms on errors. 291 void UpdateStateAfterOperationComplete(const SimpleEntryStat& entry_stat, 292 int result); 293 294 // Internal utility method used by other completion methods. Calls 295 // |completion_callback| after updating state and dooming on errors. 296 void EntryOperationComplete(CompletionOnceCallback completion_callback, 297 const SimpleEntryStat& entry_stat, 298 int result); 299 300 // Called after an asynchronous read. Updates |crc32s_| if possible. 301 void ReadOperationComplete( 302 int stream_index, 303 int offset, 304 CompletionOnceCallback completion_callback, 305 std::unique_ptr<SimpleEntryStat> entry_stat, 306 std::unique_ptr<SimpleSynchronousEntry::ReadResult> read_result); 307 308 // Called after an asynchronous write completes. 309 // |buf| parameter brings back a reference to net::IOBuffer to the original 310 // sequence, so that we can reduce cross thread malloc/free pair. 311 // See http://crbug.com/708644 for details. 312 void WriteOperationComplete( 313 int stream_index, 314 CompletionOnceCallback completion_callback, 315 std::unique_ptr<SimpleEntryStat> entry_stat, 316 std::unique_ptr<SimpleSynchronousEntry::WriteResult> result, 317 net::IOBuffer* buf); 318 319 void ReadSparseOperationComplete(CompletionOnceCallback completion_callback, 320 std::unique_ptr<base::Time> last_used, 321 std::unique_ptr<int> result); 322 323 void WriteSparseOperationComplete(CompletionOnceCallback completion_callback, 324 std::unique_ptr<SimpleEntryStat> entry_stat, 325 std::unique_ptr<int> result); 326 327 void GetAvailableRangeOperationComplete( 328 RangeResultCallback completion_callback, 329 std::unique_ptr<RangeResult> result); 330 331 // Called after an asynchronous doom completes. 332 void DoomOperationComplete(CompletionOnceCallback callback, 333 State state_to_restore, 334 int result); 335 336 // Called after completion of an operation, to either incoproprate file info 337 // received from I/O done on the worker pool, or to simply bump the 338 // timestamps. Updates the metadata both in |this| and in the index. 339 // Stream size information in particular may be important for following 340 // operations. 341 void UpdateDataFromEntryStat(const SimpleEntryStat& entry_stat); 342 343 int64_t GetDiskUsage() const; 344 345 // Completes a read from the stream data kept in memory, logging metrics 346 // and updating metadata. This assumes the caller has already range-checked 347 // offset and buf_len appropriately, and therefore always reads `buf_len` 348 // bytes. 349 void ReadFromBuffer(net::GrowableIOBuffer* in_buf, 350 int offset, 351 int buf_len, 352 net::IOBuffer* out_buf); 353 354 // Copies data from |buf| to the internal in-memory buffer for stream 0. If 355 // |truncate| is set to true, the target buffer will be truncated at |offset| 356 // + |buf_len| before being written. 357 void SetStream0Data(net::IOBuffer* buf, 358 int offset, 359 int buf_len, 360 bool truncate); 361 362 // We want all async I/O on entries to complete before recycling the dir. 363 scoped_refptr<BackendCleanupTracker> cleanup_tracker_; 364 365 std::unique_ptr<ActiveEntryProxy> active_entry_proxy_; 366 367 // All nonstatic SimpleEntryImpl methods should always be called on the 368 // source creation sequence, in all cases. |sequence_checker_| documents and 369 // enforces this. 370 SEQUENCE_CHECKER(sequence_checker_); 371 372 const base::WeakPtr<SimpleBackendImpl> backend_; 373 const raw_ptr<SimpleFileTracker> file_tracker_; 374 const scoped_refptr<BackendFileOperationsFactory> file_operations_factory_; 375 const net::CacheType cache_type_; 376 const base::FilePath path_; 377 const uint64_t entry_hash_; 378 const bool use_optimistic_operations_; 379 std::optional<std::string> key_; 380 381 // |last_used_|, |last_modified_| and |data_size_| are copied from the 382 // synchronous entry at the completion of each item of asynchronous IO. 383 // TODO(clamy): Unify last_used_ with data in the index. 384 base::Time last_used_; 385 base::Time last_modified_; 386 int32_t data_size_[kSimpleEntryStreamCount]; 387 int32_t sparse_data_size_ = 0; 388 389 // Number of times this object has been returned from Backend::OpenEntry() and 390 // Backend::CreateEntry() without subsequent Entry::Close() calls. Used to 391 // notify the backend when this entry not used by any callers. 392 int open_count_ = 0; 393 394 DoomState doom_state_ = DOOM_NONE; 395 396 enum { 397 CREATE_NORMAL, 398 CREATE_OPTIMISTIC_PENDING_DOOM, 399 CREATE_OPTIMISTIC_PENDING_DOOM_FOLLOWED_BY_DOOM, 400 } optimistic_create_pending_doom_state_ = CREATE_NORMAL; 401 402 State state_ = STATE_UNINITIALIZED; 403 404 // When possible, we compute a crc32, for the data in each entry as we read or 405 // write. For each stream, |crc32s_[index]| is the crc32 of that stream from 406 // [0 .. |crc32s_end_offset_|). If |crc32s_end_offset_[index] == 0| then the 407 // value of |crc32s_[index]| is undefined. 408 // Note at this can only be done in the current implementation in the case of 409 // a single entry reader that reads serially through the entire file. 410 // Extending this to multiple readers is possible, but isn't currently worth 411 // it; see http://crbug.com/488076#c3 for details. 412 int32_t crc32s_end_offset_[kSimpleEntryStreamCount]; 413 uint32_t crc32s_[kSimpleEntryStreamCount]; 414 415 // If |have_written_[index]| is true, we have written to the file that 416 // contains stream |index|. 417 bool have_written_[kSimpleEntryStreamCount]; 418 419 // The |synchronous_entry_| is the worker thread object that performs IO on 420 // entries. It's owned by this SimpleEntryImpl whenever |executing_operation_| 421 // is false (i.e. when an operation is not pending on the worker pool). When 422 // an operation is being executed no one owns the synchronous entry. Therefore 423 // SimpleEntryImpl should not be deleted while an operation is running as that 424 // would leak the SimpleSynchronousEntry. 425 raw_ptr<SimpleSynchronousEntry> synchronous_entry_ = nullptr; 426 427 scoped_refptr<net::PrioritizedTaskRunner> prioritized_task_runner_; 428 429 base::queue<SimpleEntryOperation> pending_operations_; 430 431 net::NetLogWithSource net_log_; 432 433 // Unlike other streams, stream 0 data is read from the disk when the entry is 434 // opened, and then kept in memory. All read/write operations on stream 0 435 // affect the |stream_0_data_| buffer. When the entry is closed, 436 // |stream_0_data_| is written to the disk. 437 // Stream 0 is kept in memory because it is stored in the same file as stream 438 // 1 on disk, to reduce the number of file descriptors and save disk space. 439 // This strategy allows stream 1 to change size easily. Since stream 0 is only 440 // used to write HTTP headers, the memory consumption of keeping it in memory 441 // is acceptable. 442 scoped_refptr<net::GrowableIOBuffer> stream_0_data_; 443 444 // Sometimes stream 1 data is prefetched when stream 0 is first read. 445 // If a write to the stream occurs on the entry the prefetch buffer is 446 // discarded. It may also be null if it wasn't prefetched in the first place. 447 scoped_refptr<net::GrowableIOBuffer> stream_1_prefetch_data_; 448 449 // This is used only while a doom is pending. 450 scoped_refptr<SimplePostOperationWaiterTable> post_doom_waiting_; 451 452 // Choosing uint32_t over uint64_t for space savings. Pages have in the 453 // hundres to possibly thousands of resources. Wrapping every 4 billion 454 // shouldn't cause inverted priorities very often. 455 uint32_t entry_priority_ = 0; 456 }; 457 458 } // namespace disk_cache 459 460 #endif // NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_IMPL_H_ 461