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