drive: Use title recovered from trashed DB when DB corruption happens
Add ResourceMetadataStorage::RecoveredCacheInfo
Recover title in ResourceMetadataStorage::RecoverCacheInfoFromTrashedResourceMap
Use title in FileCache::RecoverFilesFromCacheDirectory
BUG=277333
TEST=unit_tests
Review URL: https://codereview.chromium.org/55713002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232980 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index aae5cf2..b5bdb7c 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -143,14 +143,15 @@
.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier));
}
- std::map<std::string, FileCacheEntry> recovered_cache_entries;
- metadata_storage->RecoverCacheEntriesFromTrashedResourceMap(
- &recovered_cache_entries);
+ internal::ResourceMetadataStorage::RecoveredCacheInfoMap
+ recovered_cache_info;
+ metadata_storage->RecoverCacheInfoFromTrashedResourceMap(
+ &recovered_cache_info);
LOG(INFO) << "DB could not be opened for some reasons. "
<< "Recovering cache files to " << dest_directory.value();
if (!cache->RecoverFilesFromCacheDirectory(dest_directory,
- recovered_cache_entries)) {
+ recovered_cache_info)) {
LOG(WARNING) << "Failed to recover cache files.";
return FILE_ERROR_FAILED;
}
diff --git a/chrome/browser/chromeos/drive/file_cache.cc b/chrome/browser/chromeos/drive/file_cache.cc
index 05448b5..f5c6751 100644
--- a/chrome/browser/chromeos/drive/file_cache.cc
+++ b/chrome/browser/chromeos/drive/file_cache.cc
@@ -395,7 +395,8 @@
bool FileCache::RecoverFilesFromCacheDirectory(
const base::FilePath& dest_directory,
- const std::map<std::string, FileCacheEntry>& recovered_cache_entries) {
+ const ResourceMetadataStorage::RecoveredCacheInfoMap&
+ recovered_cache_info) {
int file_number = 1;
base::FileEnumerator enumerator(cache_file_directory_,
@@ -413,14 +414,13 @@
// If a cache entry which is non-dirty and has matching MD5 is found in
// |recovered_cache_entries|, it means the current file is already uploaded
// to the server. Just delete it instead of recovering it.
- std::map<std::string, FileCacheEntry>::const_iterator it =
- recovered_cache_entries.find(id);
- if (it != recovered_cache_entries.end()) {
- const FileCacheEntry& recovered_entry = it->second;
- // Due to the DB corruption, |recovered_entry| might be recovered from old
- // revision. Perform MD5 check even when is_dirty() is false just in case.
- if (!recovered_entry.is_dirty() &&
- recovered_entry.md5() == util::GetMd5Digest(current)) {
+ ResourceMetadataStorage::RecoveredCacheInfoMap::const_iterator it =
+ recovered_cache_info.find(id);
+ if (it != recovered_cache_info.end()) {
+ // Due to the DB corruption, cache info might be recovered from old
+ // revision. Perform MD5 check even when is_dirty is false just in case.
+ if (!it->second.is_dirty &&
+ it->second.md5 == util::GetMd5Digest(current)) {
base::DeleteFile(current, false /* recursive */);
continue;
}
@@ -437,13 +437,18 @@
if (read_result == 0) // Skip empty files.
continue;
- // Decide file name with sniffed mime type.
+ // Use recovered file name if available, otherwise decide file name with
+ // sniffed mime type.
base::FilePath dest_base_name(FILE_PATH_LITERAL("file"));
std::string mime_type;
- if (net::SniffMimeType(&content[0], read_result,
- net::FilePathToFileURL(current), std::string(),
- &mime_type) ||
- net::SniffMimeTypeFromLocalData(&content[0], read_result, &mime_type)) {
+ if (it != recovered_cache_info.end() && !it->second.title.empty()) {
+ // We can use a file name recovered from the trashed DB.
+ dest_base_name = base::FilePath::FromUTF8Unsafe(it->second.title);
+ } else if (net::SniffMimeType(&content[0], read_result,
+ net::FilePathToFileURL(current),
+ std::string(), &mime_type) ||
+ net::SniffMimeTypeFromLocalData(&content[0], read_result,
+ &mime_type)) {
// Change base name for common mime types.
if (net::MatchesMimeType("image/*", mime_type)) {
dest_base_name = base::FilePath(FILE_PATH_LITERAL("image"));
diff --git a/chrome/browser/chromeos/drive/file_cache.h b/chrome/browser/chromeos/drive/file_cache.h
index 1127ec99..cc595372 100644
--- a/chrome/browser/chromeos/drive/file_cache.h
+++ b/chrome/browser/chromeos/drive/file_cache.h
@@ -157,11 +157,12 @@
// Moves files in the cache directory which are not manged by FileCache to
// |dest_directory|.
- // |recovered_cache_entries| should contain cache entries recovered from the
- // trashed metadata DB. It is used to ignore non-dirty files.
+ // |recovered_cache_info| should contain cache info recovered from the trashed
+ // metadata DB. It is used to ignore non-dirty files.
bool RecoverFilesFromCacheDirectory(
const base::FilePath& dest_directory,
- const std::map<std::string, FileCacheEntry>& recovered_cache_entries);
+ const ResourceMetadataStorage::RecoveredCacheInfoMap&
+ recovered_cache_info);
private:
friend class FileCacheTest;
diff --git a/chrome/browser/chromeos/drive/file_cache_unittest.cc b/chrome/browser/chromeos/drive/file_cache_unittest.cc
index 493fe0f2..23a6149 100644
--- a/chrome/browser/chromeos/drive/file_cache_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_cache_unittest.cc
@@ -768,23 +768,37 @@
ASSERT_TRUE(base::CopyFile(src_path, file_directory.AppendASCII("id_bar")));
ASSERT_TRUE(base::CopyFile(src_path, file_directory.AppendASCII("id_baz")));
- // Insert a dirty entry with "id_baz" to |recovered_cache_entries|.
+ // Insert a dirty entry with "id_baz" to |recovered_cache_info|.
// This should not prevent the file from being recovered.
- std::map<std::string, FileCacheEntry> recovered_cache_entries;
- recovered_cache_entries["id_baz"].set_is_dirty(true);
+ ResourceMetadataStorage::RecoveredCacheInfoMap recovered_cache_info;
+ recovered_cache_info["id_baz"].is_dirty = true;
+ recovered_cache_info["id_baz"].title = "baz.png";
// Recover files.
const base::FilePath dest_directory = temp_dir_.path().AppendASCII("dest");
EXPECT_TRUE(cache_->RecoverFilesFromCacheDirectory(dest_directory,
- recovered_cache_entries));
+ recovered_cache_info));
// Only two files should be recovered.
EXPECT_TRUE(base::PathExists(dest_directory));
- EXPECT_TRUE(base::ContentsEqual(src_path,
- dest_directory.Append("image00000001.png")));
- EXPECT_TRUE(base::ContentsEqual(src_path,
- dest_directory.Append("image00000002.png")));
- EXPECT_FALSE(base::PathExists(dest_directory.Append("image00000003.png")));
+ // base::FileEnumerator does not guarantee the order.
+ if (base::PathExists(dest_directory.AppendASCII("baz00000001.png"))) {
+ EXPECT_TRUE(base::ContentsEqual(
+ src_path,
+ dest_directory.AppendASCII("baz00000001.png")));
+ EXPECT_TRUE(base::ContentsEqual(
+ src_path,
+ dest_directory.AppendASCII("image00000002.png")));
+ } else {
+ EXPECT_TRUE(base::ContentsEqual(
+ src_path,
+ dest_directory.AppendASCII("image00000001.png")));
+ EXPECT_TRUE(base::ContentsEqual(
+ src_path,
+ dest_directory.AppendASCII("baz00000002.png")));
+ }
+ EXPECT_FALSE(base::PathExists(
+ dest_directory.AppendASCII("image00000003.png")));
}
TEST_F(FileCacheTest, Iterator) {
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.cc b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
index d07dbffb..f3b61a6 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
@@ -477,8 +477,8 @@
return resource_map_;
}
-void ResourceMetadataStorage::RecoverCacheEntriesFromTrashedResourceMap(
- std::map<std::string, FileCacheEntry>* out_entries) {
+void ResourceMetadataStorage::RecoverCacheInfoFromTrashedResourceMap(
+ RecoveredCacheInfoMap* out_info) {
const base::FilePath trashed_resource_map_path =
directory_path_.Append(kTrashedResourceMapDBName);
@@ -526,8 +526,20 @@
if (IsCacheEntryKey(it->key())) {
const std::string& id = GetIdFromCacheEntryKey(it->key());
FileCacheEntry cache_entry;
- if (cache_entry.ParseFromArray(it->value().data(), it->value().size()))
- (*out_entries)[id] = cache_entry;
+ if (cache_entry.ParseFromArray(it->value().data(), it->value().size())) {
+ RecoveredCacheInfo* info = &(*out_info)[id];
+ info->is_dirty = cache_entry.is_dirty();
+ info->md5 = cache_entry.md5();
+
+ // Get title from ResourceEntry if available.
+ std::string serialized_entry;
+ ResourceEntry entry;
+ if (resource_map->Get(leveldb::ReadOptions(),
+ leveldb::Slice(id),
+ &serialized_entry).ok() &&
+ entry.ParseFromString(serialized_entry))
+ info->title = entry.title();
+ }
}
}
}
@@ -734,6 +746,11 @@
return make_scoped_ptr(new CacheEntryIterator(it.Pass()));
}
+ResourceMetadataStorage::RecoveredCacheInfo::RecoveredCacheInfo()
+ : is_dirty(false) {}
+
+ResourceMetadataStorage::RecoveredCacheInfo::~RecoveredCacheInfo() {}
+
bool ResourceMetadataStorage::GetIdByResourceId(
const std::string& resource_id,
std::string* out_id) {
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.h b/chrome/browser/chromeos/drive/resource_metadata_storage.h
index a6d3868..6ab0159 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.h
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.h
@@ -105,6 +105,17 @@
DISALLOW_COPY_AND_ASSIGN(CacheEntryIterator);
};
+ // Cache information recovered from trashed DB.
+ struct RecoveredCacheInfo {
+ RecoveredCacheInfo();
+ ~RecoveredCacheInfo();
+
+ bool is_dirty;
+ std::string md5;
+ std::string title;
+ };
+ typedef std::map<std::string, RecoveredCacheInfo> RecoveredCacheInfoMap;
+
// Returns true if the DB was successfully upgraded to the newest version.
static bool UpgradeOldDB(const base::FilePath& directory_path,
const ResourceIdCanonicalizer& id_canonicalizer);
@@ -124,9 +135,8 @@
// Initializes this object.
bool Initialize();
- // Collects FileCacheEntry from trashed resource map DB.
- void RecoverCacheEntriesFromTrashedResourceMap(
- std::map<std::string, FileCacheEntry>* out_entries);
+ // Collects cache info from trashed resource map DB.
+ void RecoverCacheInfoFromTrashedResourceMap(RecoveredCacheInfoMap* out_info);
// Sets the largest changestamp.
bool SetLargestChangestamp(int64 largest_changestamp);
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
index 865b7d13..0094c31e 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
@@ -446,18 +446,21 @@
cache_entry.set_md5("md5_foo");
EXPECT_TRUE(storage_->PutCacheEntry("id_foo", cache_entry));
cache_entry.set_md5("md5_bar");
+ cache_entry.set_is_dirty(true);
EXPECT_TRUE(storage_->PutCacheEntry("id_bar", cache_entry));
// Put entry with id_foo.
ResourceEntry entry;
entry.set_local_id("id_foo");
entry.set_base_name("foo");
+ entry.set_title("foo");
EXPECT_TRUE(storage_->PutEntry(entry));
// Put entry with id_bar as a id_foo's child.
entry.set_local_id("id_bar");
entry.set_parent_local_id("id_foo");
entry.set_base_name("bar");
+ entry.set_title("bar");
EXPECT_TRUE(storage_->PutEntry(entry));
// Remove parent-child relationship to make the DB invalid.
@@ -470,11 +473,15 @@
ASSERT_TRUE(storage_->Initialize());
// Recover cache entries from the trashed DB.
- std::map<std::string, FileCacheEntry> recovered_cache_entries;
- storage_->RecoverCacheEntriesFromTrashedResourceMap(&recovered_cache_entries);
- EXPECT_EQ(2U, recovered_cache_entries.size());
- EXPECT_EQ("md5_foo", recovered_cache_entries["id_foo"].md5());
- EXPECT_EQ("md5_bar", recovered_cache_entries["id_bar"].md5());
+ ResourceMetadataStorage::RecoveredCacheInfoMap recovered_cache_info;
+ storage_->RecoverCacheInfoFromTrashedResourceMap(&recovered_cache_info);
+ EXPECT_EQ(2U, recovered_cache_info.size());
+ EXPECT_FALSE(recovered_cache_info["id_foo"].is_dirty);
+ EXPECT_EQ("md5_foo", recovered_cache_info["id_foo"].md5);
+ EXPECT_EQ("foo", recovered_cache_info["id_foo"].title);
+ EXPECT_TRUE(recovered_cache_info["id_bar"].is_dirty);
+ EXPECT_EQ("md5_bar", recovered_cache_info["id_bar"].md5);
+ EXPECT_EQ("bar", recovered_cache_info["id_bar"].title);
}
TEST_F(ResourceMetadataStorageTest, CheckValidity) {