Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/service_worker/service_worker_disk_cache_migrator.h" | 5 #include "content/browser/service_worker/service_worker_disk_cache_migrator.h" |
| 6 | 6 |
| 7 #include "base/barrier_closure.h" | |
| 8 #include "base/files/file_util.h" | |
| 9 #include "base/location.h" | |
| 7 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
| 11 #include "base/metrics/histogram_macros.h" | |
| 8 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/task_runner_util.h" | |
| 14 #include "base/time/time.h" | |
| 9 #include "content/common/service_worker/service_worker_types.h" | 15 #include "content/common/service_worker/service_worker_types.h" |
| 10 #include "net/base/io_buffer.h" | 16 #include "net/base/io_buffer.h" |
| 11 #include "net/base/net_errors.h" | 17 #include "net/base/net_errors.h" |
| 12 #include "net/disk_cache/disk_cache.h" | 18 #include "net/disk_cache/disk_cache.h" |
| 13 | 19 |
| 14 namespace content { | 20 namespace content { |
| 15 | 21 |
| 16 namespace { | 22 namespace { |
| 17 | 23 |
| 18 // Disk cache entry data indices (Copied from appcache_diskcache.cc). | 24 // Disk cache entry data indices (Copied from appcache_diskcache.cc). |
| 19 enum { kResponseInfoIndex, kResponseContentIndex, kResponseMetadataIndex }; | 25 enum { kResponseInfoIndex, kResponseContentIndex, kResponseMetadataIndex }; |
| 20 | 26 |
| 27 void RecordMigrationResult(ServiceWorkerStatusCode status) { | |
| 28 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.DiskCacheMigrator.MigrationResult", | |
| 29 status, SERVICE_WORKER_ERROR_MAX_VALUE); | |
| 30 } | |
| 31 | |
| 32 void RecordNumberOfMigratedResources(size_t migrated_resources) { | |
| 33 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
| 34 "ServiceWorker.DiskCacheMigrator.NumberOfMigratedResources", | |
| 35 migrated_resources, 1, 1000, 50); | |
| 36 } | |
| 37 | |
| 38 void RecordMigrationTime(const base::TimeDelta& time) { | |
| 39 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.DiskCacheMigrator.MigrationTime", | |
| 40 time); | |
| 41 } | |
| 42 | |
| 21 } // namespace | 43 } // namespace |
| 22 | 44 |
| 23 // A task to move a cached resource from the src DiskCache to the dest | 45 // A task to move a cached resource from the src DiskCache to the dest |
| 24 // DiskCache. This is owned by ServiceWorkerDiskCacheMigrator. | 46 // DiskCache. This is owned by ServiceWorkerDiskCacheMigrator. |
| 25 class ServiceWorkerDiskCacheMigrator::Task { | 47 class ServiceWorkerDiskCacheMigrator::Task { |
| 26 public: | 48 public: |
| 27 Task(InflightTaskMap::KeyType task_id, | 49 Task(InflightTaskMap::KeyType task_id, |
| 28 int64 resource_id, | 50 int64 resource_id, |
| 29 int32 data_size, | 51 int32 data_size, |
| 30 ServiceWorkerDiskCache* src, | 52 ServiceWorkerDiskCache* src, |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 Finish(SERVICE_WORKER_OK); | 240 Finish(SERVICE_WORKER_OK); |
| 219 } | 241 } |
| 220 | 242 |
| 221 void ServiceWorkerDiskCacheMigrator::Task::Finish( | 243 void ServiceWorkerDiskCacheMigrator::Task::Finish( |
| 222 ServiceWorkerStatusCode status) { | 244 ServiceWorkerStatusCode status) { |
| 223 DCHECK(owner_); | 245 DCHECK(owner_); |
| 224 owner_->OnEntryMigrated(task_id_, status); | 246 owner_->OnEntryMigrated(task_id_, status); |
| 225 } | 247 } |
| 226 | 248 |
| 227 ServiceWorkerDiskCacheMigrator::ServiceWorkerDiskCacheMigrator( | 249 ServiceWorkerDiskCacheMigrator::ServiceWorkerDiskCacheMigrator( |
| 228 ServiceWorkerDiskCache* src, | 250 const base::FilePath& src_path, |
| 229 ServiceWorkerDiskCache* dest) | 251 const base::FilePath& dest_path, |
| 230 : src_(src), dest_(dest), weak_factory_(this) { | 252 int max_disk_cache_size, |
| 231 DCHECK(!src_->is_disabled()); | 253 const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread) |
| 232 DCHECK(!dest_->is_disabled()); | 254 : src_path_(src_path), |
| 255 dest_path_(dest_path), | |
| 256 max_disk_cache_size_(max_disk_cache_size), | |
| 257 disk_cache_thread_(disk_cache_thread), | |
| 258 weak_factory_(this) { | |
| 233 } | 259 } |
| 234 | 260 |
| 235 ServiceWorkerDiskCacheMigrator::~ServiceWorkerDiskCacheMigrator() { | 261 ServiceWorkerDiskCacheMigrator::~ServiceWorkerDiskCacheMigrator() { |
| 236 } | 262 } |
| 237 | 263 |
| 238 void ServiceWorkerDiskCacheMigrator::Start(const StatusCallback& callback) { | 264 void ServiceWorkerDiskCacheMigrator::Start(const StatusCallback& callback) { |
| 239 callback_ = callback; | 265 callback_ = callback; |
| 266 start_time_ = base::TimeTicks::Now(); | |
| 267 | |
| 268 PostTaskAndReplyWithResult( | |
| 269 disk_cache_thread_.get(), FROM_HERE, | |
| 270 base::Bind(&base::DeleteFile, dest_path_, true), | |
| 271 base::Bind(&ServiceWorkerDiskCacheMigrator::DidDeleteDestDirectory, | |
| 272 weak_factory_.GetWeakPtr())); | |
| 273 } | |
| 274 | |
| 275 void ServiceWorkerDiskCacheMigrator::DidDeleteDestDirectory(bool deleted) { | |
| 276 // Continue the migration regardless of the deletion result. If the migrator | |
| 277 // cannot proceed or the diskcache gets corrupted due to the failure, the | |
| 278 // storage detects it and recovers by DeleteAndStartOver. | |
| 279 | |
| 280 src_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend(); | |
|
michaeln
2015/06/11 00:52:38
android?
nhiroki
2015/06/11 21:04:50
Done in the separate CL:
https://codereview.chromi
| |
| 281 dest_ = ServiceWorkerDiskCache::CreateWithSimpleBackend(); | |
| 282 bool* is_failed = new bool(false); | |
| 283 | |
| 284 // This closure is called when both diskcaches are initialized. | |
| 285 base::Closure barrier_closure = base::BarrierClosure( | |
| 286 2, base::Bind(&ServiceWorkerDiskCacheMigrator::DidInitializeAllDiskCaches, | |
| 287 weak_factory_.GetWeakPtr(), base::Owned(is_failed))); | |
| 288 | |
| 289 // Initialize the src DiskCache. | |
| 290 net::CompletionCallback src_callback = | |
| 291 base::Bind(&ServiceWorkerDiskCacheMigrator::DidInitializeDiskCache, | |
| 292 weak_factory_.GetWeakPtr(), is_failed, barrier_closure); | |
| 293 int result = src_->InitWithDiskBackend(src_path_, max_disk_cache_size_, | |
| 294 false /* force */, disk_cache_thread_, | |
| 295 src_callback); | |
| 296 if (result != net::ERR_IO_PENDING) | |
| 297 src_callback.Run(result); | |
| 298 | |
| 299 // Initialize the dest DiskCache. | |
| 300 net::CompletionCallback dest_callback = | |
| 301 base::Bind(&ServiceWorkerDiskCacheMigrator::DidInitializeDiskCache, | |
| 302 weak_factory_.GetWeakPtr(), is_failed, barrier_closure); | |
| 303 result = dest_->InitWithDiskBackend(dest_path_, max_disk_cache_size_, | |
| 304 false /* force */, disk_cache_thread_, | |
| 305 dest_callback); | |
| 306 if (result != net::ERR_IO_PENDING) | |
| 307 dest_callback.Run(result); | |
| 308 } | |
| 309 | |
| 310 void ServiceWorkerDiskCacheMigrator::DidInitializeDiskCache( | |
| 311 bool* is_failed, | |
| 312 const base::Closure& barrier_closure, | |
| 313 int result) { | |
| 314 if (result != net::OK) | |
| 315 *is_failed = true; | |
| 316 barrier_closure.Run(); | |
| 317 } | |
| 318 | |
| 319 void ServiceWorkerDiskCacheMigrator::DidInitializeAllDiskCaches( | |
| 320 bool* is_failed) { | |
| 321 if (*is_failed) { | |
| 322 LOG(ERROR) << "Failed to initialize the diskcache"; | |
| 323 Complete(SERVICE_WORKER_ERROR_FAILED); | |
| 324 return; | |
| 325 } | |
| 326 | |
| 327 // Iterate through existing entries in the src DiskCache. | |
| 240 iterator_ = src_->disk_cache()->CreateIterator(); | 328 iterator_ = src_->disk_cache()->CreateIterator(); |
| 241 OpenNextEntry(); | 329 OpenNextEntry(); |
| 242 } | 330 } |
| 243 | 331 |
| 244 void ServiceWorkerDiskCacheMigrator::OpenNextEntry() { | 332 void ServiceWorkerDiskCacheMigrator::OpenNextEntry() { |
| 245 DCHECK(!pending_task_); | 333 DCHECK(!pending_task_); |
| 246 DCHECK(!is_iterating_); | 334 DCHECK(!is_iterating_); |
| 247 is_iterating_ = true; | 335 is_iterating_ = true; |
| 248 | 336 |
| 249 scoped_ptr<WrappedEntry> wrapped_entry(new WrappedEntry); | 337 scoped_ptr<WrappedEntry> wrapped_entry(new WrappedEntry); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 | 371 |
| 284 int64 resource_id = kInvalidServiceWorkerResourceId; | 372 int64 resource_id = kInvalidServiceWorkerResourceId; |
| 285 if (!base::StringToInt64(scoped_entry->GetKey(), &resource_id)) { | 373 if (!base::StringToInt64(scoped_entry->GetKey(), &resource_id)) { |
| 286 LOG(ERROR) << "Failed to read the resource id"; | 374 LOG(ERROR) << "Failed to read the resource id"; |
| 287 inflight_tasks_.Clear(); | 375 inflight_tasks_.Clear(); |
| 288 Complete(SERVICE_WORKER_ERROR_FAILED); | 376 Complete(SERVICE_WORKER_ERROR_FAILED); |
| 289 return; | 377 return; |
| 290 } | 378 } |
| 291 | 379 |
| 292 InflightTaskMap::KeyType task_id = next_task_id_++; | 380 InflightTaskMap::KeyType task_id = next_task_id_++; |
| 293 pending_task_.reset(new Task(task_id, resource_id, | 381 pending_task_.reset(new Task( |
| 294 scoped_entry->GetDataSize(kResponseContentIndex), | 382 task_id, resource_id, scoped_entry->GetDataSize(kResponseContentIndex), |
| 295 src_, dest_, weak_factory_.GetWeakPtr())); | 383 src_.get(), dest_.get(), weak_factory_.GetWeakPtr())); |
| 296 if (inflight_tasks_.size() < max_number_of_inflight_tasks_) { | 384 if (inflight_tasks_.size() < max_number_of_inflight_tasks_) { |
| 297 RunPendingTask(); | 385 RunPendingTask(); |
| 298 OpenNextEntry(); | 386 OpenNextEntry(); |
| 299 return; | 387 return; |
| 300 } | 388 } |
| 301 // |pending_task_| will run when an inflight task is completed. | 389 // |pending_task_| will run when an inflight task is completed. |
| 302 } | 390 } |
| 303 | 391 |
| 304 void ServiceWorkerDiskCacheMigrator::RunPendingTask() { | 392 void ServiceWorkerDiskCacheMigrator::RunPendingTask() { |
| 305 DCHECK(pending_task_); | 393 DCHECK(pending_task_); |
| 306 DCHECK_GT(max_number_of_inflight_tasks_, inflight_tasks_.size()); | 394 DCHECK_GT(max_number_of_inflight_tasks_, inflight_tasks_.size()); |
| 307 InflightTaskMap::KeyType task_id = pending_task_->task_id(); | 395 InflightTaskMap::KeyType task_id = pending_task_->task_id(); |
| 308 pending_task_->Run(); | 396 pending_task_->Run(); |
| 309 inflight_tasks_.AddWithID(pending_task_.release(), task_id); | 397 inflight_tasks_.AddWithID(pending_task_.release(), task_id); |
| 310 } | 398 } |
| 311 | 399 |
| 312 void ServiceWorkerDiskCacheMigrator::OnEntryMigrated( | 400 void ServiceWorkerDiskCacheMigrator::OnEntryMigrated( |
| 313 InflightTaskMap::KeyType task_id, | 401 InflightTaskMap::KeyType task_id, |
| 314 ServiceWorkerStatusCode status) { | 402 ServiceWorkerStatusCode status) { |
| 315 DCHECK(inflight_tasks_.Lookup(task_id)); | 403 DCHECK(inflight_tasks_.Lookup(task_id)); |
| 316 inflight_tasks_.Remove(task_id); | 404 inflight_tasks_.Remove(task_id); |
| 317 | 405 |
| 318 if (status != SERVICE_WORKER_OK) { | 406 if (status != SERVICE_WORKER_OK) { |
| 319 inflight_tasks_.Clear(); | 407 inflight_tasks_.Clear(); |
| 320 Complete(status); | 408 Complete(status); |
| 321 return; | 409 return; |
| 322 } | 410 } |
| 323 | 411 |
| 412 ++number_of_migrated_resources_; | |
| 413 | |
| 324 if (pending_task_) { | 414 if (pending_task_) { |
| 325 RunPendingTask(); | 415 RunPendingTask(); |
| 326 OpenNextEntry(); | 416 OpenNextEntry(); |
| 327 return; | 417 return; |
| 328 } | 418 } |
| 329 | 419 |
| 330 if (is_iterating_) | 420 if (is_iterating_) |
| 331 return; | 421 return; |
| 332 | 422 |
| 333 if (inflight_tasks_.IsEmpty()) | 423 if (inflight_tasks_.IsEmpty()) |
| 334 Complete(SERVICE_WORKER_OK); | 424 Complete(SERVICE_WORKER_OK); |
| 335 } | 425 } |
| 336 | 426 |
| 337 void ServiceWorkerDiskCacheMigrator::Complete(ServiceWorkerStatusCode status) { | 427 void ServiceWorkerDiskCacheMigrator::Complete(ServiceWorkerStatusCode status) { |
| 338 DCHECK(inflight_tasks_.IsEmpty()); | 428 DCHECK(inflight_tasks_.IsEmpty()); |
| 339 // TODO(nhiroki): Add UMA for the result of migration. | 429 if (status == SERVICE_WORKER_OK) { |
| 430 RecordMigrationTime(base::TimeTicks().Now() - start_time_); | |
| 431 RecordNumberOfMigratedResources(number_of_migrated_resources_); | |
| 432 } | |
| 433 RecordMigrationResult(status); | |
| 434 | |
| 435 src_.reset(); | |
| 436 dest_.reset(); | |
| 340 callback_.Run(status); | 437 callback_.Run(status); |
| 341 } | 438 } |
| 342 | 439 |
| 343 } // namespace content | 440 } // namespace content |
| OLD | NEW |