Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / webkit / browser / appcache / appcache_storage_impl.cc
index e0d0263..d470166 100644 (file)
@@ -174,7 +174,7 @@ class AppCacheStorageImpl::DatabaseTask
  private:
   void CallRun(base::TimeTicks schedule_time);
   void CallRunCompleted(base::TimeTicks schedule_time);
-  void CallDisableStorage();
+  void OnFatalError();
 
   scoped_refptr<base::MessageLoopProxy> io_thread_;
 };
@@ -209,10 +209,15 @@ void AppCacheStorageImpl::DatabaseTask::CallRun(
     Run();
     AppCacheHistograms::AddTaskRunTimeSample(
         base::TimeTicks::Now() - run_time);
+
+    if (database_->was_corruption_detected()) {
+      AppCacheHistograms::CountCorruptionDetected();
+      database_->Disable();
+    }
     if (database_->is_disabled()) {
       io_thread_->PostTask(
           FROM_HERE,
-          base::Bind(&DatabaseTask::CallDisableStorage, this));
+          base::Bind(&DatabaseTask::OnFatalError, this));
     }
   }
   io_thread_->PostTask(
@@ -237,10 +242,11 @@ void AppCacheStorageImpl::DatabaseTask::CallRunCompleted(
   }
 }
 
-void AppCacheStorageImpl::DatabaseTask::CallDisableStorage() {
+void AppCacheStorageImpl::DatabaseTask::OnFatalError() {
   if (storage_) {
     DCHECK(io_thread_->BelongsToCurrentThread());
     storage_->Disable();
+    storage_->DeleteAndStartOver();
   }
 }
 
@@ -251,7 +257,14 @@ class AppCacheStorageImpl::InitTask : public DatabaseTask {
   explicit InitTask(AppCacheStorageImpl* storage)
       : DatabaseTask(storage), last_group_id_(0),
         last_cache_id_(0), last_response_id_(0),
-        last_deletable_response_rowid_(0) {}
+        last_deletable_response_rowid_(0) {
+    if (!storage->is_incognito_) {
+      db_file_path_ =
+          storage->cache_directory_.Append(kAppCacheDatabaseName);
+      disk_cache_directory_ =
+          storage->cache_directory_.Append(kDiskCacheDirectoryName);
+    }
+  }
 
   // DatabaseTask:
   virtual void Run() OVERRIDE;
@@ -261,6 +274,8 @@ class AppCacheStorageImpl::InitTask : public DatabaseTask {
   virtual ~InitTask() {}
 
  private:
+  base::FilePath db_file_path_;
+  base::FilePath disk_cache_directory_;
   int64 last_group_id_;
   int64 last_cache_id_;
   int64 last_response_id_;
@@ -269,6 +284,17 @@ class AppCacheStorageImpl::InitTask : public DatabaseTask {
 };
 
 void AppCacheStorageImpl::InitTask::Run() {
+  // If there is no sql database, ensure there is no disk cache either.
+  if (!db_file_path_.empty() &&
+      !base::PathExists(db_file_path_) &&
+      base::DirectoryExists(disk_cache_directory_)) {
+    base::DeleteFile(disk_cache_directory_, true);
+    if (base::DirectoryExists(disk_cache_directory_)) {
+      database_->Disable();  // This triggers OnFatalError handling.
+      return;
+    }
+  }
+
   database_->FindLastStorageIds(
       &last_group_id_, &last_cache_id_, &last_response_id_,
       &last_deletable_response_rowid_);
@@ -913,8 +939,6 @@ class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask {
   GURL manifest_url_;
 };
 
-
-
 void AppCacheStorageImpl::FindMainResponseTask::Run() {
   // NOTE: The heuristics around choosing amoungst multiple candidates
   // is underspecified, and just plain not fully understood. This needs
@@ -1793,9 +1817,6 @@ AppCacheDiskCache* AppCacheStorageImpl::disk_cache() {
                      base::Unretained(this)));
     }
 
-    // We should not keep this reference around.
-    cache_thread_ = NULL;
-
     if (rv != net::ERR_IO_PENDING)
       OnDiskCacheInitialized(rv);
   }
@@ -1811,21 +1832,38 @@ void AppCacheStorageImpl::OnDiskCacheInitialized(int rv) {
     // really recover from. We handle it by temporarily disabling the appcache
     // deleting the directory on disk and reinitializing the appcache system.
     Disable();
-    if (!is_incognito_ && rv != net::ERR_ABORTED) {
-      VLOG(1) << "Deleting existing appcache data and starting over.";
-      db_thread_->PostTaskAndReply(
-          FROM_HERE,
-          base::Bind(base::IgnoreResult(&base::DeleteFile),
-                     cache_directory_, true),
-          base::Bind(&AppCacheStorageImpl::CallReinitialize,
-                     weak_factory_.GetWeakPtr()));
-    }
+    if (rv != net::ERR_ABORTED)
+      DeleteAndStartOver();
+  }
+}
+
+void AppCacheStorageImpl::DeleteAndStartOver() {
+  DCHECK(is_disabled_);
+  if (!is_incognito_) {
+    VLOG(1) << "Deleting existing appcache data and starting over.";
+    // We can have tasks in flight to close file handles on both the db
+    // and cache threads, we need to allow those tasks to cycle thru
+    // prior to deleting the files and calling reinit.
+    cache_thread_->PostTaskAndReply(
+        FROM_HERE,
+        base::Bind(&base::DoNothing),
+        base::Bind(&AppCacheStorageImpl::DeleteAndStartOverPart2,
+                   weak_factory_.GetWeakPtr()));
   }
 }
 
-void AppCacheStorageImpl::CallReinitialize() {
-  service_->Reinitialize();
-  // note: 'this' may be deleted during reinit.
+void AppCacheStorageImpl::DeleteAndStartOverPart2() {
+  db_thread_->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(&base::DeleteFile),
+                 cache_directory_, true),
+      base::Bind(&AppCacheStorageImpl::CallScheduleReinitialize,
+                  weak_factory_.GetWeakPtr()));
+}
+
+void AppCacheStorageImpl::CallScheduleReinitialize() {
+  service_->ScheduleReinitialize();
+  // note: 'this' may be deleted at this point.
 }
 
 }  // namespace appcache