1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/disk_cache/tracing_cache_backend.h"
6
7#include "net/base/net_errors.h"
8
9namespace disk_cache {
10
11// Proxies entry objects created by the real underlying backend. Backend users
12// will only see the proxy entries. It is necessary for recording the backend
13// operations since often non-trivial work is invoked directly on entries.
14class EntryProxy : public Entry, public base::RefCountedThreadSafe<EntryProxy> {
15 public:
16  EntryProxy(Entry *entry, TracingCacheBackend* backend);
17  virtual void Doom() OVERRIDE;
18  virtual void Close() OVERRIDE;
19  virtual std::string GetKey() const OVERRIDE;
20  virtual base::Time GetLastUsed() const OVERRIDE;
21  virtual base::Time GetLastModified() const OVERRIDE;
22  virtual int32 GetDataSize(int index) const OVERRIDE;
23  virtual int ReadData(int index, int offset, IOBuffer* buf, int buf_len,
24                       const CompletionCallback& callback) OVERRIDE;
25  virtual int WriteData(int index, int offset, IOBuffer* buf, int buf_len,
26                        const CompletionCallback& callback,
27                        bool truncate) OVERRIDE;
28  virtual int ReadSparseData(int64 offset, IOBuffer* buf, int buf_len,
29                             const CompletionCallback& callback) OVERRIDE;
30  virtual int WriteSparseData(int64 offset, IOBuffer* buf, int buf_len,
31                              const CompletionCallback& callback) OVERRIDE;
32  virtual int GetAvailableRange(int64 offset, int len, int64* start,
33                                const CompletionCallback& callback) OVERRIDE;
34  virtual bool CouldBeSparse() const OVERRIDE;
35  virtual void CancelSparseIO() OVERRIDE;
36  virtual int ReadyForSparseIO(const CompletionCallback& callback) OVERRIDE;
37
38 private:
39  friend class base::RefCountedThreadSafe<EntryProxy>;
40  typedef TracingCacheBackend::Operation Operation;
41  virtual ~EntryProxy();
42
43  struct RwOpExtra {
44    int index;
45    int offset;
46    int buf_len;
47    bool truncate;
48  };
49
50  void RecordEvent(base::TimeTicks start_time, Operation op, RwOpExtra extra,
51                   int result_to_record);
52  void EntryOpComplete(base::TimeTicks start_time, Operation op,
53                       RwOpExtra extra, const CompletionCallback& cb,
54                       int result);
55  Entry* entry_;
56  base::WeakPtr<TracingCacheBackend> backend_;
57
58  DISALLOW_COPY_AND_ASSIGN(EntryProxy);
59};
60
61EntryProxy::EntryProxy(Entry *entry, TracingCacheBackend* backend)
62  : entry_(entry),
63    backend_(backend->AsWeakPtr()) {
64}
65
66void EntryProxy::Doom() {
67  // TODO(pasko): Record the event.
68  entry_->Doom();
69}
70
71void EntryProxy::Close() {
72  // TODO(pasko): Record the event.
73  entry_->Close();
74  Release();
75}
76
77std::string EntryProxy::GetKey() const {
78  return entry_->GetKey();
79}
80
81base::Time EntryProxy::GetLastUsed() const {
82  return entry_->GetLastUsed();
83}
84
85base::Time EntryProxy::GetLastModified() const {
86  return entry_->GetLastModified();
87}
88
89int32 EntryProxy::GetDataSize(int index) const {
90  return entry_->GetDataSize(index);
91}
92
93int EntryProxy::ReadData(int index, int offset, IOBuffer* buf, int buf_len,
94                         const CompletionCallback& callback) {
95  base::TimeTicks start_time = base::TimeTicks::Now();
96  RwOpExtra extra;
97  extra.index = index;
98  extra.offset = offset;
99  extra.buf_len = buf_len;
100  extra.truncate = false;
101  int rv = entry_->ReadData(
102      index, offset, buf, buf_len,
103      base::Bind(&EntryProxy::EntryOpComplete, this, start_time,
104                 TracingCacheBackend::OP_READ, extra, callback));
105  if (rv != net::ERR_IO_PENDING) {
106    RecordEvent(start_time, TracingCacheBackend::OP_READ, extra, rv);
107  }
108  return rv;
109}
110
111int EntryProxy::WriteData(int index, int offset, IOBuffer* buf, int buf_len,
112                      const CompletionCallback& callback,
113                      bool truncate) {
114  base::TimeTicks start_time = base::TimeTicks::Now();
115  RwOpExtra extra;
116  extra.index = index;
117  extra.offset = offset;
118  extra.buf_len = buf_len;
119  extra.truncate = truncate;
120  int rv = entry_->WriteData(index, offset, buf, buf_len,
121      base::Bind(&EntryProxy::EntryOpComplete, this, start_time,
122                 TracingCacheBackend::OP_WRITE, extra, callback),
123      truncate);
124  if (rv != net::ERR_IO_PENDING) {
125    RecordEvent(start_time, TracingCacheBackend::OP_WRITE, extra, rv);
126  }
127  return rv;
128}
129
130int EntryProxy::ReadSparseData(int64 offset, IOBuffer* buf, int buf_len,
131                           const CompletionCallback& callback) {
132  // TODO(pasko): Record the event.
133  return entry_->ReadSparseData(offset, buf, buf_len, callback);
134}
135
136int EntryProxy::WriteSparseData(int64 offset, IOBuffer* buf, int buf_len,
137                            const CompletionCallback& callback) {
138  // TODO(pasko): Record the event.
139  return entry_->WriteSparseData(offset, buf, buf_len, callback);
140}
141
142int EntryProxy::GetAvailableRange(int64 offset, int len, int64* start,
143                              const CompletionCallback& callback) {
144  return entry_->GetAvailableRange(offset, len, start, callback);
145}
146
147bool EntryProxy::CouldBeSparse() const {
148  return entry_->CouldBeSparse();
149}
150
151void EntryProxy::CancelSparseIO() {
152  return entry_->CancelSparseIO();
153}
154
155int EntryProxy::ReadyForSparseIO(const CompletionCallback& callback) {
156  return entry_->ReadyForSparseIO(callback);
157}
158
159void EntryProxy::RecordEvent(base::TimeTicks start_time, Operation op,
160                             RwOpExtra extra, int result_to_record) {
161  // TODO(pasko): Implement.
162}
163
164void EntryProxy::EntryOpComplete(base::TimeTicks start_time, Operation op,
165                                 RwOpExtra extra, const CompletionCallback& cb,
166                                 int result) {
167  RecordEvent(start_time, op, extra, result);
168  if (!cb.is_null()) {
169    cb.Run(result);
170  }
171}
172
173EntryProxy::~EntryProxy() {
174  if (backend_.get()) {
175    backend_->OnDeleteEntry(entry_);
176  }
177}
178
179TracingCacheBackend::TracingCacheBackend(scoped_ptr<Backend> backend)
180  : backend_(backend.Pass()) {
181}
182
183TracingCacheBackend::~TracingCacheBackend() {
184}
185
186net::CacheType TracingCacheBackend::GetCacheType() const {
187  return backend_->GetCacheType();
188}
189
190int32 TracingCacheBackend::GetEntryCount() const {
191  return backend_->GetEntryCount();
192}
193
194void TracingCacheBackend::RecordEvent(base::TimeTicks start_time, Operation op,
195                                      std::string key, Entry* entry, int rv) {
196  // TODO(pasko): Implement.
197}
198
199EntryProxy* TracingCacheBackend::FindOrCreateEntryProxy(Entry* entry) {
200  EntryProxy* entry_proxy;
201  EntryToProxyMap::iterator it = open_entries_.find(entry);
202  if (it != open_entries_.end()) {
203    entry_proxy = it->second;
204    entry_proxy->AddRef();
205    return entry_proxy;
206  }
207  entry_proxy = new EntryProxy(entry, this);
208  entry_proxy->AddRef();
209  open_entries_[entry] = entry_proxy;
210  return entry_proxy;
211}
212
213void TracingCacheBackend::OnDeleteEntry(Entry* entry) {
214  EntryToProxyMap::iterator it = open_entries_.find(entry);
215  if (it != open_entries_.end()) {
216    open_entries_.erase(it);
217  }
218}
219
220void TracingCacheBackend::BackendOpComplete(base::TimeTicks start_time,
221                                            Operation op,
222                                            std::string key,
223                                            Entry** entry,
224                                            const CompletionCallback& callback,
225                                            int result) {
226  RecordEvent(start_time, op, key, *entry, result);
227  if (*entry) {
228    *entry = FindOrCreateEntryProxy(*entry);
229  }
230  if (!callback.is_null()) {
231    callback.Run(result);
232  }
233}
234
235net::CompletionCallback TracingCacheBackend::BindCompletion(
236    Operation op, base::TimeTicks start_time, const std::string& key,
237    Entry **entry, const net::CompletionCallback& cb) {
238  return base::Bind(&TracingCacheBackend::BackendOpComplete,
239                    AsWeakPtr(), start_time, op, key, entry, cb);
240}
241
242int TracingCacheBackend::OpenEntry(const std::string& key, Entry** entry,
243                                   const CompletionCallback& callback) {
244  DCHECK(*entry == NULL);
245  base::TimeTicks start_time = base::TimeTicks::Now();
246  int rv = backend_->OpenEntry(key, entry,
247                               BindCompletion(OP_OPEN, start_time, key, entry,
248                                              callback));
249  if (rv != net::ERR_IO_PENDING) {
250    RecordEvent(start_time, OP_OPEN, key, *entry, rv);
251    if (*entry) {
252      *entry = FindOrCreateEntryProxy(*entry);
253    }
254  }
255  return rv;
256}
257
258int TracingCacheBackend::CreateEntry(const std::string& key, Entry** entry,
259                                     const CompletionCallback& callback) {
260  base::TimeTicks start_time = base::TimeTicks::Now();
261  int rv = backend_->CreateEntry(key, entry,
262                                 BindCompletion(OP_CREATE, start_time, key,
263                                                entry, callback));
264  if (rv != net::ERR_IO_PENDING) {
265    RecordEvent(start_time, OP_CREATE, key, *entry, rv);
266    if (*entry) {
267      *entry = FindOrCreateEntryProxy(*entry);
268    }
269  }
270  return rv;
271}
272
273int TracingCacheBackend::DoomEntry(const std::string& key,
274                                   const CompletionCallback& callback) {
275  base::TimeTicks start_time = base::TimeTicks::Now();
276  int rv = backend_->DoomEntry(key, BindCompletion(OP_DOOM_ENTRY,
277                                                   start_time, key, NULL,
278                                                   callback));
279  if (rv != net::ERR_IO_PENDING) {
280    RecordEvent(start_time, OP_DOOM_ENTRY, key, NULL, rv);
281  }
282  return rv;
283}
284
285int TracingCacheBackend::DoomAllEntries(const CompletionCallback& callback) {
286  return backend_->DoomAllEntries(callback);
287}
288
289int TracingCacheBackend::DoomEntriesBetween(base::Time initial_time,
290                                            base::Time end_time,
291                                            const CompletionCallback& cb) {
292  return backend_->DoomEntriesBetween(initial_time, end_time, cb);
293}
294
295int TracingCacheBackend::DoomEntriesSince(base::Time initial_time,
296                                          const CompletionCallback& callback) {
297  return backend_->DoomEntriesSince(initial_time, callback);
298}
299
300int TracingCacheBackend::OpenNextEntry(void** iter, Entry** next_entry,
301                                       const CompletionCallback& callback) {
302  return backend_->OpenNextEntry(iter, next_entry, callback);
303}
304
305void TracingCacheBackend::EndEnumeration(void** iter) {
306  return backend_->EndEnumeration(iter);
307}
308
309void TracingCacheBackend::GetStats(StatsItems* stats) {
310  return backend_->GetStats(stats);
311}
312
313void TracingCacheBackend::OnExternalCacheHit(const std::string& key) {
314  return backend_->OnExternalCacheHit(key);
315}
316
317}  // namespace disk_cache
318