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 |