 Chromium Code Reviews
 Chromium Code Reviews Issue 9663021:
  Add database recovery for FileSystemOriginDatabase  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 9663021:
  Add database recovery for FileSystemOriginDatabase  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| Index: webkit/fileapi/file_system_origin_database.cc | 
| diff --git a/webkit/fileapi/file_system_origin_database.cc b/webkit/fileapi/file_system_origin_database.cc | 
| index 125576ae38d1eda4f7dfeae35a63059f1b326c06..fd7a13a1e214e439a84309f54d89cf33376e3564 100644 | 
| --- a/webkit/fileapi/file_system_origin_database.cc | 
| +++ b/webkit/fileapi/file_system_origin_database.cc | 
| @@ -4,21 +4,43 @@ | 
| #include "webkit/fileapi/file_system_origin_database.h" | 
| +#include "base/file_util.h" | 
| #include "base/format_macros.h" | 
| #include "base/location.h" | 
| #include "base/logging.h" | 
| #include "base/string_number_conversions.h" | 
| #include "base/stringprintf.h" | 
| #include "base/string_util.h" | 
| -#include "base/sys_string_conversions.h" | 
| +#include "base/utf_string_conversions.h" | 
| #include "third_party/leveldatabase/src/include/leveldb/iterator.h" | 
| #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 
| namespace { | 
| +const FilePath::CharType kOriginDatabaseName[] = FILE_PATH_LITERAL("Origins"); | 
| const char kOriginKeyPrefix[] = "ORIGIN:"; | 
| const char kLastPathKey[] = "LAST_PATH"; | 
| +std::string FilePathToString(const FilePath& path) { | 
| + // TODO(tzik): Unify this to FilePathToString in | 
| + // third_party/leveldatabase/env_chromium.cc. | 
| +#if defined(OS_WIN) | 
| + return UTF16ToUTF8(path.value()); | 
| +#elif defined(OS_POSIX) | 
| + return path.value(); | 
| +#endif | 
| +} | 
| + | 
| +FilePath StringToFilePath(const std::string& path_string) { | 
| + // TODO(tzik): Unify this to CreateFilePath in | 
| + // third_party/leveldatabase/env_chromium.cc. | 
| +#if defined(OS_WIN) | 
| + return FilePath(UTF8ToUTF16(path_string)); | 
| +#elif defined(OS_POSIX) | 
| + return FilePath(path_string); | 
| +#endif | 
| +} | 
| + | 
| std::string OriginToOriginKey(const std::string& origin) { | 
| std::string key(kOriginKeyPrefix); | 
| return key + origin; | 
| @@ -43,31 +65,105 @@ FileSystemOriginDatabase::OriginRecord::OriginRecord( | 
| FileSystemOriginDatabase::OriginRecord::~OriginRecord() { | 
| } | 
| -FileSystemOriginDatabase::FileSystemOriginDatabase(const FilePath& path) { | 
| -#if defined(OS_POSIX) | 
| - path_ = path.value(); | 
| -#elif defined(OS_WIN) | 
| - path_ = base::SysWideToUTF8(path.value()); | 
| -#endif | 
| +FileSystemOriginDatabase::FileSystemOriginDatabase( | 
| + const FilePath& file_system_directory) | 
| + : file_system_directory_(file_system_directory) { | 
| } | 
| FileSystemOriginDatabase::~FileSystemOriginDatabase() { | 
| } | 
| -bool FileSystemOriginDatabase::Init() { | 
| +bool FileSystemOriginDatabase::Init(RecoveryOption recovery_option) { | 
| if (db_.get()) | 
| return true; | 
| + std::string path = | 
| + FilePathToString(file_system_directory_.Append(kOriginDatabaseName)); | 
| leveldb::Options options; | 
| options.create_if_missing = true; | 
| leveldb::DB* db; | 
| - leveldb::Status status = leveldb::DB::Open(options, path_, &db); | 
| + leveldb::Status status = leveldb::DB::Open(options, path, &db); | 
| + // TODO(tzik): Collect status metrics here. | 
| if (status.ok()) { | 
| db_.reset(db); | 
| return true; | 
| } | 
| HandleError(FROM_HERE, status); | 
| - return false; | 
| + | 
| + if (recovery_option == FAIL_ON_CORRUPTION) | 
| + return false; | 
| + | 
| + if (recovery_option == REPAIR_ON_CORRUPTION) { | 
| + LOG(WARNING) << "Attempting to repair FileSystemOriginDatabase."; | 
| + if (RepairDatabase(path)) { | 
| + LOG(WARNING) << "Repairing FileSystemOriginDatabase completed."; | 
| + return true; | 
| + } | 
| + } | 
| + | 
| + DCHECK(DELETE_ON_CORRUPTION == recovery_option || | 
| + REPAIR_ON_CORRUPTION == recovery_option); | 
| + if (!file_util::Delete(file_system_directory_, true)) | 
| + return false; | 
| + if (!file_util::CreateDirectory(file_system_directory_)) | 
| + return false; | 
| + | 
| 
kinuko
2012/03/26 05:25:09
The lines 93-110 might look easier to follow in sw
 
tzik
2012/03/26 08:04:56
Done.
 | 
| + return Init(FAIL_ON_CORRUPTION); | 
| +} | 
| + | 
| +bool FileSystemOriginDatabase::RepairDatabase(const std::string& db_path) { | 
| + DCHECK(!db_.get()); | 
| + if (!leveldb::RepairDB(db_path, leveldb::Options()).ok() || | 
| + !Init(FAIL_ON_CORRUPTION)) { | 
| + LOG(WARNING) << "Failed to repair FileSystemOriginDatabase."; | 
| + return false; | 
| + } | 
| + | 
| + // See if the repaired entries match with what we have on disk. | 
| + std::set<FilePath> directories; | 
| + file_util::FileEnumerator file_enum(file_system_directory_, | 
| + false /* recursive */, | 
| + file_util::FileEnumerator::DIRECTORIES); | 
| + FilePath path_each; | 
| + while (!(path_each = file_enum.Next()).empty()) | 
| + directories.insert(path_each.BaseName()); | 
| + std::set<FilePath>::iterator db_dir_itr = | 
| + directories.find(FilePath(kOriginDatabaseName)); | 
| + DCHECK(db_dir_itr != directories.end()); | 
| + directories.erase(db_dir_itr); | 
| + | 
| + std::vector<OriginRecord> origins; | 
| + if (!ListAllOrigins(&origins)) { | 
| + DropDatabase(); | 
| + return false; | 
| + } | 
| + for (std::vector<OriginRecord>::iterator db_origin_itr = origins.begin(); | 
| + db_origin_itr != origins.end(); | 
| + ++db_origin_itr) { | 
| + std::set<FilePath>::iterator dir_itr = | 
| + directories.find(db_origin_itr->path); | 
| + if (dir_itr == directories.end()) { | 
| + if (!RemovePathForOrigin(db_origin_itr->origin)) { | 
| + DropDatabase(); | 
| + return false; | 
| + } | 
| + } else { | 
| + directories.erase(dir_itr); | 
| + } | 
| + } | 
| + | 
| + // Delete any directories not listed in the origins database. | 
| + for (std::set<FilePath>::iterator dir_itr = directories.begin(); | 
| + dir_itr != directories.end(); | 
| + ++dir_itr) { | 
| + if (!file_util::Delete(file_system_directory_.Append(*dir_itr), | 
| + true /* recursive */)) { | 
| + DropDatabase(); | 
| + return false; | 
| + } | 
| + } | 
| + | 
| + return true; | 
| } | 
| void FileSystemOriginDatabase::HandleError( | 
| @@ -78,7 +174,7 @@ void FileSystemOriginDatabase::HandleError( | 
| } | 
| bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) { | 
| - if (!Init()) | 
| + if (!Init(REPAIR_ON_CORRUPTION)) | 
| return false; | 
| if (origin.empty()) | 
| return false; | 
| @@ -95,7 +191,7 @@ bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) { | 
| bool FileSystemOriginDatabase::GetPathForOrigin( | 
| const std::string& origin, FilePath* directory) { | 
| - if (!Init()) | 
| + if (!Init(REPAIR_ON_CORRUPTION)) | 
| return false; | 
| DCHECK(directory); | 
| if (origin.empty()) | 
| @@ -120,11 +216,7 @@ bool FileSystemOriginDatabase::GetPathForOrigin( | 
| } | 
| } | 
| if (status.ok()) { | 
| -#if defined(OS_POSIX) | 
| - *directory = FilePath(path_string); | 
| -#elif defined(OS_WIN) | 
| - *directory = FilePath(base::SysUTF8ToWide(path_string)); | 
| -#endif | 
| + *directory = StringToFilePath(path_string); | 
| return true; | 
| } | 
| HandleError(FROM_HERE, status); | 
| @@ -132,7 +224,7 @@ bool FileSystemOriginDatabase::GetPathForOrigin( | 
| } | 
| bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) { | 
| - if (!Init()) | 
| + if (!Init(REPAIR_ON_CORRUPTION)) | 
| return false; | 
| leveldb::Status status = | 
| db_->Delete(leveldb::WriteOptions(), OriginToOriginKey(origin)); | 
| @@ -144,7 +236,7 @@ bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) { | 
| bool FileSystemOriginDatabase::ListAllOrigins( | 
| std::vector<OriginRecord>* origins) { | 
| - if (!Init()) | 
| + if (!Init(REPAIR_ON_CORRUPTION)) | 
| return false; | 
| DCHECK(origins); | 
| scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); | 
| @@ -155,11 +247,7 @@ bool FileSystemOriginDatabase::ListAllOrigins( | 
| StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) { | 
| std::string origin = | 
| iter->key().ToString().substr(origin_key_prefix.length()); | 
| -#if defined(OS_POSIX) | 
| - FilePath path = FilePath(iter->value().ToString()); | 
| -#elif defined(OS_WIN) | 
| - FilePath path = FilePath(base::SysUTF8ToWide(iter->value().ToString())); | 
| -#endif | 
| + FilePath path = StringToFilePath(iter->value().ToString()); | 
| origins->push_back(OriginRecord(origin, path)); | 
| iter->Next(); | 
| } | 
| @@ -171,7 +259,7 @@ void FileSystemOriginDatabase::DropDatabase() { | 
| } | 
| bool FileSystemOriginDatabase::GetLastPathNumber(int* number) { | 
| - if (!Init()) | 
| + if (!Init(REPAIR_ON_CORRUPTION)) | 
| return false; | 
| DCHECK(number); | 
| std::string number_string; |