// 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