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