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