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