1// Copyright (c) 2012 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/blockfile/in_flight_backend_io.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/compiler_specific.h"
10#include "base/logging.h"
11#include "base/single_thread_task_runner.h"
12#include "net/base/net_errors.h"
13#include "net/disk_cache/blockfile/backend_impl.h"
14#include "net/disk_cache/blockfile/entry_impl.h"
15#include "net/disk_cache/blockfile/histogram_macros.h"
16
17// Provide a BackendImpl object to macros from histogram_macros.h.
18#define CACHE_UMA_BACKEND_IMPL_OBJ backend_
19
20namespace disk_cache {
21
22BackendIO::BackendIO(InFlightIO* controller, BackendImpl* backend,
23                     const net::CompletionCallback& callback)
24    : BackgroundIO(controller),
25      backend_(backend),
26      callback_(callback),
27      operation_(OP_NONE),
28      entry_ptr_(NULL),
29      iterator_(NULL),
30      entry_(NULL),
31      index_(0),
32      offset_(0),
33      buf_len_(0),
34      truncate_(false),
35      offset64_(0),
36      start_(NULL) {
37  start_time_ = base::TimeTicks::Now();
38}
39
40// Runs on the background thread.
41void BackendIO::ExecuteOperation() {
42  if (IsEntryOperation())
43    return ExecuteEntryOperation();
44
45  ExecuteBackendOperation();
46}
47
48// Runs on the background thread.
49void BackendIO::OnIOComplete(int result) {
50  DCHECK(IsEntryOperation());
51  DCHECK_NE(result, net::ERR_IO_PENDING);
52  result_ = result;
53  NotifyController();
54}
55
56// Runs on the primary thread.
57void BackendIO::OnDone(bool cancel) {
58  if (IsEntryOperation()) {
59    CACHE_UMA(TIMES, "TotalIOTime", 0, ElapsedTime());
60  }
61
62  if (!ReturnsEntry())
63    return;
64
65  if (result() == net::OK) {
66    static_cast<EntryImpl*>(*entry_ptr_)->OnEntryCreated(backend_);
67    if (cancel)
68      (*entry_ptr_)->Close();
69  }
70}
71
72bool BackendIO::IsEntryOperation() {
73  return operation_ > OP_MAX_BACKEND;
74}
75
76// Runs on the background thread.
77void BackendIO::ReferenceEntry() {
78  entry_->AddRef();
79}
80
81void BackendIO::Init() {
82  operation_ = OP_INIT;
83}
84
85void BackendIO::OpenEntry(const std::string& key, Entry** entry) {
86  operation_ = OP_OPEN;
87  key_ = key;
88  entry_ptr_ = entry;
89}
90
91void BackendIO::CreateEntry(const std::string& key, Entry** entry) {
92  operation_ = OP_CREATE;
93  key_ = key;
94  entry_ptr_ = entry;
95}
96
97void BackendIO::DoomEntry(const std::string& key) {
98  operation_ = OP_DOOM;
99  key_ = key;
100}
101
102void BackendIO::DoomAllEntries() {
103  operation_ = OP_DOOM_ALL;
104}
105
106void BackendIO::DoomEntriesBetween(const base::Time initial_time,
107                                   const base::Time end_time) {
108  operation_ = OP_DOOM_BETWEEN;
109  initial_time_ = initial_time;
110  end_time_ = end_time;
111}
112
113void BackendIO::DoomEntriesSince(const base::Time initial_time) {
114  operation_ = OP_DOOM_SINCE;
115  initial_time_ = initial_time;
116}
117
118void BackendIO::OpenNextEntry(Rankings::Iterator* iterator,
119                              Entry** next_entry) {
120  operation_ = OP_OPEN_NEXT;
121  iterator_ = iterator;
122  entry_ptr_ = next_entry;
123}
124
125void BackendIO::EndEnumeration(scoped_ptr<Rankings::Iterator> iterator) {
126  operation_ = OP_END_ENUMERATION;
127  scoped_iterator_ = iterator.Pass();
128}
129
130void BackendIO::OnExternalCacheHit(const std::string& key) {
131  operation_ = OP_ON_EXTERNAL_CACHE_HIT;
132  key_ = key;
133}
134
135void BackendIO::CloseEntryImpl(EntryImpl* entry) {
136  operation_ = OP_CLOSE_ENTRY;
137  entry_ = entry;
138}
139
140void BackendIO::DoomEntryImpl(EntryImpl* entry) {
141  operation_ = OP_DOOM_ENTRY;
142  entry_ = entry;
143}
144
145void BackendIO::FlushQueue() {
146  operation_ = OP_FLUSH_QUEUE;
147}
148
149void BackendIO::RunTask(const base::Closure& task) {
150  operation_ = OP_RUN_TASK;
151  task_ = task;
152}
153
154void BackendIO::ReadData(EntryImpl* entry, int index, int offset,
155                         net::IOBuffer* buf, int buf_len) {
156  operation_ = OP_READ;
157  entry_ = entry;
158  index_ = index;
159  offset_ = offset;
160  buf_ = buf;
161  buf_len_ = buf_len;
162}
163
164void BackendIO::WriteData(EntryImpl* entry, int index, int offset,
165                          net::IOBuffer* buf, int buf_len, bool truncate) {
166  operation_ = OP_WRITE;
167  entry_ = entry;
168  index_ = index;
169  offset_ = offset;
170  buf_ = buf;
171  buf_len_ = buf_len;
172  truncate_ = truncate;
173}
174
175void BackendIO::ReadSparseData(EntryImpl* entry, int64 offset,
176                               net::IOBuffer* buf, int buf_len) {
177  operation_ = OP_READ_SPARSE;
178  entry_ = entry;
179  offset64_ = offset;
180  buf_ = buf;
181  buf_len_ = buf_len;
182}
183
184void BackendIO::WriteSparseData(EntryImpl* entry, int64 offset,
185                                net::IOBuffer* buf, int buf_len) {
186  operation_ = OP_WRITE_SPARSE;
187  entry_ = entry;
188  offset64_ = offset;
189  buf_ = buf;
190  buf_len_ = buf_len;
191}
192
193void BackendIO::GetAvailableRange(EntryImpl* entry, int64 offset, int len,
194                                  int64* start) {
195  operation_ = OP_GET_RANGE;
196  entry_ = entry;
197  offset64_ = offset;
198  buf_len_ = len;
199  start_ = start;
200}
201
202void BackendIO::CancelSparseIO(EntryImpl* entry) {
203  operation_ = OP_CANCEL_IO;
204  entry_ = entry;
205}
206
207void BackendIO::ReadyForSparseIO(EntryImpl* entry) {
208  operation_ = OP_IS_READY;
209  entry_ = entry;
210}
211
212BackendIO::~BackendIO() {}
213
214bool BackendIO::ReturnsEntry() {
215  return operation_ == OP_OPEN || operation_ == OP_CREATE ||
216      operation_ == OP_OPEN_NEXT;
217}
218
219base::TimeDelta BackendIO::ElapsedTime() const {
220  return base::TimeTicks::Now() - start_time_;
221}
222
223// Runs on the background thread.
224void BackendIO::ExecuteBackendOperation() {
225  switch (operation_) {
226    case OP_INIT:
227      result_ = backend_->SyncInit();
228      break;
229    case OP_OPEN:
230      result_ = backend_->SyncOpenEntry(key_, entry_ptr_);
231      break;
232    case OP_CREATE:
233      result_ = backend_->SyncCreateEntry(key_, entry_ptr_);
234      break;
235    case OP_DOOM:
236      result_ = backend_->SyncDoomEntry(key_);
237      break;
238    case OP_DOOM_ALL:
239      result_ = backend_->SyncDoomAllEntries();
240      break;
241    case OP_DOOM_BETWEEN:
242      result_ = backend_->SyncDoomEntriesBetween(initial_time_, end_time_);
243      break;
244    case OP_DOOM_SINCE:
245      result_ = backend_->SyncDoomEntriesSince(initial_time_);
246      break;
247    case OP_OPEN_NEXT:
248      result_ = backend_->SyncOpenNextEntry(iterator_, entry_ptr_);
249      break;
250    case OP_END_ENUMERATION:
251      backend_->SyncEndEnumeration(scoped_iterator_.Pass());
252      result_ = net::OK;
253      break;
254    case OP_ON_EXTERNAL_CACHE_HIT:
255      backend_->SyncOnExternalCacheHit(key_);
256      result_ = net::OK;
257      break;
258    case OP_CLOSE_ENTRY:
259      entry_->Release();
260      result_ = net::OK;
261      break;
262    case OP_DOOM_ENTRY:
263      entry_->DoomImpl();
264      result_ = net::OK;
265      break;
266    case OP_FLUSH_QUEUE:
267      result_ = net::OK;
268      break;
269    case OP_RUN_TASK:
270      task_.Run();
271      result_ = net::OK;
272      break;
273    default:
274      NOTREACHED() << "Invalid Operation";
275      result_ = net::ERR_UNEXPECTED;
276  }
277  DCHECK_NE(net::ERR_IO_PENDING, result_);
278  NotifyController();
279}
280
281// Runs on the background thread.
282void BackendIO::ExecuteEntryOperation() {
283  switch (operation_) {
284    case OP_READ:
285      result_ =
286          entry_->ReadDataImpl(index_, offset_, buf_.get(), buf_len_,
287                               base::Bind(&BackendIO::OnIOComplete, this));
288      break;
289    case OP_WRITE:
290      result_ =
291          entry_->WriteDataImpl(index_, offset_, buf_.get(), buf_len_,
292                                base::Bind(&BackendIO::OnIOComplete, this),
293                                truncate_);
294      break;
295    case OP_READ_SPARSE:
296      result_ = entry_->ReadSparseDataImpl(
297                    offset64_, buf_.get(), buf_len_,
298                    base::Bind(&BackendIO::OnIOComplete, this));
299      break;
300    case OP_WRITE_SPARSE:
301      result_ = entry_->WriteSparseDataImpl(
302                    offset64_, buf_.get(), buf_len_,
303                    base::Bind(&BackendIO::OnIOComplete, this));
304      break;
305    case OP_GET_RANGE:
306      result_ = entry_->GetAvailableRangeImpl(offset64_, buf_len_, start_);
307      break;
308    case OP_CANCEL_IO:
309      entry_->CancelSparseIOImpl();
310      result_ = net::OK;
311      break;
312    case OP_IS_READY:
313      result_ = entry_->ReadyForSparseIOImpl(
314                    base::Bind(&BackendIO::OnIOComplete, this));
315      break;
316    default:
317      NOTREACHED() << "Invalid Operation";
318      result_ = net::ERR_UNEXPECTED;
319  }
320  buf_ = NULL;
321  if (result_ != net::ERR_IO_PENDING)
322    NotifyController();
323}
324
325InFlightBackendIO::InFlightBackendIO(
326    BackendImpl* backend,
327    const scoped_refptr<base::SingleThreadTaskRunner>& background_thread)
328    : backend_(backend),
329      background_thread_(background_thread),
330      ptr_factory_(this) {
331}
332
333InFlightBackendIO::~InFlightBackendIO() {
334}
335
336void InFlightBackendIO::Init(const net::CompletionCallback& callback) {
337  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
338  operation->Init();
339  PostOperation(operation.get());
340}
341
342void InFlightBackendIO::OpenEntry(const std::string& key, Entry** entry,
343                                  const net::CompletionCallback& callback) {
344  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
345  operation->OpenEntry(key, entry);
346  PostOperation(operation.get());
347}
348
349void InFlightBackendIO::CreateEntry(const std::string& key, Entry** entry,
350                                    const net::CompletionCallback& callback) {
351  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
352  operation->CreateEntry(key, entry);
353  PostOperation(operation.get());
354}
355
356void InFlightBackendIO::DoomEntry(const std::string& key,
357                                  const net::CompletionCallback& callback) {
358  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
359  operation->DoomEntry(key);
360  PostOperation(operation.get());
361}
362
363void InFlightBackendIO::DoomAllEntries(
364    const net::CompletionCallback& callback) {
365  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
366  operation->DoomAllEntries();
367  PostOperation(operation.get());
368}
369
370void InFlightBackendIO::DoomEntriesBetween(const base::Time initial_time,
371                        const base::Time end_time,
372                        const net::CompletionCallback& callback) {
373  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
374  operation->DoomEntriesBetween(initial_time, end_time);
375  PostOperation(operation.get());
376}
377
378void InFlightBackendIO::DoomEntriesSince(
379    const base::Time initial_time, const net::CompletionCallback& callback) {
380  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
381  operation->DoomEntriesSince(initial_time);
382  PostOperation(operation.get());
383}
384
385void InFlightBackendIO::OpenNextEntry(Rankings::Iterator* iterator,
386                                      Entry** next_entry,
387                                      const net::CompletionCallback& callback) {
388  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
389  operation->OpenNextEntry(iterator, next_entry);
390  PostOperation(operation.get());
391}
392
393void InFlightBackendIO::EndEnumeration(
394    scoped_ptr<Rankings::Iterator> iterator) {
395  scoped_refptr<BackendIO> operation(
396      new BackendIO(this, backend_, net::CompletionCallback()));
397  operation->EndEnumeration(iterator.Pass());
398  PostOperation(operation.get());
399}
400
401void InFlightBackendIO::OnExternalCacheHit(const std::string& key) {
402  scoped_refptr<BackendIO> operation(
403      new BackendIO(this, backend_, net::CompletionCallback()));
404  operation->OnExternalCacheHit(key);
405  PostOperation(operation.get());
406}
407
408void InFlightBackendIO::CloseEntryImpl(EntryImpl* entry) {
409  scoped_refptr<BackendIO> operation(
410      new BackendIO(this, backend_, net::CompletionCallback()));
411  operation->CloseEntryImpl(entry);
412  PostOperation(operation.get());
413}
414
415void InFlightBackendIO::DoomEntryImpl(EntryImpl* entry) {
416  scoped_refptr<BackendIO> operation(
417      new BackendIO(this, backend_, net::CompletionCallback()));
418  operation->DoomEntryImpl(entry);
419  PostOperation(operation.get());
420}
421
422void InFlightBackendIO::FlushQueue(const net::CompletionCallback& callback) {
423  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
424  operation->FlushQueue();
425  PostOperation(operation.get());
426}
427
428void InFlightBackendIO::RunTask(
429    const base::Closure& task, const net::CompletionCallback& callback) {
430  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
431  operation->RunTask(task);
432  PostOperation(operation.get());
433}
434
435void InFlightBackendIO::ReadData(EntryImpl* entry, int index, int offset,
436                                 net::IOBuffer* buf, int buf_len,
437                                 const net::CompletionCallback& callback) {
438  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
439  operation->ReadData(entry, index, offset, buf, buf_len);
440  PostOperation(operation.get());
441}
442
443void InFlightBackendIO::WriteData(EntryImpl* entry, int index, int offset,
444                                  net::IOBuffer* buf, int buf_len,
445                                  bool truncate,
446                                  const net::CompletionCallback& callback) {
447  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
448  operation->WriteData(entry, index, offset, buf, buf_len, truncate);
449  PostOperation(operation.get());
450}
451
452void InFlightBackendIO::ReadSparseData(
453    EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len,
454    const net::CompletionCallback& callback) {
455  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
456  operation->ReadSparseData(entry, offset, buf, buf_len);
457  PostOperation(operation.get());
458}
459
460void InFlightBackendIO::WriteSparseData(
461    EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len,
462    const net::CompletionCallback& callback) {
463  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
464  operation->WriteSparseData(entry, offset, buf, buf_len);
465  PostOperation(operation.get());
466}
467
468void InFlightBackendIO::GetAvailableRange(
469    EntryImpl* entry, int64 offset, int len, int64* start,
470    const net::CompletionCallback& callback) {
471  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
472  operation->GetAvailableRange(entry, offset, len, start);
473  PostOperation(operation.get());
474}
475
476void InFlightBackendIO::CancelSparseIO(EntryImpl* entry) {
477  scoped_refptr<BackendIO> operation(
478      new BackendIO(this, backend_, net::CompletionCallback()));
479  operation->CancelSparseIO(entry);
480  PostOperation(operation.get());
481}
482
483void InFlightBackendIO::ReadyForSparseIO(
484    EntryImpl* entry, const net::CompletionCallback& callback) {
485  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
486  operation->ReadyForSparseIO(entry);
487  PostOperation(operation.get());
488}
489
490void InFlightBackendIO::WaitForPendingIO() {
491  InFlightIO::WaitForPendingIO();
492}
493
494void InFlightBackendIO::OnOperationComplete(BackgroundIO* operation,
495                                            bool cancel) {
496  BackendIO* op = static_cast<BackendIO*>(operation);
497  op->OnDone(cancel);
498
499  if (!op->callback().is_null() && (!cancel || op->IsEntryOperation()))
500    op->callback().Run(op->result());
501}
502
503void InFlightBackendIO::PostOperation(BackendIO* operation) {
504  background_thread_->PostTask(
505      FROM_HERE, base::Bind(&BackendIO::ExecuteOperation, operation));
506  OnOperationPosted(operation);
507}
508
509base::WeakPtr<InFlightBackendIO> InFlightBackendIO::GetWeakPtr() {
510  return ptr_factory_.GetWeakPtr();
511}
512
513}  // namespace
514