Chromium Code Reviews| Index: chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc |
| diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc |
| index f4c32af6d75b525a36fbfe849e6c0eb7e91245d6..096338ad3719a6aacaa9cfb17f6abc6cd3d2c2df 100644 |
| --- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc |
| +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc |
| @@ -140,6 +140,110 @@ std::string GenerateDemotedDirtyIDKey(int64 tracker_id) { |
| return kDemotedDirtyIDKeyPrefix + base::Int64ToString(tracker_id); |
| } |
| +void RemoveUnreachableItems(LevelDBWrapper* db) { |
| + DCHECK(db); |
| + |
| + typedef std::map<int64, std::set<int64> > ChildTrackersByParent; |
| + ChildTrackersByParent trackers_by_parent; |
| + { |
| + // Set up links from parent tracker to child trackers. |
| + std::set<int64> inactive_trackers; |
| + scoped_ptr<LevelDBWrapper::Iterator> itr = db->NewIterator(); |
| + for (itr->Seek(kFileTrackerKeyPrefix); itr->Valid(); itr->Next()) { |
| + if (!RemovePrefix(itr->key().ToString(), kFileTrackerKeyPrefix, NULL)) |
| + break; |
| + |
| + scoped_ptr<FileTracker> tracker(new FileTracker); |
| + if (!tracker->ParseFromString(itr->value().ToString())) { |
| + util::Log(logging::LOG_WARNING, FROM_HERE, |
| + "Failed to parse a Tracker"); |
| + continue; |
| + } |
| + |
| + int64 parent_tracker_id = tracker->parent_tracker_id(); |
| + int64 tracker_id = tracker->tracker_id(); |
| + trackers_by_parent[parent_tracker_id].insert(tracker_id); |
| + if (!tracker->active()) |
| + inactive_trackers.insert(tracker_id); |
| + } |
| + |
| + // Drop links from inactive trackers. |
| + for (std::set<int64>::iterator iter = inactive_trackers.begin(); |
| + iter != inactive_trackers.end(); ++iter) { |
| + trackers_by_parent.erase(*iter); |
| + } |
| + } |
| + |
| + // Traverse tracker tree from sync-root. |
| + std::set<int64> visited_trackers; |
| + { |
| + scoped_ptr<ServiceMetadata> service_metadata = |
| + InitializeServiceMetadata(db); |
| + int64 sync_root_tracker_id = service_metadata->sync_root_tracker_id(); |
| + std::vector<int64> pending; |
| + if (sync_root_tracker_id != kInvalidTrackerID) |
| + pending.push_back(sync_root_tracker_id); |
| + |
| + while (!pending.empty()) { |
| + int64 tracker_id = pending.back(); |
| + DCHECK_NE(kInvalidTrackerID, tracker_id); |
| + pending.pop_back(); |
| + |
| + if (!visited_trackers.insert(tracker_id).second) { |
| + NOTREACHED(); |
| + continue; |
| + } |
| + |
| + AppendContents( |
| + LookUpMap(trackers_by_parent, tracker_id, std::set<int64>()), |
| + &pending); |
| + } |
| + } |
| + |
| + // Delete all unreachable trackers, and list all |file_id| referred by |
| + // remained trackers. |
| + base::hash_set<std::string> referred_file_ids; |
| + { |
| + scoped_ptr<LevelDBWrapper::Iterator> itr = db->NewIterator(); |
| + for (itr->Seek(kFileTrackerKeyPrefix); itr->Valid(); itr->Next()) { |
| + if (!RemovePrefix(itr->key().ToString(), kFileTrackerKeyPrefix, NULL)) |
| + break; |
| + |
| + scoped_ptr<FileTracker> tracker(new FileTracker); |
| + if (!tracker->ParseFromString(itr->value().ToString())) { |
| + util::Log(logging::LOG_WARNING, FROM_HERE, |
| + "Failed to parse a Tracker"); |
| + continue; |
| + } |
| + |
| + if (ContainsKey(visited_trackers, tracker->tracker_id())) { |
| + referred_file_ids.insert(tracker->file_id()); |
| + } else { |
| + PutFileTrackerDeletionToDB(tracker->tracker_id(), db); |
| + } |
| + } |
| + } |
| + |
| + // Delete all unreferred metadata. |
| + { |
| + scoped_ptr<LevelDBWrapper::Iterator> itr = db->NewIterator(); |
| + for (itr->Seek(kFileMetadataKeyPrefix); itr->Valid(); itr->Next()) { |
| + if (!RemovePrefix(itr->key().ToString(), kFileMetadataKeyPrefix, NULL)) |
| + break; |
| + |
| + scoped_ptr<FileMetadata> metadata(new FileMetadata); |
| + if (!metadata->ParseFromString(itr->value().ToString())) { |
| + util::Log(logging::LOG_WARNING, FROM_HERE, |
| + "Failed to parse a Tracker"); |
| + continue; |
| + } |
| + |
| + if (!ContainsKey(referred_file_ids, metadata->file_id())) |
| + PutFileMetadataDeletionToDB(metadata->file_id(), db); |
| + } |
| + } |
| +} |
| + |
| } // namespace |
| // static |
| @@ -148,6 +252,9 @@ MetadataDatabaseIndexOnDisk::Create(LevelDBWrapper* db) { |
| DCHECK(db); |
| PutVersionToDB(kDatabaseOnDiskVersion, db); |
| + // TODO(peria): It is not good to call RemoveUnreachableItems on every |
| + // creation. |
| + RemoveUnreachableItems(db); |
| scoped_ptr<MetadataDatabaseIndexOnDisk> |
| index(new MetadataDatabaseIndexOnDisk(db)); |
|
nhiroki
2014/08/05 07:19:16
When is |db| committed?
peria
2014/08/05 07:35:59
It is handled by MetadataDatabase class.
This clas
nhiroki
2014/08/05 09:21:50
I see, thanks!
|
| return index.Pass(); |
| @@ -573,6 +680,10 @@ void MetadataDatabaseIndexOnDisk::BuildTrackerIndexes() { |
| } |
| } |
| +LevelDBWrapper* MetadataDatabaseIndexOnDisk::GetDBForTesting() { |
| + return db_; |
| +} |
| + |
| MetadataDatabaseIndexOnDisk::MetadataDatabaseIndexOnDisk(LevelDBWrapper* db) |
| : db_(db) { |
| // TODO(peria): Add UMA to measure the number of FileMetadata, FileTracker, |