|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_IMPL_H_ | 
|  | #define NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_IMPL_H_ | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  |  | 
|  | #include "base/containers/queue.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/threading/thread_checker.h" | 
|  | #include "net/base/cache_type.h" | 
|  | #include "net/base/net_export.h" | 
|  | #include "net/base/request_priority.h" | 
|  | #include "net/disk_cache/disk_cache.h" | 
|  | #include "net/disk_cache/simple/simple_entry_format.h" | 
|  | #include "net/disk_cache/simple/simple_entry_operation.h" | 
|  | #include "net/disk_cache/simple/simple_synchronous_entry.h" | 
|  | #include "net/log/net_log_event_type.h" | 
|  | #include "net/log/net_log_with_source.h" | 
|  | #include "starboard/types.h" | 
|  |  | 
|  | namespace base { | 
|  | class TaskRunner; | 
|  | } | 
|  |  | 
|  | namespace net { | 
|  | class GrowableIOBuffer; | 
|  | class IOBuffer; | 
|  | class NetLog; | 
|  | class PrioritizedTaskRunner; | 
|  | } | 
|  |  | 
|  | namespace disk_cache { | 
|  |  | 
|  | class BackendCleanupTracker; | 
|  | class SimpleBackendImpl; | 
|  | class SimpleEntryStat; | 
|  | class SimpleFileTracker; | 
|  | class SimpleSynchronousEntry; | 
|  | struct SimpleEntryCreationResults; | 
|  |  | 
|  | // SimpleEntryImpl is the IO thread interface to an entry in the very simple | 
|  | // disk cache. It proxies for the SimpleSynchronousEntry, which performs IO | 
|  | // on the worker thread. | 
|  | class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry, | 
|  | public base::RefCounted<SimpleEntryImpl> { | 
|  | friend class base::RefCounted<SimpleEntryImpl>; | 
|  | public: | 
|  | enum OperationsMode { | 
|  | NON_OPTIMISTIC_OPERATIONS, | 
|  | OPTIMISTIC_OPERATIONS, | 
|  | }; | 
|  |  | 
|  | // The Backend provides an |ActiveEntryProxy| instance to this entry when it | 
|  | // is active, meaning it's the canonical entry for this |entry_hash_|. The | 
|  | // entry can make itself inactive by deleting its proxy. | 
|  | class ActiveEntryProxy { | 
|  | public: | 
|  | virtual ~ActiveEntryProxy() = 0; | 
|  | }; | 
|  |  | 
|  | SimpleEntryImpl(net::CacheType cache_type, | 
|  | const base::FilePath& path, | 
|  | scoped_refptr<BackendCleanupTracker> cleanup_tracker, | 
|  | uint64_t entry_hash, | 
|  | OperationsMode operations_mode, | 
|  | SimpleBackendImpl* backend, | 
|  | SimpleFileTracker* file_tracker, | 
|  | net::NetLog* net_log, | 
|  | uint32_t entry_priority); | 
|  |  | 
|  | void SetActiveEntryProxy( | 
|  | std::unique_ptr<ActiveEntryProxy> active_entry_proxy); | 
|  |  | 
|  | // Adds another reader/writer to this entry, if possible, returning |this| to | 
|  | // |entry|. | 
|  | net::Error OpenEntry(Entry** entry, CompletionOnceCallback callback); | 
|  |  | 
|  | // Creates this entry, if possible. Returns |this| to |entry|. | 
|  | net::Error CreateEntry(Entry** entry, CompletionOnceCallback callback); | 
|  |  | 
|  | // Identical to Backend::Doom() except that it accepts a | 
|  | // CompletionOnceCallback. | 
|  | net::Error DoomEntry(CompletionOnceCallback callback); | 
|  |  | 
|  | const std::string& key() const { return key_; } | 
|  | uint64_t entry_hash() const { return entry_hash_; } | 
|  |  | 
|  | // The key is not a constructor parameter to the SimpleEntryImpl, because | 
|  | // during cache iteration, it's necessary to open entries by their hash | 
|  | // alone. In that case, the SimpleSynchronousEntry will read the key from disk | 
|  | // and it will be set. | 
|  | void SetKey(const std::string& key); | 
|  |  | 
|  | // SetCreatePendingDoom() should be called before CreateEntry() if the | 
|  | // creation should suceed optimistically but not do any I/O until | 
|  | // NotifyDoomBeforeCreateComplete() is called. | 
|  | void SetCreatePendingDoom(); | 
|  | void NotifyDoomBeforeCreateComplete(); | 
|  |  | 
|  | // From Entry: | 
|  | void Doom() override; | 
|  | void Close() override; | 
|  | std::string GetKey() const override; | 
|  | base::Time GetLastUsed() const override; | 
|  | base::Time GetLastModified() const override; | 
|  | int32_t GetDataSize(int index) const override; | 
|  | int ReadData(int stream_index, | 
|  | int offset, | 
|  | net::IOBuffer* buf, | 
|  | int buf_len, | 
|  | CompletionOnceCallback callback) override; | 
|  | int WriteData(int stream_index, | 
|  | int offset, | 
|  | net::IOBuffer* buf, | 
|  | int buf_len, | 
|  | CompletionOnceCallback callback, | 
|  | bool truncate) override; | 
|  | int ReadSparseData(int64_t offset, | 
|  | net::IOBuffer* buf, | 
|  | int buf_len, | 
|  | CompletionOnceCallback callback) override; | 
|  | int WriteSparseData(int64_t offset, | 
|  | net::IOBuffer* buf, | 
|  | int buf_len, | 
|  | CompletionOnceCallback callback) override; | 
|  | int GetAvailableRange(int64_t offset, | 
|  | int len, | 
|  | int64_t* start, | 
|  | CompletionOnceCallback callback) override; | 
|  | bool CouldBeSparse() const override; | 
|  | void CancelSparseIO() override; | 
|  | net::Error ReadyForSparseIO(CompletionOnceCallback callback) override; | 
|  | void SetLastUsedTimeForTest(base::Time time) override; | 
|  |  | 
|  | // Returns the estimate of dynamically allocated memory in bytes. | 
|  | size_t EstimateMemoryUsage() const; | 
|  |  | 
|  | // Changes the entry's priority in its TaskRunner. | 
|  | void SetPriority(uint32_t entry_priority); | 
|  |  | 
|  | private: | 
|  | class ScopedOperationRunner; | 
|  | friend class ScopedOperationRunner; | 
|  |  | 
|  | enum State { | 
|  | // The state immediately after construction, but before |synchronous_entry_| | 
|  | // has been assigned. This is the state at construction, and is one of the | 
|  | // two states (along with failure) one can destruct an entry in. | 
|  | STATE_UNINITIALIZED, | 
|  |  | 
|  | // This entry is available for regular IO. | 
|  | STATE_READY, | 
|  |  | 
|  | // IO is currently in flight, operations must wait for completion before | 
|  | // launching. | 
|  | STATE_IO_PENDING, | 
|  |  | 
|  | // A failure occurred in the current or previous operation. All operations | 
|  | // after that must fail, until we receive a Close(). | 
|  | STATE_FAILURE, | 
|  | }; | 
|  |  | 
|  | enum DoomState { | 
|  | // No attempt to doom the entry has been made. | 
|  | DOOM_NONE, | 
|  |  | 
|  | // We have moved ourselves to |entries_pending_doom_| and have queued an | 
|  | // operation to actually update the disk, but haven't completed it yet. | 
|  | DOOM_QUEUED, | 
|  |  | 
|  | // The disk has been updated. This corresponds to the state where we | 
|  | // are in neither |entries_pending_doom_| nor |active_entries_|. | 
|  | DOOM_COMPLETED, | 
|  | }; | 
|  |  | 
|  | // Used in histograms, please only add entries at the end. | 
|  | enum CheckCrcResult { | 
|  | CRC_CHECK_NEVER_READ_TO_END = 0, | 
|  | CRC_CHECK_NOT_DONE = 1, | 
|  | CRC_CHECK_DONE = 2, | 
|  | CRC_CHECK_NEVER_READ_AT_ALL = 3, | 
|  | CRC_CHECK_MAX = 4, | 
|  | }; | 
|  |  | 
|  | ~SimpleEntryImpl() override; | 
|  |  | 
|  | // Must be used to invoke a client-provided completion callback for an | 
|  | // operation initiated through the backend (e.g. create, open, doom) so that | 
|  | // clients don't get notified after they deleted the backend (which they would | 
|  | // not expect). | 
|  | void PostClientCallback(CompletionOnceCallback callback, int result); | 
|  |  | 
|  | // Clears entry state enough to prepare it for re-use. This will generally | 
|  | // put it back into STATE_UNINITIALIZED, except if the entry is doomed and | 
|  | // therefore disconnected from ownership of corresponding filename, in which | 
|  | // case it will be put into STATE_FAILURE. | 
|  | void ResetEntry(); | 
|  |  | 
|  | // Return this entry to a user of the API in |out_entry|. Increments the user | 
|  | // count. | 
|  | void ReturnEntryToCaller(Entry** out_entry); | 
|  |  | 
|  | // Remove |this| from the Backend and the index, either because | 
|  | // SimpleSynchronousEntry has detected an error or because we are about to | 
|  | // be dooming it ourselves and want it to be tracked in | 
|  | // |entries_pending_doom_| instead. | 
|  | void MarkAsDoomed(DoomState doom_state); | 
|  |  | 
|  | // Runs the next operation in the queue, if any and if there is no other | 
|  | // operation running at the moment. | 
|  | // WARNING: May delete |this|, as an operation in the queue can contain | 
|  | // the last reference. | 
|  | void RunNextOperationIfNeeded(); | 
|  |  | 
|  | void OpenEntryInternal(bool have_index, | 
|  | CompletionOnceCallback callback, | 
|  | Entry** out_entry); | 
|  |  | 
|  | void CreateEntryInternal(bool have_index, | 
|  | CompletionOnceCallback callback, | 
|  | Entry** out_entry); | 
|  |  | 
|  | void CloseInternal(); | 
|  |  | 
|  | int ReadDataInternal(bool sync_possible, | 
|  | int index, | 
|  | int offset, | 
|  | net::IOBuffer* buf, | 
|  | int buf_len, | 
|  | CompletionOnceCallback callback); | 
|  |  | 
|  | void WriteDataInternal(int index, | 
|  | int offset, | 
|  | net::IOBuffer* buf, | 
|  | int buf_len, | 
|  | CompletionOnceCallback callback, | 
|  | bool truncate); | 
|  |  | 
|  | void ReadSparseDataInternal(int64_t sparse_offset, | 
|  | net::IOBuffer* buf, | 
|  | int buf_len, | 
|  | CompletionOnceCallback callback); | 
|  |  | 
|  | void WriteSparseDataInternal(int64_t sparse_offset, | 
|  | net::IOBuffer* buf, | 
|  | int buf_len, | 
|  | CompletionOnceCallback callback); | 
|  |  | 
|  | void GetAvailableRangeInternal(int64_t sparse_offset, | 
|  | int len, | 
|  | int64_t* out_start, | 
|  | CompletionOnceCallback callback); | 
|  |  | 
|  | void DoomEntryInternal(CompletionOnceCallback callback); | 
|  |  | 
|  | // Called after a SimpleSynchronousEntry has completed CreateEntry() or | 
|  | // OpenEntry(). If |in_sync_entry| is non-NULL, creation is successful and we | 
|  | // can return |this| SimpleEntryImpl to |*out_entry|. Runs | 
|  | // |completion_callback|. | 
|  | void CreationOperationComplete( | 
|  | CompletionOnceCallback completion_callback, | 
|  | const base::TimeTicks& start_time, | 
|  | std::unique_ptr<SimpleEntryCreationResults> in_results, | 
|  | Entry** out_entry, | 
|  | net::NetLogEventType end_event_type); | 
|  |  | 
|  | // Called after we've closed and written the EOF record to our entry. Until | 
|  | // this point it hasn't been safe to OpenEntry() the same entry, but from this | 
|  | // point it is. | 
|  | void CloseOperationComplete(); | 
|  |  | 
|  | // Internal utility method used by other completion methods. Calls | 
|  | // |completion_callback| after updating state and dooming on errors. | 
|  | void EntryOperationComplete(CompletionOnceCallback completion_callback, | 
|  | const SimpleEntryStat& entry_stat, | 
|  | int result); | 
|  |  | 
|  | // Called after an asynchronous read. Updates |crc32s_| if possible. | 
|  | void ReadOperationComplete( | 
|  | int stream_index, | 
|  | int offset, | 
|  | CompletionOnceCallback completion_callback, | 
|  | std::unique_ptr<SimpleEntryStat> entry_stat, | 
|  | std::unique_ptr<SimpleSynchronousEntry::ReadResult> read_result); | 
|  |  | 
|  | // Called after an asynchronous write completes. | 
|  | // |buf| parameter brings back a reference to net::IOBuffer to the original | 
|  | // thread, so that we can reduce cross thread malloc/free pair. | 
|  | // See http://crbug.com/708644 for details. | 
|  | void WriteOperationComplete( | 
|  | int stream_index, | 
|  | CompletionOnceCallback completion_callback, | 
|  | std::unique_ptr<SimpleEntryStat> entry_stat, | 
|  | std::unique_ptr<SimpleSynchronousEntry::WriteResult> result, | 
|  | net::IOBuffer* buf); | 
|  |  | 
|  | void ReadSparseOperationComplete(CompletionOnceCallback completion_callback, | 
|  | std::unique_ptr<base::Time> last_used, | 
|  | std::unique_ptr<int> result); | 
|  |  | 
|  | void WriteSparseOperationComplete(CompletionOnceCallback completion_callback, | 
|  | std::unique_ptr<SimpleEntryStat> entry_stat, | 
|  | std::unique_ptr<int> result); | 
|  |  | 
|  | void GetAvailableRangeOperationComplete( | 
|  | CompletionOnceCallback completion_callback, | 
|  | std::unique_ptr<int> result); | 
|  |  | 
|  | // Called after an asynchronous doom completes. | 
|  | void DoomOperationComplete(CompletionOnceCallback callback, | 
|  | State state_to_restore, | 
|  | int result); | 
|  |  | 
|  | void RecordReadResultConsideringChecksum( | 
|  | const std::unique_ptr<SimpleSynchronousEntry::ReadResult>& read_result) | 
|  | const; | 
|  |  | 
|  | // Called after completion of an operation, to either incoproprate file info | 
|  | // received from I/O done on the worker pool, or to simply bump the | 
|  | // timestamps. Updates the metadata both in |this| and in the index. | 
|  | // Stream size information in particular may be important for following | 
|  | // operations. | 
|  | void UpdateDataFromEntryStat(const SimpleEntryStat& entry_stat); | 
|  |  | 
|  | int64_t GetDiskUsage() const; | 
|  |  | 
|  | // Completes a read from the stream data kept in memory, logging metrics | 
|  | // and updating metadata. Returns the # of bytes read successfully. | 
|  | // This asumes the caller has already range-checked offset and buf_len | 
|  | // appropriately. | 
|  | int ReadFromBuffer(net::GrowableIOBuffer* in_buf, | 
|  | int offset, | 
|  | int buf_len, | 
|  | net::IOBuffer* out_buf); | 
|  |  | 
|  | // Copies data from |buf| to the internal in-memory buffer for stream 0. If | 
|  | // |truncate| is set to true, the target buffer will be truncated at |offset| | 
|  | // + |buf_len| before being written. | 
|  | int SetStream0Data(net::IOBuffer* buf, | 
|  | int offset, int buf_len, | 
|  | bool truncate); | 
|  |  | 
|  | // We want all async I/O on entries to complete before recycling the dir. | 
|  | scoped_refptr<BackendCleanupTracker> cleanup_tracker_; | 
|  |  | 
|  | std::unique_ptr<ActiveEntryProxy> active_entry_proxy_; | 
|  |  | 
|  | // All nonstatic SimpleEntryImpl methods should always be called on the IO | 
|  | // thread, in all cases. |io_thread_checker_| documents and enforces this. | 
|  | base::ThreadChecker io_thread_checker_; | 
|  |  | 
|  | const base::WeakPtr<SimpleBackendImpl> backend_; | 
|  | SimpleFileTracker* const file_tracker_; | 
|  | const net::CacheType cache_type_; | 
|  | const base::FilePath path_; | 
|  | const uint64_t entry_hash_; | 
|  | const bool use_optimistic_operations_; | 
|  | bool is_initial_stream1_read_;  // used for metrics only. | 
|  | std::string key_; | 
|  |  | 
|  | // |last_used_|, |last_modified_| and |data_size_| are copied from the | 
|  | // synchronous entry at the completion of each item of asynchronous IO. | 
|  | // TODO(clamy): Unify last_used_ with data in the index. | 
|  | base::Time last_used_; | 
|  | base::Time last_modified_; | 
|  | int32_t data_size_[kSimpleEntryStreamCount]; | 
|  | int32_t sparse_data_size_; | 
|  |  | 
|  | // Number of times this object has been returned from Backend::OpenEntry() and | 
|  | // Backend::CreateEntry() without subsequent Entry::Close() calls. Used to | 
|  | // notify the backend when this entry not used by any callers. | 
|  | int open_count_; | 
|  |  | 
|  | DoomState doom_state_; | 
|  |  | 
|  | enum { | 
|  | CREATE_NORMAL, | 
|  | CREATE_OPTIMISTIC_PENDING_DOOM, | 
|  | CREATE_OPTIMISTIC_PENDING_DOOM_FOLLOWED_BY_DOOM, | 
|  | } optimistic_create_pending_doom_state_; | 
|  |  | 
|  | State state_; | 
|  |  | 
|  | // When possible, we compute a crc32, for the data in each entry as we read or | 
|  | // write. For each stream, |crc32s_[index]| is the crc32 of that stream from | 
|  | // [0 .. |crc32s_end_offset_|). If |crc32s_end_offset_[index] == 0| then the | 
|  | // value of |crc32s_[index]| is undefined. | 
|  | // Note at this can only be done in the current implementation in the case of | 
|  | // a single entry reader that reads serially through the entire file. | 
|  | // Extending this to multiple readers is possible, but isn't currently worth | 
|  | // it; see http://crbug.com/488076#c3 for details. | 
|  | int32_t crc32s_end_offset_[kSimpleEntryStreamCount]; | 
|  | uint32_t crc32s_[kSimpleEntryStreamCount]; | 
|  |  | 
|  | // If |have_written_[index]| is true, we have written to the file that | 
|  | // contains stream |index|. | 
|  | bool have_written_[kSimpleEntryStreamCount]; | 
|  |  | 
|  | // Reflects how much CRC checking has been done with the entry. This state is | 
|  | // reported on closing each entry stream. | 
|  | CheckCrcResult crc_check_state_[kSimpleEntryStreamCount]; | 
|  |  | 
|  | // The |synchronous_entry_| is the worker thread object that performs IO on | 
|  | // entries. It's owned by this SimpleEntryImpl whenever |executing_operation_| | 
|  | // is false (i.e. when an operation is not pending on the worker pool). When | 
|  | // an operation is being executed no one owns the synchronous entry. Therefore | 
|  | // SimpleEntryImpl should not be deleted while an operation is running as that | 
|  | // would leak the SimpleSynchronousEntry. | 
|  | SimpleSynchronousEntry* synchronous_entry_; | 
|  |  | 
|  | scoped_refptr<net::PrioritizedTaskRunner> prioritized_task_runner_; | 
|  |  | 
|  | base::queue<SimpleEntryOperation> pending_operations_; | 
|  |  | 
|  | net::NetLogWithSource net_log_; | 
|  |  | 
|  | // Unlike other streams, stream 0 data is read from the disk when the entry is | 
|  | // opened, and then kept in memory. All read/write operations on stream 0 | 
|  | // affect the |stream_0_data_| buffer. When the entry is closed, | 
|  | // |stream_0_data_| is written to the disk. | 
|  | // Stream 0 is kept in memory because it is stored in the same file as stream | 
|  | // 1 on disk, to reduce the number of file descriptors and save disk space. | 
|  | // This strategy allows stream 1 to change size easily. Since stream 0 is only | 
|  | // used to write HTTP headers, the memory consumption of keeping it in memory | 
|  | // is acceptable. | 
|  | scoped_refptr<net::GrowableIOBuffer> stream_0_data_; | 
|  |  | 
|  | // Sometimes stream 1 data is prefetched when stream 0 is first read. | 
|  | // If a write to the stream occurs on the entry the prefetch buffer is | 
|  | // discarded. It may also be null if it wasn't prefetched in the first place. | 
|  | scoped_refptr<net::GrowableIOBuffer> stream_1_prefetch_data_; | 
|  |  | 
|  | // Choosing uint32_t over uint64_t for space savings. Pages have in the | 
|  | // hundres to possibly thousands of resources. Wrapping every 4 billion | 
|  | // shouldn't cause inverted priorities very often. | 
|  | uint32_t entry_priority_ = 0; | 
|  | }; | 
|  |  | 
|  | }  // namespace disk_cache | 
|  |  | 
|  | #endif  // NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_IMPL_H_ |