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 f87cf36e45daca86ef50e5bdefb152bc726acd27..d8cf321364e2bf2f8ecabd681296e703cad82bd4 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 |
@@ -50,19 +50,27 @@ |
// value: <int64 'active_tracker_id'> |
// |
// # Index from file ID to a tracker ID |
-// key: "IDS_BY_FILE: " + <string 'file_id'> + '\x00' + <int64 'tracker_id'> |
+// key: "TRACKER_FILE: " + <string 'file_id'> + '\x00' + <int64 'tracker_id'> |
+// value: <empty> |
+// |
+// # Tracker IDs; a file metadata linked to multiple tracker IDs. |
+// key: "MULTI_FILE: " + <int64 'tracker_id'> |
// value: <empty> |
// |
// # Index from the parent tracker ID and the title to the active tracker ID |
-// key: "ACTIVE_BY_PATH_INDEX: " + <int64 'parent_tracker_id'> + |
+// key: "ACTIVE_PATH: " + <int64 'parent_tracker_id'> + |
// '\x00' + <string 'title'> |
// value: <int64 'active_tracker_id'> |
// |
// # Index from the parent tracker ID and the title to a tracker ID |
-// key: "IDS_BY_PATH_INDEX: " + <int64 'parent_tracker_id'> + |
+// key: "TRACKER_PATH: " + <int64 'parent_tracker_id'> + |
// '\x00' + <string 'title'> + '\x00' + <int64 'tracker_id'> |
// value: <empty> |
// |
+// # Tracker IDs; a parent tracker ID and a title figure multiple tracker IDs |
+// key: "MULTI_PATH: " + <int64 'tracker_id'> |
+// value: <empty> |
+// |
// # Dirty tracker IDs |
// key: "DIRTY: " + <int64 'dirty_tracker_id'> |
// value: <empty> |
@@ -94,6 +102,36 @@ std::string GenerateMultiTrackerKey(const std::string& file_id) { |
return kMultiTrackerByFileIDKeyPrefix + file_id; |
} |
+std::string GenerateActiveTrackerIDByParentAndTitleKey( |
+ int64 parent_id, const std::string& title) { |
+ std::ostringstream oss; |
+ oss << kActiveTrackerIDByParentAndTitleKeyPrefix << parent_id |
+ << '\0' << title; |
+ return oss.str(); |
+} |
+ |
+std::string GenerateTrackerIDByParentAndTitleKeyPrefix( |
+ int64 parent_id, const std::string& title) { |
+ std::ostringstream oss; |
+ oss << kTrackerIDByParentAndTitleKeyPrefix << parent_id << '\0' |
+ << title << '\0'; |
+ return oss.str(); |
+} |
+ |
+std::string GenerateTrackerIDsByParentIDKeyPrefix(int64 parent_id) { |
+ std::ostringstream oss; |
+ oss << kTrackerIDByParentAndTitleKeyPrefix << parent_id << '\0'; |
+ return oss.str(); |
+} |
+ |
+std::string GenerateMultiBackingParentAndTitleKey( |
+ int64 parent_id, const std::string& title) { |
+ std::ostringstream oss; |
+ oss << kMultiBackingParentAndTitleKeyPrefix << parent_id << '\0' |
+ << title; |
+ return oss.str(); |
+} |
+ |
std::string GenerateDirtyIDKey(int64 tracker_id) { |
return kDirtyIDKeyPrefix + base::Int64ToString(tracker_id); |
} |
@@ -192,15 +230,15 @@ void MetadataDatabaseIndexOnDisk::StoreFileTracker( |
<< " " << GetTrackerTitle(*tracker); |
AddToAppIDIndex(*tracker, batch); |
AddToFileIDIndexes(*tracker, batch); |
+ AddToPathIndexes(*tracker, batch); |
AddToDirtyTrackerIndexes(*tracker, batch); |
- // TODO(peria): Add other indexes. |
} else { |
DVLOG(3) << "Updating tracker: " << tracker->tracker_id() |
<< " " << GetTrackerTitle(*tracker); |
UpdateInAppIDIndex(old_tracker, *tracker, batch); |
UpdateInFileIDIndexes(old_tracker, *tracker, batch); |
+ UpdateInPathIndexes(old_tracker, *tracker, batch); |
UpdateInDirtyTrackerIndexes(old_tracker, *tracker, batch); |
- // TODO(peria): Update other indexes. |
} |
} |
@@ -223,8 +261,8 @@ void MetadataDatabaseIndexOnDisk::RemoveFileTracker( |
<< tracker.tracker_id() << " " << GetTrackerTitle(tracker); |
RemoveFromAppIDIndex(tracker, batch); |
RemoveFromFileIDIndexes(tracker, batch); |
+ RemoveFromPathIndexes(tracker, batch); |
RemoveFromDirtyTrackerIndexes(tracker, batch); |
- // TODO(peria): Remove from other indexes. |
} |
TrackerIDSet MetadataDatabaseIndexOnDisk::GetFileTrackerIDsByFileID( |
@@ -265,28 +303,67 @@ int64 MetadataDatabaseIndexOnDisk::GetAppRootTracker( |
TrackerIDSet MetadataDatabaseIndexOnDisk::GetFileTrackerIDsByParentAndTitle( |
int64 parent_tracker_id, const std::string& title) const { |
- // TODO(peria): Implement here |
- NOTIMPLEMENTED(); |
- return TrackerIDSet(); |
+ return GetTrackerIDSetByPrefix( |
+ GenerateActiveTrackerIDByParentAndTitleKey(parent_tracker_id, title), |
+ GenerateTrackerIDByParentAndTitleKeyPrefix(parent_tracker_id, title)); |
} |
std::vector<int64> MetadataDatabaseIndexOnDisk::GetFileTrackerIDsByParent( |
- int64 parent_tracker_id) const { |
- // TODO(peria): Implement here |
- NOTIMPLEMENTED(); |
- return std::vector<int64>(); |
+ int64 parent_id) const { |
+ std::vector<int64> result; |
+ |
+ const std::string prefix = GenerateTrackerIDsByParentIDKeyPrefix(parent_id); |
+ scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
+ for (itr->Seek(prefix); itr->Valid(); itr->Next()) { |
+ const std::string& key(itr->key().ToString()); |
+ std::string title_and_id; |
+ if (!RemovePrefix(key, prefix, &title_and_id)) |
+ break; |
+ |
+ size_t pos = title_and_id.rfind('\0'); |
+ DCHECK(pos != std::string::npos); |
+ |
+ int64 tracker_id; |
+ if (!base::StringToInt64(title_and_id.substr(pos + 1), &tracker_id)) |
+ continue; |
+ result.push_back(tracker_id); |
+ } |
+ return result; |
} |
std::string MetadataDatabaseIndexOnDisk::PickMultiTrackerFileID() const { |
- // TODO(peria): Implement here |
- NOTIMPLEMENTED(); |
- return std::string(); |
+ scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
+ itr->Seek(kMultiTrackerByFileIDKeyPrefix); |
+ if (!itr->Valid()) |
+ return std::string(); |
+ |
+ std::string file_id; |
+ if (!RemovePrefix(itr->key().ToString(), |
+ kMultiTrackerByFileIDKeyPrefix, &file_id)) |
+ return std::string(); |
+ |
+ return file_id; |
} |
ParentIDAndTitle MetadataDatabaseIndexOnDisk::PickMultiBackingFilePath() const { |
- // TODO(peria): Implement here |
- NOTIMPLEMENTED(); |
- return ParentIDAndTitle(); |
+ scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
+ itr->Seek(kMultiBackingParentAndTitleKeyPrefix); |
+ if (!itr->Valid()) |
+ return ParentIDAndTitle(); |
+ |
+ std::string value; |
+ if (!RemovePrefix(itr->key().ToString(), |
+ kMultiBackingParentAndTitleKeyPrefix, &value)) |
+ return ParentIDAndTitle(); |
+ |
+ size_t pos = value.find('\0'); // '\0' is a separator. |
+ int64 parent_id; |
+ if (pos == std::string::npos || |
+ !base::StringToInt64(value.substr(0, pos), &parent_id)) |
+ return ParentIDAndTitle(); |
+ |
+ // Successfully found an entry. |
+ return ParentIDAndTitle(parent_id, value.substr(pos + 1)); |
} |
int64 MetadataDatabaseIndexOnDisk::PickDirtyTracker() const { |
@@ -495,29 +572,19 @@ void MetadataDatabaseIndexOnDisk::RemoveFromAppIDIndex( |
void MetadataDatabaseIndexOnDisk::AddToFileIDIndexes( |
const FileTracker& new_tracker, leveldb::WriteBatch* batch) { |
- DVLOG(1) << " Add to trackers by file ID: " << new_tracker.file_id(); |
- const std::string prefix = |
- GenerateTrackerIDByFileIDKeyPrefix(new_tracker.file_id()); |
+ const std::string& file_id = new_tracker.file_id(); |
+ DVLOG(1) << " Add to trackers by file ID: " << file_id; |
+ const std::string prefix = GenerateTrackerIDByFileIDKeyPrefix(file_id); |
AddToTrackerIDSetWithPrefix( |
- GenerateActiveTrackerIDByFileIDKey(new_tracker.file_id()), |
+ GenerateActiveTrackerIDByFileIDKey(file_id), |
prefix, new_tracker, batch); |
- scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
- for (itr->Seek(prefix); itr->Valid(); itr->Next()) { |
- std::string id_str; |
- if (!RemovePrefix(itr->key().ToString(), prefix, &id_str)) |
- break; |
- |
- int64 tracker_id; |
- base::StringToInt64(id_str, &tracker_id); |
- if (tracker_id == new_tracker.tracker_id()) |
- continue; |
- |
- DVLOG_IF(1, !DBHasKey(GenerateMultiTrackerKey(new_tracker.file_id()))) |
- << " Add to multi-tracker file IDs: " << new_tracker.file_id(); |
- batch->Put(GenerateMultiTrackerKey(new_tracker.file_id()), std::string()); |
- break; |
+ const std::string multi_tracker_key = GenerateMultiTrackerKey(file_id); |
+ if (!DBHasKey(multi_tracker_key) && |
+ CountWithPrefix(prefix, new_tracker.tracker_id()) != NONE) { |
+ DVLOG(1) << " Add to multi-tracker file IDs: " << file_id; |
+ batch->Put(multi_tracker_key, std::string()); |
} |
} |
@@ -545,32 +612,153 @@ void MetadataDatabaseIndexOnDisk::UpdateInFileIDIndexes( |
void MetadataDatabaseIndexOnDisk::RemoveFromFileIDIndexes( |
const FileTracker& tracker, leveldb::WriteBatch* batch) { |
+ const std::string& file_id = tracker.file_id(); |
const std::string prefix = |
- GenerateTrackerIDByFileIDKeyPrefix(tracker.file_id()); |
+ GenerateTrackerIDByFileIDKeyPrefix(file_id); |
if (!EraseInTrackerIDSetWithPrefix( |
- GenerateActiveTrackerIDByFileIDKey(tracker.file_id()), prefix, |
- tracker.tracker_id(), batch)) |
+ GenerateActiveTrackerIDByFileIDKey(file_id), |
+ prefix, tracker.tracker_id(), batch)) |
return; |
DVLOG(1) << " Remove from trackers by file ID: " << tracker.tracker_id(); |
- // Deletions are not done yet, so the number looks +1 larger than expected. |
- size_t count = 0; |
+ const std::string multi_key = GenerateMultiTrackerKey(file_id); |
+ if (DBHasKey(multi_key) && |
+ CountWithPrefix(prefix, tracker.tracker_id()) != MULTIPLE) { |
+ DVLOG(1) << " Remove from multi-tracker file IDs: " << file_id; |
+ batch->Delete(multi_key); |
+ } |
+} |
+ |
+void MetadataDatabaseIndexOnDisk::AddToPathIndexes( |
+ const FileTracker& new_tracker, leveldb::WriteBatch* batch) { |
+ int64 parent_id = new_tracker.parent_tracker_id(); |
+ std::string title = GetTrackerTitle(new_tracker); |
+ |
+ DVLOG(1) << " Add to trackers by parent and title: " |
+ << parent_id << " " << title; |
+ |
+ const std::string prefix = |
+ GenerateTrackerIDByParentAndTitleKeyPrefix(parent_id, title); |
+ AddToTrackerIDSetWithPrefix( |
+ GenerateActiveTrackerIDByParentAndTitleKey(parent_id, title), |
+ prefix, new_tracker, batch); |
+ |
scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
- for (itr->Seek(prefix); itr->Valid() && count <= 2; itr->Next()) { |
- if (!StartsWithASCII(itr->key().ToString(), prefix, true)) |
+ for (itr->Seek(prefix); itr->Valid(); itr->Next()) { |
+ std::string id_str; |
+ if (!RemovePrefix(itr->key().ToString(), prefix, &id_str)) |
break; |
- ++count; |
+ |
+ int64 tracker_id; |
+ if (!base::StringToInt64(id_str, &tracker_id)) |
+ continue; |
+ if (tracker_id == new_tracker.tracker_id()) { |
+ NOTREACHED(); |
+ continue; |
+ } |
+ |
+ const std::string multi_key = |
+ GenerateMultiBackingParentAndTitleKey(parent_id, title); |
+ DVLOG_IF(1, !DBHasKey(multi_key)) |
+ << " Add to multi backing file paths: " << parent_id << " " << title; |
+ batch->Put(GenerateMultiBackingParentAndTitleKey(parent_id, title), |
+ std::string()); |
+ break; |
+ } |
+} |
+ |
+void MetadataDatabaseIndexOnDisk::UpdateInPathIndexes( |
+ const FileTracker& old_tracker, |
+ const FileTracker& new_tracker, |
+ leveldb::WriteBatch* batch) { |
+ DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); |
+ DCHECK_EQ(old_tracker.parent_tracker_id(), new_tracker.parent_tracker_id()); |
+ DCHECK(GetTrackerTitle(old_tracker) == GetTrackerTitle(new_tracker) || |
+ !old_tracker.has_synced_details()); |
+ |
+ int64 tracker_id = new_tracker.tracker_id(); |
+ int64 parent_id = new_tracker.parent_tracker_id(); |
+ const std::string old_title = GetTrackerTitle(old_tracker); |
+ const std::string title = GetTrackerTitle(new_tracker); |
+ |
+ if (old_title != title) { |
+ const std::string old_prefix = |
+ GenerateTrackerIDByParentAndTitleKeyPrefix(parent_id, old_title); |
+ EraseInTrackerIDSetWithPrefix( |
+ GenerateActiveTrackerIDByParentAndTitleKey(parent_id, old_title), |
+ old_prefix, tracker_id, batch); |
+ |
+ if (!old_title.empty() && |
+ CountWithPrefix(old_prefix, tracker_id) != MULTIPLE) { |
+ const std::string old_multi_backing_key = |
+ GenerateMultiBackingParentAndTitleKey(parent_id, old_title); |
+ DVLOG_IF(1, DBHasKey(old_multi_backing_key)) |
+ << " Remove from multi backing file paths: " |
+ << parent_id << " " << old_title; |
+ batch->Delete(old_multi_backing_key); |
+ } |
+ |
+ DVLOG(1) << " Add to trackers by parent and title: " |
+ << parent_id << " " << title; |
+ |
+ const std::string prefix = |
+ GenerateTrackerIDByParentAndTitleKeyPrefix(parent_id, title); |
+ AddToTrackerIDSetWithPrefix( |
+ GenerateActiveTrackerIDByParentAndTitleKey(parent_id, title), |
+ prefix, new_tracker, batch); |
+ |
+ if (CountWithPrefix(prefix, tracker_id) != NONE) { |
+ const std::string multi_backing_key = |
+ GenerateMultiBackingParentAndTitleKey(parent_id, title); |
+ DVLOG_IF(1, !DBHasKey(multi_backing_key)) |
+ << " Add to multi backing file_paths: " |
+ << parent_id << " " << title; |
+ batch->Put(multi_backing_key, std::string()); |
+ } |
+ |
+ return; |
} |
- if (count >= 3) |
+ const std::string active_tracker_key = |
+ GenerateActiveTrackerIDByParentAndTitleKey(parent_id, title); |
+ const std::string prefix = |
+ GenerateTrackerIDByParentAndTitleKeyPrefix(parent_id, title); |
+ if (old_tracker.active() && !new_tracker.active()) { |
+ DeactivateInTrackerIDSetWithPrefix( |
+ active_tracker_key, prefix, tracker_id, batch); |
+ } else if (!old_tracker.active() && new_tracker.active()) { |
+ ActivateInTrackerIDSetWithPrefix( |
+ active_tracker_key, prefix, tracker_id, batch); |
+ } |
+} |
+ |
+void MetadataDatabaseIndexOnDisk::RemoveFromPathIndexes( |
+ const FileTracker& tracker, leveldb::WriteBatch* batch) { |
+ int64 tracker_id = tracker.tracker_id(); |
+ int64 parent_id = tracker.parent_tracker_id(); |
+ std::string title = GetTrackerTitle(tracker); |
+ |
+ DVLOG(1) << " Remove from trackers by parent and title: " |
+ << parent_id << " " << title; |
+ |
+ const std::string active_tracker_key = |
+ GenerateActiveTrackerIDByParentAndTitleKey(parent_id, title); |
+ const std::string key_prefix = |
+ GenerateTrackerIDByParentAndTitleKeyPrefix(parent_id, title); |
+ if (!EraseInTrackerIDSetWithPrefix( |
+ active_tracker_key, key_prefix, tracker_id, batch)) |
return; |
- const std::string multi_key = GenerateMultiTrackerKey(tracker.file_id()); |
- DVLOG_IF(1, DBHasKey(multi_key)) |
- << " Remove from multi-tracker file IDs: " << tracker.file_id(); |
- batch->Delete(multi_key); |
+ const std::string multi_key = |
+ GenerateMultiBackingParentAndTitleKey(parent_id, title); |
+ if (!title.empty() && DBHasKey(multi_key) && |
+ CountWithPrefix(key_prefix, tracker_id) != MULTIPLE) { |
+ DVLOG(1) << " Remove from multi backing file paths: " |
+ << parent_id << " " << title; |
+ batch->Delete(multi_key); |
+ } |
} |
void MetadataDatabaseIndexOnDisk::AddToDirtyTrackerIndexes( |
@@ -746,5 +934,27 @@ bool MetadataDatabaseIndexOnDisk::DBHasKey(const std::string& key) { |
return itr->Valid() && (itr->key() == key); |
} |
+MetadataDatabaseIndexOnDisk::NumEntries |
+MetadataDatabaseIndexOnDisk::CountWithPrefix( |
+ const std::string& prefix, int64 ignored_id) { |
+ const std::string ignored = base::Int64ToString(ignored_id); |
+ |
+ size_t count = 0; |
+ scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
+ for (itr->Seek(prefix); itr->Valid() && count <= 1; itr->Next()) { |
+ std::string value; |
+ if (!RemovePrefix(itr->key().ToString(), prefix, &value)) |
+ break; |
+ if (value == ignored) |
+ continue; |
+ |
+ ++count; |
+ } |
+ |
+ if (count >= 2) |
+ return MULTIPLE; |
+ return count == 0 ? NONE : SINGLE; |
+} |
+ |
} // namespace drive_backend |
} // namespace sync_file_system |