• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_operation_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 #include "third_party/abseil-cpp/absl/types/optional.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 absl::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. Returns the # of bytes read successfully.
347   // This asumes the caller has already range-checked offset and buf_len
348   // appropriately.
349   int 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   int SetStream0Data(net::IOBuffer* buf,
358                      int offset, int buf_len,
359                      bool truncate);
360 
361   // We want all async I/O on entries to complete before recycling the dir.
362   scoped_refptr<BackendCleanupTracker> cleanup_tracker_;
363 
364   std::unique_ptr<ActiveEntryProxy> active_entry_proxy_;
365 
366   // All nonstatic SimpleEntryImpl methods should always be called on the
367   // source creation sequence, in all cases. |sequence_checker_| documents and
368   // enforces this.
369   SEQUENCE_CHECKER(sequence_checker_);
370 
371   const base::WeakPtr<SimpleBackendImpl> backend_;
372   const raw_ptr<SimpleFileTracker> file_tracker_;
373   const scoped_refptr<BackendFileOperationsFactory> file_operations_factory_;
374   const net::CacheType cache_type_;
375   const base::FilePath path_;
376   const uint64_t entry_hash_;
377   const bool use_optimistic_operations_;
378   absl::optional<std::string> key_;
379 
380   // |last_used_|, |last_modified_| and |data_size_| are copied from the
381   // synchronous entry at the completion of each item of asynchronous IO.
382   // TODO(clamy): Unify last_used_ with data in the index.
383   base::Time last_used_;
384   base::Time last_modified_;
385   int32_t data_size_[kSimpleEntryStreamCount];
386   int32_t sparse_data_size_ = 0;
387 
388   // Number of times this object has been returned from Backend::OpenEntry() and
389   // Backend::CreateEntry() without subsequent Entry::Close() calls. Used to
390   // notify the backend when this entry not used by any callers.
391   int open_count_ = 0;
392 
393   DoomState doom_state_ = DOOM_NONE;
394 
395   enum {
396     CREATE_NORMAL,
397     CREATE_OPTIMISTIC_PENDING_DOOM,
398     CREATE_OPTIMISTIC_PENDING_DOOM_FOLLOWED_BY_DOOM,
399   } optimistic_create_pending_doom_state_ = CREATE_NORMAL;
400 
401   State state_ = STATE_UNINITIALIZED;
402 
403   // When possible, we compute a crc32, for the data in each entry as we read or
404   // write. For each stream, |crc32s_[index]| is the crc32 of that stream from
405   // [0 .. |crc32s_end_offset_|). If |crc32s_end_offset_[index] == 0| then the
406   // value of |crc32s_[index]| is undefined.
407   // Note at this can only be done in the current implementation in the case of
408   // a single entry reader that reads serially through the entire file.
409   // Extending this to multiple readers is possible, but isn't currently worth
410   // it; see http://crbug.com/488076#c3 for details.
411   int32_t crc32s_end_offset_[kSimpleEntryStreamCount];
412   uint32_t crc32s_[kSimpleEntryStreamCount];
413 
414   // If |have_written_[index]| is true, we have written to the file that
415   // contains stream |index|.
416   bool have_written_[kSimpleEntryStreamCount];
417 
418   // The |synchronous_entry_| is the worker thread object that performs IO on
419   // entries. It's owned by this SimpleEntryImpl whenever |executing_operation_|
420   // is false (i.e. when an operation is not pending on the worker pool). When
421   // an operation is being executed no one owns the synchronous entry. Therefore
422   // SimpleEntryImpl should not be deleted while an operation is running as that
423   // would leak the SimpleSynchronousEntry.
424   // This dangling raw_ptr occurred in:
425   // content_unittests:
426   // GeneratedCodeCacheTest/GeneratedCodeCacheTest.StressVeryLargeEntries/1
427   // https://ci.chromium.org/ui/p/chromium/builders/try/linux-rel/1425125/test-results?q=ExactID%3Aninja%3A%2F%2Fcontent%2Ftest%3Acontent_unittests%2FGeneratedCodeCacheTest.StressVeryLargeEntries%2FGeneratedCodeCacheTest.1+VHash%3Ab3ba0803668e9981&sortby=&groupby=
428   raw_ptr<SimpleSynchronousEntry, FlakyDanglingUntriaged> synchronous_entry_ =
429       nullptr;
430 
431   scoped_refptr<net::PrioritizedTaskRunner> prioritized_task_runner_;
432 
433   base::queue<SimpleEntryOperation> pending_operations_;
434 
435   net::NetLogWithSource net_log_;
436 
437   // Unlike other streams, stream 0 data is read from the disk when the entry is
438   // opened, and then kept in memory. All read/write operations on stream 0
439   // affect the |stream_0_data_| buffer. When the entry is closed,
440   // |stream_0_data_| is written to the disk.
441   // Stream 0 is kept in memory because it is stored in the same file as stream
442   // 1 on disk, to reduce the number of file descriptors and save disk space.
443   // This strategy allows stream 1 to change size easily. Since stream 0 is only
444   // used to write HTTP headers, the memory consumption of keeping it in memory
445   // is acceptable.
446   scoped_refptr<net::GrowableIOBuffer> stream_0_data_;
447 
448   // Sometimes stream 1 data is prefetched when stream 0 is first read.
449   // If a write to the stream occurs on the entry the prefetch buffer is
450   // discarded. It may also be null if it wasn't prefetched in the first place.
451   scoped_refptr<net::GrowableIOBuffer> stream_1_prefetch_data_;
452 
453   // This is used only while a doom is pending.
454   scoped_refptr<SimplePostOperationWaiterTable> post_doom_waiting_;
455 
456   // Choosing uint32_t over uint64_t for space savings. Pages have in the
457   // hundres to possibly thousands of resources. Wrapping every 4 billion
458   // shouldn't cause inverted priorities very often.
459   uint32_t entry_priority_ = 0;
460 };
461 
462 }  // namespace disk_cache
463 
464 #endif  // NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_IMPL_H_
465