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 20 namespace disk_cache { 21 22 BackendIO::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. 41 void BackendIO::ExecuteOperation() { 42 if (IsEntryOperation()) 43 return ExecuteEntryOperation(); 44 45 ExecuteBackendOperation(); 46 } 47 48 // Runs on the background thread. 49 void 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. 57 void 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 72 bool BackendIO::IsEntryOperation() { 73 return operation_ > OP_MAX_BACKEND; 74 } 75 76 // Runs on the background thread. 77 void BackendIO::ReferenceEntry() { 78 entry_->AddRef(); 79 } 80 81 void BackendIO::Init() { 82 operation_ = OP_INIT; 83 } 84 85 void BackendIO::OpenEntry(const std::string& key, Entry** entry) { 86 operation_ = OP_OPEN; 87 key_ = key; 88 entry_ptr_ = entry; 89 } 90 91 void BackendIO::CreateEntry(const std::string& key, Entry** entry) { 92 operation_ = OP_CREATE; 93 key_ = key; 94 entry_ptr_ = entry; 95 } 96 97 void BackendIO::DoomEntry(const std::string& key) { 98 operation_ = OP_DOOM; 99 key_ = key; 100 } 101 102 void BackendIO::DoomAllEntries() { 103 operation_ = OP_DOOM_ALL; 104 } 105 106 void 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 113 void BackendIO::DoomEntriesSince(const base::Time initial_time) { 114 operation_ = OP_DOOM_SINCE; 115 initial_time_ = initial_time; 116 } 117 118 void BackendIO::OpenNextEntry(Rankings::Iterator* iterator, 119 Entry** next_entry) { 120 operation_ = OP_OPEN_NEXT; 121 iterator_ = iterator; 122 entry_ptr_ = next_entry; 123 } 124 125 void BackendIO::EndEnumeration(scoped_ptr<Rankings::Iterator> iterator) { 126 operation_ = OP_END_ENUMERATION; 127 scoped_iterator_ = iterator.Pass(); 128 } 129 130 void BackendIO::OnExternalCacheHit(const std::string& key) { 131 operation_ = OP_ON_EXTERNAL_CACHE_HIT; 132 key_ = key; 133 } 134 135 void BackendIO::CloseEntryImpl(EntryImpl* entry) { 136 operation_ = OP_CLOSE_ENTRY; 137 entry_ = entry; 138 } 139 140 void BackendIO::DoomEntryImpl(EntryImpl* entry) { 141 operation_ = OP_DOOM_ENTRY; 142 entry_ = entry; 143 } 144 145 void BackendIO::FlushQueue() { 146 operation_ = OP_FLUSH_QUEUE; 147 } 148 149 void BackendIO::RunTask(const base::Closure& task) { 150 operation_ = OP_RUN_TASK; 151 task_ = task; 152 } 153 154 void 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 164 void 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 175 void 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 184 void 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 193 void 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 202 void BackendIO::CancelSparseIO(EntryImpl* entry) { 203 operation_ = OP_CANCEL_IO; 204 entry_ = entry; 205 } 206 207 void BackendIO::ReadyForSparseIO(EntryImpl* entry) { 208 operation_ = OP_IS_READY; 209 entry_ = entry; 210 } 211 212 BackendIO::~BackendIO() {} 213 214 bool BackendIO::ReturnsEntry() { 215 return operation_ == OP_OPEN || operation_ == OP_CREATE || 216 operation_ == OP_OPEN_NEXT; 217 } 218 219 base::TimeDelta BackendIO::ElapsedTime() const { 220 return base::TimeTicks::Now() - start_time_; 221 } 222 223 // Runs on the background thread. 224 void 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. 282 void 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 325 InFlightBackendIO::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 333 InFlightBackendIO::~InFlightBackendIO() { 334 } 335 336 void 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 342 void 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 349 void 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 356 void 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 363 void 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 370 void 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 378 void 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 385 void 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 393 void 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 401 void 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 408 void 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 415 void 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 422 void 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 428 void 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 435 void 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 443 void 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 452 void 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 460 void 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 468 void 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 476 void 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 483 void 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 490 void InFlightBackendIO::WaitForPendingIO() { 491 InFlightIO::WaitForPendingIO(); 492 } 493 494 void 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 503 void InFlightBackendIO::PostOperation(BackendIO* operation) { 504 background_thread_->PostTask( 505 FROM_HERE, base::Bind(&BackendIO::ExecuteOperation, operation)); 506 OnOperationPosted(operation); 507 } 508 509 base::WeakPtr<InFlightBackendIO> InFlightBackendIO::GetWeakPtr() { 510 return ptr_factory_.GetWeakPtr(); 511 } 512 513 } // namespace 514