| Index: content/browser/service_worker/service_worker_storage.cc | 
| diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc | 
| index a9a5b774ac0597ced39ad398f1b67815c82a5a26..9a79263d718d49b94d630fe81914daa1fcee4091 100644 | 
| --- a/content/browser/service_worker/service_worker_storage.cc | 
| +++ b/content/browser/service_worker/service_worker_storage.cc | 
| @@ -25,17 +25,6 @@ namespace content { | 
|  | 
| namespace { | 
|  | 
| -typedef base::Callback<void( | 
| -    ServiceWorkerStorage::InitialData* data, | 
| -    ServiceWorkerDatabase::Status status)> InitializeCallback; | 
| -typedef base::Callback<void( | 
| -    const ServiceWorkerDatabase::RegistrationData& data, | 
| -    const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources, | 
| -    ServiceWorkerDatabase::Status status)> ReadRegistrationCallback; | 
| -typedef base::Callback<void( | 
| -    bool origin_is_deletable, | 
| -    ServiceWorkerDatabase::Status status)> DeleteRegistrationCallback; | 
| - | 
| void RunSoon(const tracked_objects::Location& from_here, | 
| const base::Closure& closure) { | 
| base::MessageLoop::current()->PostTask(from_here, closure); | 
| @@ -60,8 +49,11 @@ const base::FilePath::CharType kServiceWorkerDirectory[] = | 
| FILE_PATH_LITERAL("Service Worker"); | 
| const base::FilePath::CharType kDatabaseName[] = | 
| FILE_PATH_LITERAL("Database"); | 
| +const base::FilePath::CharType kDiskCacheName[] = | 
| +    FILE_PATH_LITERAL("Cache"); | 
|  | 
| const int kMaxMemDiskCacheSize = 10 * 1024 * 1024; | 
| +const int kMaxDiskCacheSize = 250 * 1024 * 1024; | 
|  | 
| void EmptyCompletionCallback(int) {} | 
|  | 
| @@ -77,59 +69,6 @@ ServiceWorkerStatusCode DatabaseStatusToStatusCode( | 
| } | 
| } | 
|  | 
| -void ReadInitialDataFromDB( | 
| -    ServiceWorkerDatabase* database, | 
| -    scoped_refptr<base::SequencedTaskRunner> original_task_runner, | 
| -    const InitializeCallback& callback) { | 
| -  DCHECK(database); | 
| -  scoped_ptr<ServiceWorkerStorage::InitialData> data( | 
| -      new ServiceWorkerStorage::InitialData()); | 
| - | 
| -  ServiceWorkerDatabase::Status status = | 
| -      database->GetNextAvailableIds(&data->next_registration_id, | 
| -                                    &data->next_version_id, | 
| -                                    &data->next_resource_id); | 
| -  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| -    original_task_runner->PostTask( | 
| -        FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); | 
| -    return; | 
| -  } | 
| - | 
| -  status = database->GetOriginsWithRegistrations(&data->origins); | 
| -  original_task_runner->PostTask( | 
| -      FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); | 
| -} | 
| - | 
| -void DeleteRegistrationFromDB( | 
| -    ServiceWorkerDatabase* database, | 
| -    scoped_refptr<base::SequencedTaskRunner> original_task_runner, | 
| -    int64 registration_id, | 
| -    const GURL& origin, | 
| -    const DeleteRegistrationCallback& callback) { | 
| -  DCHECK(database); | 
| -  ServiceWorkerDatabase::Status status = | 
| -      database->DeleteRegistration(registration_id, origin); | 
| -  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| -    original_task_runner->PostTask( | 
| -        FROM_HERE, base::Bind(callback, false, status)); | 
| -    return; | 
| -  } | 
| - | 
| -  // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the | 
| -  // unique origin list. | 
| -  std::vector<ServiceWorkerDatabase::RegistrationData> registrations; | 
| -  status = database->GetRegistrationsForOrigin(origin, ®istrations); | 
| -  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| -    original_task_runner->PostTask( | 
| -        FROM_HERE, base::Bind(callback, false, status)); | 
| -    return; | 
| -  } | 
| - | 
| -  bool deletable = registrations.empty(); | 
| -  original_task_runner->PostTask( | 
| -      FROM_HERE, base::Bind(callback, deletable, status)); | 
| -} | 
| - | 
| }  // namespace | 
|  | 
| ServiceWorkerStorage::InitialData::InitialData() | 
| @@ -155,14 +94,11 @@ ServiceWorkerStorage::ServiceWorkerStorage( | 
| database_task_runner_(database_task_runner), | 
| disk_cache_thread_(disk_cache_thread), | 
| quota_manager_proxy_(quota_manager_proxy), | 
| +      is_purge_pending_(false), | 
| weak_factory_(this) { | 
| -  if (!path.empty()) { | 
| +  if (!path.empty()) | 
| path_ = path.Append(kServiceWorkerDirectory); | 
| -    database_.reset(new ServiceWorkerDatabase(path_.Append(kDatabaseName))); | 
| -  } else { | 
| -    // Create an in-memory database. | 
| -    database_.reset(new ServiceWorkerDatabase(base::FilePath())); | 
| -  } | 
| +  database_.reset(new ServiceWorkerDatabase(GetDatabasePath())); | 
| } | 
|  | 
| ServiceWorkerStorage::~ServiceWorkerStorage() { | 
| @@ -170,112 +106,107 @@ ServiceWorkerStorage::~ServiceWorkerStorage() { | 
| database_task_runner_->DeleteSoon(FROM_HERE, database_.release()); | 
| } | 
|  | 
| -void ServiceWorkerStorage::FindRegistrationForPattern( | 
| -    const GURL& scope, | 
| +void ServiceWorkerStorage::FindRegistrationForDocument( | 
| +    const GURL& document_url, | 
| const FindRegistrationCallback& callback) { | 
| -  scoped_refptr<ServiceWorkerRegistration> null_registration; | 
| if (!LazyInitialize(base::Bind( | 
| -          &ServiceWorkerStorage::FindRegistrationForPattern, | 
| -          weak_factory_.GetWeakPtr(), scope, callback))) { | 
| +          &ServiceWorkerStorage::FindRegistrationForDocument, | 
| +          weak_factory_.GetWeakPtr(), document_url, callback))) { | 
| if (state_ != INITIALIZING || !context_) { | 
| -      CompleteFindSoon(FROM_HERE, null_registration, | 
| -                       SERVICE_WORKER_ERROR_FAILED, callback); | 
| +      CompleteFindNow(scoped_refptr<ServiceWorkerRegistration>(), | 
| +                      SERVICE_WORKER_ERROR_FAILED, callback); | 
| } | 
| return; | 
| } | 
| DCHECK_EQ(INITIALIZED, state_); | 
|  | 
| // See if there are any stored registrations for the origin. | 
| -  if (!ContainsKey(registered_origins_, scope.GetOrigin())) { | 
| +  if (!ContainsKey(registered_origins_, document_url.GetOrigin())) { | 
| // Look for something currently being installed. | 
| scoped_refptr<ServiceWorkerRegistration> installing_registration = | 
| -        FindInstallingRegistrationForPattern(scope); | 
| -    if (installing_registration) { | 
| -      CompleteFindSoon( | 
| -          FROM_HERE, installing_registration, SERVICE_WORKER_OK, callback); | 
| -      return; | 
| -    } | 
| -    CompleteFindSoon( | 
| -        FROM_HERE, null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback); | 
| +        FindInstallingRegistrationForDocument(document_url); | 
| +    CompleteFindNow( | 
| +        installing_registration, | 
| +        installing_registration ? | 
| +            SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND, | 
| +        callback); | 
| return; | 
| } | 
|  | 
| -  RegistrationList* registrations = new RegistrationList(); | 
| -  PostTaskAndReplyWithResult( | 
| -      database_task_runner_, | 
| +  database_task_runner_->PostTask( | 
| FROM_HERE, | 
| -      base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin, | 
| -                 base::Unretained(database_.get()), | 
| -                 scope.GetOrigin(), base::Unretained(registrations)), | 
| -      base::Bind(&ServiceWorkerStorage::DidGetRegistrationsForPattern, | 
| -                 weak_factory_.GetWeakPtr(), scope, callback, | 
| -                 base::Owned(registrations))); | 
| +      base::Bind( | 
| +          &FindForDocumentInDB, | 
| +          database_.get(), | 
| +          base::MessageLoopProxy::current(), | 
| +          document_url, | 
| +          base::Bind(&ServiceWorkerStorage::DidFindRegistrationForDocument, | 
| +                     weak_factory_.GetWeakPtr(), document_url, callback))); | 
| } | 
|  | 
| -void ServiceWorkerStorage::FindRegistrationForDocument( | 
| -    const GURL& document_url, | 
| +void ServiceWorkerStorage::FindRegistrationForPattern( | 
| +    const GURL& scope, | 
| const FindRegistrationCallback& callback) { | 
| -  scoped_refptr<ServiceWorkerRegistration> null_registration; | 
| if (!LazyInitialize(base::Bind( | 
| -          &ServiceWorkerStorage::FindRegistrationForDocument, | 
| -          weak_factory_.GetWeakPtr(), document_url, callback))) { | 
| -    if (state_ != INITIALIZING || !context_) | 
| -      CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback); | 
| +          &ServiceWorkerStorage::FindRegistrationForPattern, | 
| +          weak_factory_.GetWeakPtr(), scope, callback))) { | 
| +    if (state_ != INITIALIZING || !context_) { | 
| +      CompleteFindSoon(FROM_HERE, scoped_refptr<ServiceWorkerRegistration>(), | 
| +                       SERVICE_WORKER_ERROR_FAILED, callback); | 
| +    } | 
| return; | 
| } | 
| DCHECK_EQ(INITIALIZED, state_); | 
|  | 
| // See if there are any stored registrations for the origin. | 
| -  if (!ContainsKey(registered_origins_, document_url.GetOrigin())) { | 
| +  if (!ContainsKey(registered_origins_, scope.GetOrigin())) { | 
| // Look for something currently being installed. | 
| scoped_refptr<ServiceWorkerRegistration> installing_registration = | 
| -        FindInstallingRegistrationForDocument(document_url); | 
| -    if (installing_registration) { | 
| -      CompleteFindNow(installing_registration, SERVICE_WORKER_OK, callback); | 
| -      return; | 
| -    } | 
| -    CompleteFindNow( | 
| -        null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback); | 
| +        FindInstallingRegistrationForPattern(scope); | 
| +    CompleteFindSoon( | 
| +        FROM_HERE, installing_registration, | 
| +        installing_registration ? | 
| +            SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND, | 
| +        callback); | 
| return; | 
| } | 
|  | 
| -  RegistrationList* registrations = new RegistrationList(); | 
| -  PostTaskAndReplyWithResult( | 
| -      database_task_runner_, | 
| +  database_task_runner_->PostTask( | 
| FROM_HERE, | 
| -      base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin, | 
| -                 base::Unretained(database_.get()), | 
| -                 document_url.GetOrigin(), base::Unretained(registrations)), | 
| -      base::Bind(&ServiceWorkerStorage::DidGetRegistrationsForDocument, | 
| -                 weak_factory_.GetWeakPtr(), document_url, callback, | 
| -                 base::Owned(registrations))); | 
| +      base::Bind( | 
| +          &FindForPatternInDB, | 
| +          database_.get(), | 
| +          base::MessageLoopProxy::current(), | 
| +          scope, | 
| +          base::Bind(&ServiceWorkerStorage::DidFindRegistrationForPattern, | 
| +                     weak_factory_.GetWeakPtr(), scope, callback))); | 
| } | 
|  | 
| void ServiceWorkerStorage::FindRegistrationForId( | 
| int64 registration_id, | 
| const GURL& origin, | 
| const FindRegistrationCallback& callback) { | 
| -  scoped_refptr<ServiceWorkerRegistration> null_registration; | 
| if (!LazyInitialize(base::Bind( | 
| &ServiceWorkerStorage::FindRegistrationForId, | 
| weak_factory_.GetWeakPtr(), registration_id, origin, callback))) { | 
| -    if (state_ != INITIALIZING || !context_) | 
| -      CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback); | 
| +    if (state_ != INITIALIZING || !context_) { | 
| +      CompleteFindNow(scoped_refptr<ServiceWorkerRegistration>(), | 
| +                      SERVICE_WORKER_ERROR_FAILED, callback); | 
| +    } | 
| return; | 
| } | 
| DCHECK_EQ(INITIALIZED, state_); | 
|  | 
| // See if there are any stored registrations for the origin. | 
| if (!ContainsKey(registered_origins_, origin)) { | 
| -    // Look for somthing currently being installed. | 
| +    // Look for something currently being installed. | 
| scoped_refptr<ServiceWorkerRegistration> installing_registration = | 
| FindInstallingRegistrationForId(registration_id); | 
| -    if (installing_registration) { | 
| -      CompleteFindNow(installing_registration, SERVICE_WORKER_OK, callback); | 
| -      return; | 
| -    } | 
| CompleteFindNow( | 
| -        null_registration, SERVICE_WORKER_ERROR_NOT_FOUND, callback); | 
| +        installing_registration, | 
| +        installing_registration ? | 
| +            SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND, | 
| +        callback); | 
| return; | 
| } | 
|  | 
| @@ -286,20 +217,14 @@ void ServiceWorkerStorage::FindRegistrationForId( | 
| return; | 
| } | 
|  | 
| -  ServiceWorkerDatabase::RegistrationData* data = | 
| -      new ServiceWorkerDatabase::RegistrationData; | 
| -  ResourceList* resources = new ResourceList; | 
| -  PostTaskAndReplyWithResult( | 
| -      database_task_runner_, | 
| +  database_task_runner_->PostTask( | 
| FROM_HERE, | 
| -      base::Bind(&ServiceWorkerDatabase::ReadRegistration, | 
| -                 base::Unretained(database_.get()), | 
| +      base::Bind(&FindForIdInDB, | 
| +                 database_.get(), | 
| +                 base::MessageLoopProxy::current(), | 
| registration_id, origin, | 
| -                 base::Unretained(data), | 
| -                 base::Unretained(resources)), | 
| -      base::Bind(&ServiceWorkerStorage::DidReadRegistrationForId, | 
| -                 weak_factory_.GetWeakPtr(), | 
| -                 callback, base::Owned(data), base::Owned(resources))); | 
| +                 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId, | 
| +                            weak_factory_.GetWeakPtr(), callback))); | 
| } | 
|  | 
| void ServiceWorkerStorage::GetAllRegistrations( | 
| @@ -351,15 +276,17 @@ void ServiceWorkerStorage::StoreRegistration( | 
| data.is_active = false;  // initially stored in the waiting state | 
|  | 
| ResourceList resources; | 
| -  PostTaskAndReplyWithResult( | 
| -      database_task_runner_, | 
| +  version->script_cache_map()->GetResources(&resources); | 
| + | 
| +  database_task_runner_->PostTask( | 
| FROM_HERE, | 
| -      base::Bind(&ServiceWorkerDatabase::WriteRegistration, | 
| -                 base::Unretained(database_.get()), data, resources), | 
| -      base::Bind(&ServiceWorkerStorage::DidStoreRegistration, | 
| -                 weak_factory_.GetWeakPtr(), | 
| -                 registration->script_url().GetOrigin(), | 
| -                 callback)); | 
| +      base::Bind(&WriteRegistrationInDB, | 
| +                 database_.get(), | 
| +                 base::MessageLoopProxy::current(), | 
| +                 data, resources, | 
| +                 base::Bind(&ServiceWorkerStorage::DidStoreRegistration, | 
| +                            weak_factory_.GetWeakPtr(), | 
| +                            callback))); | 
| } | 
|  | 
| void ServiceWorkerStorage::UpdateToActiveState( | 
| @@ -453,6 +380,18 @@ void ServiceWorkerStorage::NotifyDoneInstallingRegistration( | 
| installing_registrations_.erase(registration->id()); | 
| } | 
|  | 
| +base::FilePath ServiceWorkerStorage::GetDatabasePath() { | 
| +  if (path_.empty()) | 
| +    return base::FilePath(); | 
| +  return path_.Append(kDatabaseName); | 
| +} | 
| + | 
| +base::FilePath ServiceWorkerStorage::GetDiskCachePath() { | 
| +  if (path_.empty()) | 
| +    return base::FilePath(); | 
| +  return path_.Append(kDiskCacheName); | 
| +} | 
| + | 
| bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) { | 
| if (!context_) | 
| return false; | 
| @@ -507,118 +446,70 @@ void ServiceWorkerStorage::DidReadInitialData( | 
| pending_tasks_.clear(); | 
| } | 
|  | 
| -void ServiceWorkerStorage::DidGetRegistrationsForPattern( | 
| -    const GURL& scope, | 
| +void ServiceWorkerStorage::DidFindRegistrationForDocument( | 
| +    const GURL& document_url, | 
| const FindRegistrationCallback& callback, | 
| -    RegistrationList* registrations, | 
| +    const ServiceWorkerDatabase::RegistrationData& data, | 
| +    const ResourceList& resources, | 
| ServiceWorkerDatabase::Status status) { | 
| -  DCHECK(registrations); | 
| -  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| -    // TODO(nhiroki): Handle database error (http://crbug.com/371675). | 
| -    callback.Run(SERVICE_WORKER_ERROR_FAILED, | 
| -                 scoped_refptr<ServiceWorkerRegistration>()); | 
| +  if (status == ServiceWorkerDatabase::STATUS_OK) { | 
| +    callback.Run(SERVICE_WORKER_OK, GetOrCreateRegistration(data, resources)); | 
| return; | 
| } | 
|  | 
| -  // Find one with a matching scope. | 
| -  for (RegistrationList::const_iterator it = registrations->begin(); | 
| -       it != registrations->end(); ++it) { | 
| -    if (scope == it->scope) { | 
| -      scoped_refptr<ServiceWorkerRegistration> registration = | 
| -          context_->GetLiveRegistration(it->registration_id); | 
| -      if (!registration) | 
| -        registration = CreateRegistration(*it); | 
| -      callback.Run(SERVICE_WORKER_OK, registration); | 
| -      return; | 
| -    } | 
| -  } | 
| - | 
| -  // Look for something currently being installed. | 
| -  scoped_refptr<ServiceWorkerRegistration> installing_registration = | 
| -      FindInstallingRegistrationForPattern(scope); | 
| -  if (installing_registration) { | 
| -    callback.Run(SERVICE_WORKER_OK, installing_registration); | 
| +  if (status == ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) { | 
| +    // Look for something currently being installed. | 
| +    scoped_refptr<ServiceWorkerRegistration> installing_registration = | 
| +        FindInstallingRegistrationForDocument(document_url); | 
| +    callback.Run(installing_registration ? | 
| +        SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND, | 
| +        installing_registration); | 
| return; | 
| } | 
|  | 
| -  callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, | 
| +  // TODO(nhiroki): Handle database error (http://crbug.com/371675). | 
| +  callback.Run(DatabaseStatusToStatusCode(status), | 
| scoped_refptr<ServiceWorkerRegistration>()); | 
| } | 
|  | 
| -void ServiceWorkerStorage::DidGetRegistrationsForDocument( | 
| -    const GURL& document_url, | 
| +void ServiceWorkerStorage::DidFindRegistrationForPattern( | 
| +    const GURL& scope, | 
| const FindRegistrationCallback& callback, | 
| -    RegistrationList* registrations, | 
| +    const ServiceWorkerDatabase::RegistrationData& data, | 
| +    const ResourceList& resources, | 
| ServiceWorkerDatabase::Status status) { | 
| -  DCHECK(registrations); | 
| -  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| -    // TODO(nhiroki): Handle database error (http://crbug.com/371675). | 
| -    callback.Run(SERVICE_WORKER_ERROR_FAILED, | 
| -                 scoped_refptr<ServiceWorkerRegistration>()); | 
| +  if (status == ServiceWorkerDatabase::STATUS_OK) { | 
| +    callback.Run(SERVICE_WORKER_OK, GetOrCreateRegistration(data, resources)); | 
| return; | 
| } | 
|  | 
| -  // Find one with a pattern match. | 
| -  for (RegistrationList::const_iterator it = registrations->begin(); | 
| -       it != registrations->end(); ++it) { | 
| -    // TODO(michaeln): if there are multiple matches the one with | 
| -    // the longest scope should win. | 
| -    if (ServiceWorkerUtils::ScopeMatches(it->scope, document_url)) { | 
| -      scoped_refptr<ServiceWorkerRegistration> registration = | 
| -          context_->GetLiveRegistration(it->registration_id); | 
| -      if (registration) { | 
| -        callback.Run(SERVICE_WORKER_OK, registration); | 
| -        return; | 
| -      } | 
| -      callback.Run(SERVICE_WORKER_OK, CreateRegistration(*it)); | 
| -      return; | 
| -    } | 
| -  } | 
| - | 
| -  // Look for something currently being installed. | 
| -  // TODO(michaeln): Should be mixed in with the stored registrations | 
| -  // for this test. | 
| -  scoped_refptr<ServiceWorkerRegistration> installing_registration = | 
| -      FindInstallingRegistrationForDocument(document_url); | 
| -  if (installing_registration) { | 
| -    callback.Run(SERVICE_WORKER_OK, installing_registration); | 
| +  if (status == ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) { | 
| +    scoped_refptr<ServiceWorkerRegistration> installing_registration = | 
| +        FindInstallingRegistrationForPattern(scope); | 
| +    callback.Run(installing_registration ? | 
| +        SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND, | 
| +        installing_registration); | 
| return; | 
| } | 
|  | 
| -  callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, | 
| +  // TODO(nhiroki): Handle database error (http://crbug.com/371675). | 
| +  callback.Run(DatabaseStatusToStatusCode(status), | 
| scoped_refptr<ServiceWorkerRegistration>()); | 
| } | 
|  | 
| -void ServiceWorkerStorage::DidReadRegistrationForId( | 
| +void ServiceWorkerStorage::DidFindRegistrationForId( | 
| const FindRegistrationCallback& callback, | 
| -    ServiceWorkerDatabase::RegistrationData* registration, | 
| -    ResourceList* resources, | 
| +    const ServiceWorkerDatabase::RegistrationData& data, | 
| +    const ResourceList& resources, | 
| ServiceWorkerDatabase::Status status) { | 
| -  DCHECK(registration); | 
| -  DCHECK(resources); | 
| - | 
| if (status == ServiceWorkerDatabase::STATUS_OK) { | 
| -    callback.Run(SERVICE_WORKER_OK, CreateRegistration(*registration)); | 
| +    callback.Run(SERVICE_WORKER_OK, | 
| +                 GetOrCreateRegistration(data, resources)); | 
| return; | 
| } | 
| - | 
| -  if (status == ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) { | 
| -    // Look for somthing currently being installed. | 
| -    scoped_refptr<ServiceWorkerRegistration> installing_registration = | 
| -        FindInstallingRegistrationForId(registration->registration_id); | 
| -    if (installing_registration) { | 
| -      callback.Run(SERVICE_WORKER_OK, installing_registration); | 
| -      return; | 
| -    } | 
| -    callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, | 
| -                 scoped_refptr<ServiceWorkerRegistration>()); | 
| -    return; | 
| -  } | 
| - | 
| // TODO(nhiroki): Handle database error (http://crbug.com/371675). | 
| callback.Run(DatabaseStatusToStatusCode(status), | 
| scoped_refptr<ServiceWorkerRegistration>()); | 
| -  return; | 
| } | 
|  | 
| void ServiceWorkerStorage::DidGetAllRegistrations( | 
| @@ -668,8 +559,9 @@ void ServiceWorkerStorage::DidGetAllRegistrations( | 
| } | 
|  | 
| void ServiceWorkerStorage::DidStoreRegistration( | 
| -    const GURL& origin, | 
| const StatusCallback& callback, | 
| +    const GURL& origin, | 
| +    const std::vector<int64>& newly_purgeable_resources, | 
| ServiceWorkerDatabase::Status status) { | 
| if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| // TODO(nhiroki): Handle database error (http://crbug.com/371675). | 
| @@ -678,6 +570,7 @@ void ServiceWorkerStorage::DidStoreRegistration( | 
| } | 
| registered_origins_.insert(origin); | 
| callback.Run(SERVICE_WORKER_OK); | 
| +  StartPurgingResources(newly_purgeable_resources); | 
| } | 
|  | 
| void ServiceWorkerStorage::DidUpdateToActiveState( | 
| @@ -691,6 +584,7 @@ void ServiceWorkerStorage::DidDeleteRegistration( | 
| const GURL& origin, | 
| const StatusCallback& callback, | 
| bool origin_is_deletable, | 
| +    const std::vector<int64>& newly_purgeable_resources, | 
| ServiceWorkerDatabase::Status status) { | 
| if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| // TODO(nhiroki): Handle database error (http://crbug.com/371675). | 
| @@ -700,21 +594,27 @@ void ServiceWorkerStorage::DidDeleteRegistration( | 
| if (origin_is_deletable) | 
| registered_origins_.erase(origin); | 
| callback.Run(SERVICE_WORKER_OK); | 
| +  StartPurgingResources(newly_purgeable_resources); | 
| } | 
|  | 
| scoped_refptr<ServiceWorkerRegistration> | 
| -ServiceWorkerStorage::CreateRegistration( | 
| -    const ServiceWorkerDatabase::RegistrationData& data) { | 
| -  scoped_refptr<ServiceWorkerRegistration> registration( | 
| -      new ServiceWorkerRegistration( | 
| -          data.scope, data.script, data.registration_id, context_)); | 
| +ServiceWorkerStorage::GetOrCreateRegistration( | 
| +    const ServiceWorkerDatabase::RegistrationData& data, | 
| +    const ResourceList& resources) { | 
| +  scoped_refptr<ServiceWorkerRegistration> registration = | 
| +      context_->GetLiveRegistration(data.registration_id); | 
| +  if (registration) | 
| +    return registration; | 
|  | 
| +  registration = new ServiceWorkerRegistration( | 
| +      data.scope, data.script, data.registration_id, context_); | 
| scoped_refptr<ServiceWorkerVersion> version = | 
| context_->GetLiveVersion(data.version_id); | 
| if (!version) { | 
| version = new ServiceWorkerVersion(registration, data.version_id, context_); | 
| version->SetStatus(data.is_active ? | 
| ServiceWorkerVersion::ACTIVE : ServiceWorkerVersion::INSTALLED); | 
| +    version->script_cache_map()->SetResources(resources); | 
| } | 
|  | 
| if (version->status() == ServiceWorkerVersion::ACTIVE) | 
| @@ -725,7 +625,6 @@ ServiceWorkerStorage::CreateRegistration( | 
| NOTREACHED(); | 
| // TODO(michaeln): Hmmm, what if DeleteReg was invoked after | 
| // the Find result we're returning here? NOTREACHED condition? | 
| - | 
| return registration; | 
| } | 
|  | 
| @@ -733,8 +632,7 @@ ServiceWorkerRegistration* | 
| ServiceWorkerStorage::FindInstallingRegistrationForDocument( | 
| const GURL& document_url) { | 
| // TODO(michaeln): if there are multiple matches the one with | 
| -  // the longest scope should win, and these should on equal footing | 
| -  // with the stored registrations in FindRegistrationForDocument(). | 
| +  // the longest scope should win. | 
| for (RegistrationRefsById::const_iterator it = | 
| installing_registrations_.begin(); | 
| it != installing_registrations_.end(); ++it) { | 
| @@ -772,13 +670,240 @@ ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() { | 
| if (disk_cache_) | 
| return disk_cache_.get(); | 
|  | 
| -  // TODO(michaeln): Store data on disk and do error checking. | 
| disk_cache_.reset(new ServiceWorkerDiskCache); | 
| -  int rv = disk_cache_->InitWithMemBackend( | 
| -      kMaxMemDiskCacheSize, | 
| -      base::Bind(&EmptyCompletionCallback)); | 
| -  DCHECK_EQ(net::OK, rv); | 
| + | 
| +  base::FilePath path = GetDiskCachePath(); | 
| +  if (path.empty()) { | 
| +    int rv = disk_cache_->InitWithMemBackend( | 
| +        kMaxMemDiskCacheSize, | 
| +        base::Bind(&EmptyCompletionCallback)); | 
| +    DCHECK_EQ(net::OK, rv); | 
| +    return disk_cache_.get(); | 
| +  } | 
| + | 
| +  int rv = disk_cache_->InitWithDiskBackend( | 
| +      path, kMaxDiskCacheSize, false, | 
| +      disk_cache_thread_.get(), | 
| +      base::Bind(&ServiceWorkerStorage::OnDiskCacheInitialized, | 
| +                 weak_factory_.GetWeakPtr())); | 
| +  if (rv != net::ERR_IO_PENDING) | 
| +    OnDiskCacheInitialized(rv); | 
| + | 
| return disk_cache_.get(); | 
| } | 
|  | 
| +void ServiceWorkerStorage::OnDiskCacheInitialized(int rv) { | 
| +  if (rv != net::OK) { | 
| +    LOG(ERROR) << "Failed to open the serviceworker diskcache."; | 
| +    // TODO(michaeln): DeleteAndStartOver() | 
| +    disk_cache_->Disable(); | 
| +    state_ = DISABLED; | 
| +  } | 
| +} | 
| + | 
| +void ServiceWorkerStorage::StartPurgingResources( | 
| +    const std::vector<int64>& ids) { | 
| +  for (size_t i = 0; i < ids.size(); ++i) | 
| +    purgeable_reource_ids_.push_back(ids[i]); | 
| + | 
| +  if (purgeable_reource_ids_.empty() || is_purge_pending_) | 
| +    return; | 
| + | 
| +  // Do one at a time until we're done, use RunSoon to avoid recursion when | 
| +  // DoomEntry returns immediately. | 
| +  is_purge_pending_ = true; | 
| +  int64 id = purgeable_reource_ids_.front(); | 
| +  purgeable_reource_ids_.pop_front(); | 
| +  RunSoon(FROM_HERE, | 
| +          base::Bind(&ServiceWorkerStorage::PurgeResource, | 
| +                     weak_factory_.GetWeakPtr(), id)); | 
| +} | 
| + | 
| +void ServiceWorkerStorage::PurgeResource(int64 id) { | 
| +  DCHECK(is_purge_pending_); | 
| +  int rv = disk_cache()->DoomEntry( | 
| +      id, base::Bind(&ServiceWorkerStorage::OnResourcePurged, | 
| +                     weak_factory_.GetWeakPtr(), id)); | 
| +  if (rv != net::ERR_IO_PENDING) | 
| +    OnResourcePurged(id, rv); | 
| +} | 
| + | 
| +void ServiceWorkerStorage::OnResourcePurged(int64 id, int rv) { | 
| +  DCHECK(is_purge_pending_); | 
| +  is_purge_pending_ = false; | 
| + | 
| +  database_task_runner_->PostTask( | 
| +      FROM_HERE, | 
| +      base::Bind(base::IgnoreResult( | 
| +          &ServiceWorkerDatabase::ClearPurgeableResourceIds), | 
| +          base::Unretained(database_.get()), | 
| +          std::set<int64>(&id, &id + 1))); | 
| + | 
| +  // Continue purging the remaining resources. | 
| +  StartPurgingResources(std::vector<int64>()); | 
| +} | 
| + | 
| +void ServiceWorkerStorage::ReadInitialDataFromDB( | 
| +    ServiceWorkerDatabase* database, | 
| +    scoped_refptr<base::SequencedTaskRunner> original_task_runner, | 
| +    const InitializeCallback& callback) { | 
| +  DCHECK(database); | 
| +  scoped_ptr<ServiceWorkerStorage::InitialData> data( | 
| +      new ServiceWorkerStorage::InitialData()); | 
| + | 
| +  ServiceWorkerDatabase::Status status = | 
| +      database->GetNextAvailableIds(&data->next_registration_id, | 
| +                                    &data->next_version_id, | 
| +                                    &data->next_resource_id); | 
| +  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| +    original_task_runner->PostTask( | 
| +        FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); | 
| +    return; | 
| +  } | 
| + | 
| +  status = database->GetOriginsWithRegistrations(&data->origins); | 
| +  original_task_runner->PostTask( | 
| +      FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); | 
| +} | 
| + | 
| +void ServiceWorkerStorage::DeleteRegistrationFromDB( | 
| +    ServiceWorkerDatabase* database, | 
| +    scoped_refptr<base::SequencedTaskRunner> original_task_runner, | 
| +    int64 registration_id, | 
| +    const GURL& origin, | 
| +    const DeleteRegistrationCallback& callback) { | 
| +  DCHECK(database); | 
| + | 
| +  std::vector<int64> newly_purgeable_resources; | 
| +  ServiceWorkerDatabase::Status status = | 
| +      database->DeleteRegistration(registration_id, origin, | 
| +                                   &newly_purgeable_resources); | 
| +  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| +    original_task_runner->PostTask( | 
| +        FROM_HERE, base::Bind(callback, false, std::vector<int64>(), status)); | 
| +    return; | 
| +  } | 
| + | 
| +  // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the | 
| +  // unique origin list. | 
| +  std::vector<ServiceWorkerDatabase::RegistrationData> registrations; | 
| +  status = database->GetRegistrationsForOrigin(origin, ®istrations); | 
| +  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| +    original_task_runner->PostTask( | 
| +        FROM_HERE, base::Bind(callback, false, std::vector<int64>(), status)); | 
| +    return; | 
| +  } | 
| + | 
| +  bool deletable = registrations.empty(); | 
| +  original_task_runner->PostTask( | 
| +      FROM_HERE, base::Bind(callback, deletable, | 
| +                            newly_purgeable_resources, status)); | 
| +} | 
| + | 
| +void ServiceWorkerStorage::WriteRegistrationInDB( | 
| +    ServiceWorkerDatabase* database, | 
| +    scoped_refptr<base::SequencedTaskRunner> original_task_runner, | 
| +    const ServiceWorkerDatabase::RegistrationData& data, | 
| +    const ResourceList& resources, | 
| +    const WriteRegistrationCallback& callback) { | 
| +  DCHECK(database); | 
| +  std::vector<int64> newly_purgeable_resources; | 
| +  ServiceWorkerDatabase::Status status = | 
| +      database->WriteRegistration(data, resources, &newly_purgeable_resources); | 
| +  original_task_runner->PostTask( | 
| +      FROM_HERE, | 
| +      base::Bind(callback, data.script.GetOrigin(), | 
| +                 newly_purgeable_resources, status)); | 
| +} | 
| + | 
| +void ServiceWorkerStorage::FindForDocumentInDB( | 
| +    ServiceWorkerDatabase* database, | 
| +    scoped_refptr<base::SequencedTaskRunner> original_task_runner, | 
| +    const GURL& document_url, | 
| +    const FindInDBCallback& callback) { | 
| +  GURL origin = document_url.GetOrigin(); | 
| +  RegistrationList registrations; | 
| +  ServiceWorkerDatabase::Status status = | 
| +      database->GetRegistrationsForOrigin(origin, ®istrations); | 
| +  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| +    original_task_runner->PostTask( | 
| +        FROM_HERE, | 
| +        base::Bind(callback, | 
| +                   ServiceWorkerDatabase::RegistrationData(), | 
| +                   ResourceList(), | 
| +                   status)); | 
| +    return; | 
| +  } | 
| + | 
| +  // Find one with a pattern match. | 
| +  // TODO(michaeln): if there are multiple matches the one with | 
| +  // the longest scope should win. | 
| +  ServiceWorkerDatabase::RegistrationData data; | 
| +  ResourceList resources; | 
| +  status = ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND; | 
| +  for (RegistrationList::const_iterator it = registrations.begin(); | 
| +       it != registrations.end(); ++it) { | 
| +    if (!ServiceWorkerUtils::ScopeMatches(it->scope, document_url)) | 
| +      continue; | 
| +    status = database->ReadRegistration(it->registration_id, origin, | 
| +                                        &data, &resources); | 
| +    break;  // We're done looping. | 
| +  } | 
| + | 
| +  original_task_runner->PostTask( | 
| +      FROM_HERE, | 
| +      base::Bind(callback, data, resources, status)); | 
| +} | 
| + | 
| +void ServiceWorkerStorage::FindForPatternInDB( | 
| +    ServiceWorkerDatabase* database, | 
| +    scoped_refptr<base::SequencedTaskRunner> original_task_runner, | 
| +    const GURL& scope, | 
| +    const FindInDBCallback& callback) { | 
| +  GURL origin = scope.GetOrigin(); | 
| +  std::vector<ServiceWorkerDatabase::RegistrationData> registrations; | 
| +  ServiceWorkerDatabase::Status status = | 
| +      database->GetRegistrationsForOrigin(origin, ®istrations); | 
| +  if (status != ServiceWorkerDatabase::STATUS_OK) { | 
| +    original_task_runner->PostTask( | 
| +        FROM_HERE, | 
| +        base::Bind(callback, | 
| +                   ServiceWorkerDatabase::RegistrationData(), | 
| +                   ResourceList(), | 
| +                   status)); | 
| +    return; | 
| +  } | 
| + | 
| +  // Find one with an exact matching scope. | 
| +  ServiceWorkerDatabase::RegistrationData data; | 
| +  ResourceList resources; | 
| +  status = ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND; | 
| +  for (RegistrationList::const_iterator it = registrations.begin(); | 
| +       it != registrations.end(); ++it) { | 
| +    if (scope != it->scope) | 
| +      continue; | 
| +    status = database->ReadRegistration(it->registration_id, origin, | 
| +                                        &data, &resources); | 
| +    break;  // We're done looping. | 
| +  } | 
| + | 
| +  original_task_runner->PostTask( | 
| +      FROM_HERE, | 
| +      base::Bind(callback, data, resources, status)); | 
| +} | 
| + | 
| +void ServiceWorkerStorage::FindForIdInDB( | 
| +    ServiceWorkerDatabase* database, | 
| +    scoped_refptr<base::SequencedTaskRunner> original_task_runner, | 
| +    int64 registration_id, | 
| +    const GURL& origin, | 
| +    const FindInDBCallback& callback) { | 
| +  ServiceWorkerDatabase::RegistrationData data; | 
| +  ResourceList resources; | 
| +  ServiceWorkerDatabase::Status status = | 
| +      database->ReadRegistration(registration_id, origin, &data, &resources); | 
| +  original_task_runner->PostTask( | 
| +      FROM_HERE, base::Bind(callback, data, resources, status)); | 
| +} | 
| + | 
| }  // namespace content | 
|  |