Chromium Code Reviews| Index: chrome/browser/sync_file_system/drive_backend/metadata_database.cc |
| diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc |
| index 98df266c11fd8f5129d1653f23c9f7484d337260..b37d578de922457587fa4a199e2acebbcd610475 100644 |
| --- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc |
| +++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc |
| @@ -710,7 +710,7 @@ void MetadataDatabase::PopulateFolder(const std::string& folder_id, |
| itr != child_file_ids.end(); ++itr) |
| CreateTrackerForParentAndFileID(*folder_tracker, *itr, batch.get()); |
| folder_tracker->set_needs_folder_listing(false); |
| - if (!ShouldKeepDirty(*folder_tracker)) { |
| + if (folder_tracker->dirty() && !ShouldKeepDirty(*folder_tracker)) { |
| folder_tracker->set_dirty(false); |
| dirty_trackers_.erase(folder_tracker); |
| } |
| @@ -719,6 +719,63 @@ void MetadataDatabase::PopulateFolder(const std::string& folder_id, |
| WriteToDatabase(batch.Pass(), callback); |
| } |
| +void MetadataDatabase::UpdateTracker(int64 tracker_id, |
| + const FileDetails& updated_details, |
| + const SyncStatusCallback& callback) { |
| + TrackerByID::iterator found = tracker_by_id_.find(tracker_id); |
| + if (found == tracker_by_id_.end()) { |
| + RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); |
| + return; |
| + } |
| + |
| + FileTracker* tracker = found->second; |
| + DCHECK(tracker); |
| + |
| + scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); |
| + |
| + // Local file is deleted. |
|
kinuko
2013/08/27 07:47:05
nit: the term 'local' is confusing here. Do you as
tzik
2013/08/30 05:51:57
Yes, the updated_details should contain latest loc
|
| + if (updated_details.deleted()) { |
| + FileByID::iterator found = file_by_id_.find(tracker->file_id()); |
| + if (found == file_by_id_.end() || found->second->details().deleted()) { |
| + // Both the tracker and metadata have the deleted flag, now it's safe to |
| + // delete the |tracker|. |
| + RemoveTracker(tracker->tracker_id(), batch.get()); |
| + } else { |
| + // The local file is deleted, but corresponding remote file isn't. |
| + // Put the tracker back to the initial state. |
| + tracker->clear_synced_details(); |
| + tracker->set_dirty(true); |
| + tracker->set_active(false); |
| + PutTrackerToBatch(*tracker, batch.get()); |
| + } |
| + |
| + WriteToDatabase(batch.Pass(), callback); |
| + return; |
| + } |
| + |
| + // Check if the tracker was retitled. If it was, update the title and its |
| + // index in advance. |
| + if (!tracker->has_synced_details() || |
| + tracker->synced_details().title() != updated_details.title()) { |
| + UpdateTrackerTitle(tracker, updated_details.title(), batch.get()); |
| + } |
| + |
| + *tracker->mutable_synced_details() = updated_details; |
| + |
| + // Activate the tracker if: |
| + // - There is no active tracker that tracks |tracker->file_id()|. |
| + // - There is no active tracker that has the same |parent| and |title|. |
| + if (!tracker->active() && CanActivateTracker(*tracker)) |
| + MakeTrackerActive(tracker->tracker_id(), batch.get()); |
| + if (tracker->dirty() && !ShouldKeepDirty(*tracker)) { |
| + tracker->set_dirty(false); |
| + dirty_trackers_.erase(tracker); |
| + } |
| + PutTrackerToBatch(*tracker, batch.get()); |
| + |
| + WriteToDatabase(batch.Pass(), callback); |
| +} |
| + |
| MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner) |
| : task_runner_(task_runner), weak_ptr_factory_(this) { |
| DCHECK(task_runner); |
| @@ -960,9 +1017,21 @@ void MetadataDatabase::CreateTrackerForParentAndFileID( |
| tracker_by_id_[tracker_id] = tracker.release(); |
| } |
| +void MetadataDatabase::RemoveTracker(int64 tracker_id, |
| + leveldb::WriteBatch* batch) { |
| + RemoveTrackerInternal(tracker_id, batch, false); |
| +} |
| + |
| void MetadataDatabase::RemoveTrackerIgnoringSiblings( |
| int64 tracker_id, |
| leveldb::WriteBatch* batch) { |
| + RemoveTrackerInternal(tracker_id, batch, true); |
| +} |
| + |
| +void MetadataDatabase::RemoveTrackerInternal( |
| + int64 tracker_id, |
| + leveldb::WriteBatch* batch, |
| + bool ignore_name_conflicted_trackers) { |
|
kinuko
2013/08/27 13:20:19
nit: I'd name this bool parameter similar to the m
tzik
2013/08/30 05:51:57
Done.
|
| scoped_ptr<FileTracker> tracker( |
| FindAndEraseItem(&tracker_by_id_, tracker_id)); |
| if (!tracker) |
| @@ -974,8 +1043,11 @@ void MetadataDatabase::RemoveTrackerIgnoringSiblings( |
| EraseTrackerFromPathIndex(tracker.get()); |
| MarkTrackersDirtyByFileID(tracker->file_id(), batch); |
| - // Do not mark the same path trackers as dirty, since the caller is deleting |
| - // all its siblings. |
| + if (!ignore_name_conflicted_trackers) { |
| + MarkTrackersDirtyByPath(tracker->parent_tracker_id(), |
| + GetTrackerTitle(*tracker), |
| + batch); |
| + } |
| PutTrackerDeletionToBatch(tracker_id, batch); |
| } |
| @@ -1138,7 +1210,27 @@ void MetadataDatabase::RecursiveMarkTrackerAsDirty(int64 root_tracker_id, |
| } |
| } |
| +bool MetadataDatabase::CanActivateTracker(const FileTracker& tracker) { |
| + DCHECK(!tracker.active()); |
| + DCHECK_NE(service_metadata_->sync_root_tracker_id(), tracker.tracker_id()); |
| + |
| + if (HasActiveTrackerForFileID(tracker.file_id())) |
| + return false; |
| + |
| + if (tracker.app_id().empty()) |
| + return false; |
| + if (!tracker.has_synced_details()) |
| + return false; |
| + DCHECK(tracker.parent_tracker_id()); |
| + |
| + return !HasActiveTrackerForPath(tracker.parent_tracker_id(), |
| + tracker.synced_details().title()); |
| +} |
| + |
| bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const { |
| + if (HasDisabledAppRoot(tracker)) |
| + return false; |
| + |
| DCHECK(tracker.dirty()); |
| if (!tracker.has_synced_details()) |
| return true; |
| @@ -1146,17 +1238,18 @@ bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const { |
| FileByID::const_iterator found = file_by_id_.find(tracker.file_id()); |
| if (found == file_by_id_.end()) |
| return true; |
| - const FileMetadata& file = *found->second; |
| + const FileMetadata* file = found->second; |
| + DCHECK(file); |
| if (tracker.active()) { |
| if (tracker.needs_folder_listing()) |
| return true; |
| - if (tracker.synced_details().md5() != file.details().md5()) |
| + if (tracker.synced_details().md5() != file->details().md5()) |
| return true; |
| } |
| const FileDetails& local_details = tracker.synced_details(); |
| - const FileDetails& remote_details = file.details(); |
| + const FileDetails& remote_details = file->details(); |
| if (local_details.title() != remote_details.title()) |
| return true; |
| @@ -1166,6 +1259,75 @@ bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const { |
| return false; |
| } |
| +bool MetadataDatabase::HasDisabledAppRoot(const FileTracker& tracker) const { |
| + TrackerByAppID::const_iterator found = |
| + app_root_by_app_id_.find(tracker.app_id()); |
| + if (found == app_root_by_app_id_.end()) |
| + return false; |
|
kinuko
2013/08/27 13:20:19
What does this case mean..?
tzik
2013/08/30 05:51:57
This means the trackers is out of any app-root tre
|
| + |
| + const FileTracker* app_root_tracker = found->second; |
| + DCHECK(app_root_tracker); |
| + return app_root_tracker->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT; |
| +} |
| + |
| +bool MetadataDatabase::HasActiveTrackerForFileID( |
| + const std::string& file_id) const { |
| + TrackersByFileID::const_iterator found = trackers_by_file_id_.find(file_id); |
| + return found != trackers_by_file_id_.end() && found->second.has_active(); |
| +} |
| + |
| +bool MetadataDatabase::HasActiveTrackerForPath(int64 parent_tracker_id, |
| + const std::string& title) const { |
| + TrackersByParentAndTitle::const_iterator found_by_parent = |
| + trackers_by_parent_and_title_.find(parent_tracker_id); |
| + if (found_by_parent == trackers_by_parent_and_title_.end()) |
| + return false; |
| + |
| + const TrackersByTitle& trackers_by_title = found_by_parent->second; |
| + TrackersByTitle::const_iterator found = trackers_by_title.find(title); |
| + return found != trackers_by_title.end() && found->second.has_active(); |
| +} |
| + |
| +void MetadataDatabase::UpdateTrackerTitle(FileTracker* tracker, |
| + const std::string& new_title, |
| + leveldb::WriteBatch* batch) { |
| + int64 parent_id = tracker->parent_tracker_id(); |
| + std::string old_title = GetTrackerTitle(*tracker); |
| + DCHECK_NE(old_title, new_title); |
| + DCHECK(!new_title.empty()); |
|
kinuko
2013/08/27 13:20:19
We don't check this in UpdateTracker. Is new_titl
tzik
2013/08/30 05:51:57
New title should not be empty unless the file is d
kinuko
2013/08/30 06:03:46
Ok, I assume title cannot be assigned to an empty
|
| + |
| + TrackersByTitle* trackers_by_title = |
| + &trackers_by_parent_and_title_[parent_id]; |
| + TrackerSet* old_siblings = &(*trackers_by_title)[old_title]; |
| + TrackerSet* new_siblings = &(*trackers_by_title)[new_title]; |
| + |
| + old_siblings->Erase(tracker); |
| + if (old_siblings->empty()) |
| + trackers_by_title->erase(old_title); |
| + else |
| + MarkTrackerSetDirty(old_siblings, batch); |
| + |
| + if (tracker->active() && new_siblings->has_active()) { |
| + // Inactivate existing active tracker. |
|
kinuko
2013/08/27 13:20:19
Why does the new one always win here?
tzik
2013/08/30 05:51:57
The file is already updated locally here by the sy
|
| + FileTracker* obstacle = new_siblings->active_tracker(); |
| + new_siblings->Inactivate(obstacle); |
|
kinuko
2013/08/27 13:20:19
Do we need to check if the obstacle is KIND_REGULA
tzik
2013/08/30 05:51:57
Done.
|
| + |
| + TrackerSet* chain = &trackers_by_file_id_[obstacle->file_id()]; |
|
kinuko
2013/08/27 13:20:19
chain... ?
tzik
2013/08/30 05:51:57
Done.
|
| + chain->Inactivate(obstacle); |
| + MarkTrackerSetDirty(chain, batch); |
| + |
| + obstacle->set_active(false); |
| + PutTrackerToBatch(*obstacle, batch); |
| + |
| + RemoveAllDescendantTrackers(obstacle->tracker_id(), batch); |
| + new_siblings->Insert(tracker); |
|
kinuko
2013/08/27 13:20:19
duplicated with line 1327?
tzik
2013/08/30 05:51:57
Done.
|
| + } |
| + |
| + tracker->mutable_synced_details()->set_title(new_title); |
| + new_siblings->Insert(tracker); |
| + PutTrackerToBatch(*tracker, batch); |
| +} |
| + |
| void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch, |
| const SyncStatusCallback& callback) { |
| base::PostTaskAndReplyWithResult( |