private:
void CallRun(base::TimeTicks schedule_time);
void CallRunCompleted(base::TimeTicks schedule_time);
- void CallDisableStorage();
+ void OnFatalError();
scoped_refptr<base::MessageLoopProxy> io_thread_;
};
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(
}
}
-void AppCacheStorageImpl::DatabaseTask::CallDisableStorage() {
+void AppCacheStorageImpl::DatabaseTask::OnFatalError() {
if (storage_) {
DCHECK(io_thread_->BelongsToCurrentThread());
storage_->Disable();
+ storage_->DeleteAndStartOver();
}
}
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;
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_;
};
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_);
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
base::Unretained(this)));
}
- // We should not keep this reference around.
- cache_thread_ = NULL;
-
if (rv != net::ERR_IO_PENDING)
OnDiskCacheInitialized(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