| // 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. |
| |
| #include "net/disk_cache/tracing_cache_backend.h" |
| |
| #include "net/base/net_errors.h" |
| |
| namespace disk_cache { |
| |
| // Proxies entry objects created by the real underlying backend. Backend users |
| // will only see the proxy entries. It is necessary for recording the backend |
| // operations since often non-trivial work is invoked directly on entries. |
| class EntryProxy : public Entry, public base::RefCountedThreadSafe<EntryProxy> { |
| public: |
| EntryProxy(Entry *entry, TracingCacheBackend* backend); |
| virtual void Doom() OVERRIDE; |
| virtual void Close() OVERRIDE; |
| virtual std::string GetKey() const OVERRIDE; |
| virtual base::Time GetLastUsed() const OVERRIDE; |
| virtual base::Time GetLastModified() const OVERRIDE; |
| virtual int32 GetDataSize(int index) const OVERRIDE; |
| virtual int ReadData(int index, int offset, IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback) OVERRIDE; |
| virtual int WriteData(int index, int offset, IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback, |
| bool truncate) OVERRIDE; |
| virtual int ReadSparseData(int64 offset, IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback) OVERRIDE; |
| virtual int WriteSparseData(int64 offset, IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback) OVERRIDE; |
| virtual int GetAvailableRange(int64 offset, int len, int64* start, |
| const CompletionCallback& callback) OVERRIDE; |
| virtual bool CouldBeSparse() const OVERRIDE; |
| virtual void CancelSparseIO() OVERRIDE; |
| virtual int ReadyForSparseIO(const CompletionCallback& callback) OVERRIDE; |
| |
| private: |
| friend class base::RefCountedThreadSafe<EntryProxy>; |
| typedef TracingCacheBackend::Operation Operation; |
| virtual ~EntryProxy(); |
| |
| struct RwOpExtra { |
| int index; |
| int offset; |
| int buf_len; |
| bool truncate; |
| }; |
| |
| void RecordEvent(base::TimeTicks start_time, Operation op, RwOpExtra extra, |
| int result_to_record); |
| void EntryOpComplete(base::TimeTicks start_time, Operation op, |
| RwOpExtra extra, const CompletionCallback& cb, |
| int result); |
| Entry* entry_; |
| base::WeakPtr<TracingCacheBackend> backend_; |
| |
| DISALLOW_COPY_AND_ASSIGN(EntryProxy); |
| }; |
| |
| EntryProxy::EntryProxy(Entry *entry, TracingCacheBackend* backend) |
| : entry_(entry), |
| backend_(backend->AsWeakPtr()) { |
| } |
| |
| void EntryProxy::Doom() { |
| // TODO(pasko): Record the event. |
| entry_->Doom(); |
| } |
| |
| void EntryProxy::Close() { |
| // TODO(pasko): Record the event. |
| entry_->Close(); |
| Release(); |
| } |
| |
| std::string EntryProxy::GetKey() const { |
| return entry_->GetKey(); |
| } |
| |
| base::Time EntryProxy::GetLastUsed() const { |
| return entry_->GetLastUsed(); |
| } |
| |
| base::Time EntryProxy::GetLastModified() const { |
| return entry_->GetLastModified(); |
| } |
| |
| int32 EntryProxy::GetDataSize(int index) const { |
| return entry_->GetDataSize(index); |
| } |
| |
| int EntryProxy::ReadData(int index, int offset, IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback) { |
| base::TimeTicks start_time = base::TimeTicks::Now(); |
| RwOpExtra extra; |
| extra.index = index; |
| extra.offset = offset; |
| extra.buf_len = buf_len; |
| extra.truncate = false; |
| int rv = entry_->ReadData( |
| index, offset, buf, buf_len, |
| base::Bind(&EntryProxy::EntryOpComplete, this, start_time, |
| TracingCacheBackend::OP_READ, extra, callback)); |
| if (rv != net::ERR_IO_PENDING) { |
| RecordEvent(start_time, TracingCacheBackend::OP_READ, extra, rv); |
| } |
| return rv; |
| } |
| |
| int EntryProxy::WriteData(int index, int offset, IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback, |
| bool truncate) { |
| base::TimeTicks start_time = base::TimeTicks::Now(); |
| RwOpExtra extra; |
| extra.index = index; |
| extra.offset = offset; |
| extra.buf_len = buf_len; |
| extra.truncate = truncate; |
| int rv = entry_->WriteData(index, offset, buf, buf_len, |
| base::Bind(&EntryProxy::EntryOpComplete, this, start_time, |
| TracingCacheBackend::OP_WRITE, extra, callback), |
| truncate); |
| if (rv != net::ERR_IO_PENDING) { |
| RecordEvent(start_time, TracingCacheBackend::OP_WRITE, extra, rv); |
| } |
| return rv; |
| } |
| |
| int EntryProxy::ReadSparseData(int64 offset, IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback) { |
| // TODO(pasko): Record the event. |
| return entry_->ReadSparseData(offset, buf, buf_len, callback); |
| } |
| |
| int EntryProxy::WriteSparseData(int64 offset, IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback) { |
| // TODO(pasko): Record the event. |
| return entry_->WriteSparseData(offset, buf, buf_len, callback); |
| } |
| |
| int EntryProxy::GetAvailableRange(int64 offset, int len, int64* start, |
| const CompletionCallback& callback) { |
| return entry_->GetAvailableRange(offset, len, start, callback); |
| } |
| |
| bool EntryProxy::CouldBeSparse() const { |
| return entry_->CouldBeSparse(); |
| } |
| |
| void EntryProxy::CancelSparseIO() { |
| return entry_->CancelSparseIO(); |
| } |
| |
| int EntryProxy::ReadyForSparseIO(const CompletionCallback& callback) { |
| return entry_->ReadyForSparseIO(callback); |
| } |
| |
| void EntryProxy::RecordEvent(base::TimeTicks start_time, Operation op, |
| RwOpExtra extra, int result_to_record) { |
| // TODO(pasko): Implement. |
| } |
| |
| void EntryProxy::EntryOpComplete(base::TimeTicks start_time, Operation op, |
| RwOpExtra extra, const CompletionCallback& cb, |
| int result) { |
| RecordEvent(start_time, op, extra, result); |
| if (!cb.is_null()) { |
| cb.Run(result); |
| } |
| } |
| |
| EntryProxy::~EntryProxy() { |
| if (backend_.get()) { |
| backend_->OnDeleteEntry(entry_); |
| } |
| } |
| |
| TracingCacheBackend::TracingCacheBackend(scoped_ptr<Backend> backend) |
| : backend_(backend.Pass()) { |
| } |
| |
| TracingCacheBackend::~TracingCacheBackend() { |
| } |
| |
| net::CacheType TracingCacheBackend::GetCacheType() const { |
| return backend_->GetCacheType(); |
| } |
| |
| int32 TracingCacheBackend::GetEntryCount() const { |
| return backend_->GetEntryCount(); |
| } |
| |
| void TracingCacheBackend::RecordEvent(base::TimeTicks start_time, Operation op, |
| std::string key, Entry* entry, int rv) { |
| // TODO(pasko): Implement. |
| } |
| |
| EntryProxy* TracingCacheBackend::FindOrCreateEntryProxy(Entry* entry) { |
| EntryProxy* entry_proxy; |
| EntryToProxyMap::iterator it = open_entries_.find(entry); |
| if (it != open_entries_.end()) { |
| entry_proxy = it->second; |
| entry_proxy->AddRef(); |
| return entry_proxy; |
| } |
| entry_proxy = new EntryProxy(entry, this); |
| entry_proxy->AddRef(); |
| open_entries_[entry] = entry_proxy; |
| return entry_proxy; |
| } |
| |
| void TracingCacheBackend::OnDeleteEntry(Entry* entry) { |
| EntryToProxyMap::iterator it = open_entries_.find(entry); |
| if (it != open_entries_.end()) { |
| open_entries_.erase(it); |
| } |
| } |
| |
| void TracingCacheBackend::BackendOpComplete(base::TimeTicks start_time, |
| Operation op, |
| std::string key, |
| Entry** entry, |
| const CompletionCallback& callback, |
| int result) { |
| RecordEvent(start_time, op, key, *entry, result); |
| if (*entry) { |
| *entry = FindOrCreateEntryProxy(*entry); |
| } |
| if (!callback.is_null()) { |
| callback.Run(result); |
| } |
| } |
| |
| net::CompletionCallback TracingCacheBackend::BindCompletion( |
| Operation op, base::TimeTicks start_time, const std::string& key, |
| Entry **entry, const net::CompletionCallback& cb) { |
| return base::Bind(&TracingCacheBackend::BackendOpComplete, |
| AsWeakPtr(), start_time, op, key, entry, cb); |
| } |
| |
| int TracingCacheBackend::OpenEntry(const std::string& key, Entry** entry, |
| const CompletionCallback& callback) { |
| DCHECK(*entry == NULL); |
| base::TimeTicks start_time = base::TimeTicks::Now(); |
| int rv = backend_->OpenEntry(key, entry, |
| BindCompletion(OP_OPEN, start_time, key, entry, |
| callback)); |
| if (rv != net::ERR_IO_PENDING) { |
| RecordEvent(start_time, OP_OPEN, key, *entry, rv); |
| if (*entry) { |
| *entry = FindOrCreateEntryProxy(*entry); |
| } |
| } |
| return rv; |
| } |
| |
| int TracingCacheBackend::CreateEntry(const std::string& key, Entry** entry, |
| const CompletionCallback& callback) { |
| base::TimeTicks start_time = base::TimeTicks::Now(); |
| int rv = backend_->CreateEntry(key, entry, |
| BindCompletion(OP_CREATE, start_time, key, |
| entry, callback)); |
| if (rv != net::ERR_IO_PENDING) { |
| RecordEvent(start_time, OP_CREATE, key, *entry, rv); |
| if (*entry) { |
| *entry = FindOrCreateEntryProxy(*entry); |
| } |
| } |
| return rv; |
| } |
| |
| int TracingCacheBackend::DoomEntry(const std::string& key, |
| const CompletionCallback& callback) { |
| base::TimeTicks start_time = base::TimeTicks::Now(); |
| int rv = backend_->DoomEntry(key, BindCompletion(OP_DOOM_ENTRY, |
| start_time, key, NULL, |
| callback)); |
| if (rv != net::ERR_IO_PENDING) { |
| RecordEvent(start_time, OP_DOOM_ENTRY, key, NULL, rv); |
| } |
| return rv; |
| } |
| |
| int TracingCacheBackend::DoomAllEntries(const CompletionCallback& callback) { |
| return backend_->DoomAllEntries(callback); |
| } |
| |
| int TracingCacheBackend::DoomEntriesBetween(base::Time initial_time, |
| base::Time end_time, |
| const CompletionCallback& cb) { |
| return backend_->DoomEntriesBetween(initial_time, end_time, cb); |
| } |
| |
| int TracingCacheBackend::DoomEntriesSince(base::Time initial_time, |
| const CompletionCallback& callback) { |
| return backend_->DoomEntriesSince(initial_time, callback); |
| } |
| |
| int TracingCacheBackend::OpenNextEntry(void** iter, Entry** next_entry, |
| const CompletionCallback& callback) { |
| return backend_->OpenNextEntry(iter, next_entry, callback); |
| } |
| |
| void TracingCacheBackend::EndEnumeration(void** iter) { |
| return backend_->EndEnumeration(iter); |
| } |
| |
| void TracingCacheBackend::GetStats(StatsItems* stats) { |
| return backend_->GetStats(stats); |
| } |
| |
| void TracingCacheBackend::OnExternalCacheHit(const std::string& key) { |
| return backend_->OnExternalCacheHit(key); |
| } |
| |
| } // namespace disk_cache |