Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" | 5 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" |
| 6 | 6 |
| 7 #include <stack> | 7 #include <stack> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| (...skipping 692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 703 std::back_inserter(known_children)); | 703 std::back_inserter(known_children)); |
| 704 for (std::vector<int64>::iterator itr = known_children.begin(); | 704 for (std::vector<int64>::iterator itr = known_children.begin(); |
| 705 itr != known_children.end(); ++itr) | 705 itr != known_children.end(); ++itr) |
| 706 children.erase(tracker_by_id_[*itr]->file_id()); | 706 children.erase(tracker_by_id_[*itr]->file_id()); |
| 707 | 707 |
| 708 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | 708 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); |
| 709 for (FileIDList::const_iterator itr = child_file_ids.begin(); | 709 for (FileIDList::const_iterator itr = child_file_ids.begin(); |
| 710 itr != child_file_ids.end(); ++itr) | 710 itr != child_file_ids.end(); ++itr) |
| 711 CreateTrackerForParentAndFileID(*folder_tracker, *itr, batch.get()); | 711 CreateTrackerForParentAndFileID(*folder_tracker, *itr, batch.get()); |
| 712 folder_tracker->set_needs_folder_listing(false); | 712 folder_tracker->set_needs_folder_listing(false); |
| 713 if (!ShouldKeepDirty(*folder_tracker)) { | 713 if (folder_tracker->dirty() && !ShouldKeepDirty(*folder_tracker)) { |
| 714 folder_tracker->set_dirty(false); | 714 folder_tracker->set_dirty(false); |
| 715 dirty_trackers_.erase(folder_tracker); | 715 dirty_trackers_.erase(folder_tracker); |
| 716 } | 716 } |
| 717 PutTrackerToBatch(*folder_tracker, batch.get()); | 717 PutTrackerToBatch(*folder_tracker, batch.get()); |
| 718 | 718 |
| 719 WriteToDatabase(batch.Pass(), callback); | 719 WriteToDatabase(batch.Pass(), callback); |
| 720 } | 720 } |
| 721 | 721 |
| 722 void MetadataDatabase::UpdateTracker(int64 tracker_id, | |
| 723 const FileDetails& updated_details, | |
| 724 const SyncStatusCallback& callback) { | |
| 725 TrackerByID::iterator found = tracker_by_id_.find(tracker_id); | |
| 726 if (found == tracker_by_id_.end()) { | |
| 727 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); | |
| 728 return; | |
| 729 } | |
| 730 | |
| 731 FileTracker* tracker = found->second; | |
| 732 DCHECK(tracker); | |
| 733 | |
| 734 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
| 735 | |
| 736 // 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
| |
| 737 if (updated_details.deleted()) { | |
| 738 FileByID::iterator found = file_by_id_.find(tracker->file_id()); | |
| 739 if (found == file_by_id_.end() || found->second->details().deleted()) { | |
| 740 // Both the tracker and metadata have the deleted flag, now it's safe to | |
| 741 // delete the |tracker|. | |
| 742 RemoveTracker(tracker->tracker_id(), batch.get()); | |
| 743 } else { | |
| 744 // The local file is deleted, but corresponding remote file isn't. | |
| 745 // Put the tracker back to the initial state. | |
| 746 tracker->clear_synced_details(); | |
| 747 tracker->set_dirty(true); | |
| 748 tracker->set_active(false); | |
| 749 PutTrackerToBatch(*tracker, batch.get()); | |
| 750 } | |
| 751 | |
| 752 WriteToDatabase(batch.Pass(), callback); | |
| 753 return; | |
| 754 } | |
| 755 | |
| 756 // Check if the tracker was retitled. If it was, update the title and its | |
| 757 // index in advance. | |
| 758 if (!tracker->has_synced_details() || | |
| 759 tracker->synced_details().title() != updated_details.title()) { | |
| 760 UpdateTrackerTitle(tracker, updated_details.title(), batch.get()); | |
| 761 } | |
| 762 | |
| 763 *tracker->mutable_synced_details() = updated_details; | |
| 764 | |
| 765 // Activate the tracker if: | |
| 766 // - There is no active tracker that tracks |tracker->file_id()|. | |
| 767 // - There is no active tracker that has the same |parent| and |title|. | |
| 768 if (!tracker->active() && CanActivateTracker(*tracker)) | |
| 769 MakeTrackerActive(tracker->tracker_id(), batch.get()); | |
| 770 if (tracker->dirty() && !ShouldKeepDirty(*tracker)) { | |
| 771 tracker->set_dirty(false); | |
| 772 dirty_trackers_.erase(tracker); | |
| 773 } | |
| 774 PutTrackerToBatch(*tracker, batch.get()); | |
| 775 | |
| 776 WriteToDatabase(batch.Pass(), callback); | |
| 777 } | |
| 778 | |
| 722 MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner) | 779 MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner) |
| 723 : task_runner_(task_runner), weak_ptr_factory_(this) { | 780 : task_runner_(task_runner), weak_ptr_factory_(this) { |
| 724 DCHECK(task_runner); | 781 DCHECK(task_runner); |
| 725 } | 782 } |
| 726 | 783 |
| 727 // static | 784 // static |
| 728 void MetadataDatabase::CreateOnTaskRunner( | 785 void MetadataDatabase::CreateOnTaskRunner( |
| 729 base::SingleThreadTaskRunner* callback_runner, | 786 base::SingleThreadTaskRunner* callback_runner, |
| 730 base::SequencedTaskRunner* task_runner, | 787 base::SequencedTaskRunner* task_runner, |
| 731 const base::FilePath& database_path, | 788 const base::FilePath& database_path, |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 953 // FileMetadata::details but from FileTracker::synced_details, which is filled | 1010 // FileMetadata::details but from FileTracker::synced_details, which is filled |
| 954 // on tracker updated phase. Use empty string as the title since | 1011 // on tracker updated phase. Use empty string as the title since |
| 955 // FileTracker::synced_details is empty here. | 1012 // FileTracker::synced_details is empty here. |
| 956 trackers_by_parent_and_title_[parent_tracker.tracker_id()][std::string()] | 1013 trackers_by_parent_and_title_[parent_tracker.tracker_id()][std::string()] |
| 957 .Insert(tracker.get()); | 1014 .Insert(tracker.get()); |
| 958 dirty_trackers_.insert(tracker.get()); | 1015 dirty_trackers_.insert(tracker.get()); |
| 959 DCHECK(!ContainsKey(tracker_by_id_, tracker_id)); | 1016 DCHECK(!ContainsKey(tracker_by_id_, tracker_id)); |
| 960 tracker_by_id_[tracker_id] = tracker.release(); | 1017 tracker_by_id_[tracker_id] = tracker.release(); |
| 961 } | 1018 } |
| 962 | 1019 |
| 1020 void MetadataDatabase::RemoveTracker(int64 tracker_id, | |
| 1021 leveldb::WriteBatch* batch) { | |
| 1022 RemoveTrackerInternal(tracker_id, batch, false); | |
| 1023 } | |
| 1024 | |
| 963 void MetadataDatabase::RemoveTrackerIgnoringSiblings( | 1025 void MetadataDatabase::RemoveTrackerIgnoringSiblings( |
| 964 int64 tracker_id, | 1026 int64 tracker_id, |
| 965 leveldb::WriteBatch* batch) { | 1027 leveldb::WriteBatch* batch) { |
| 1028 RemoveTrackerInternal(tracker_id, batch, true); | |
| 1029 } | |
| 1030 | |
| 1031 void MetadataDatabase::RemoveTrackerInternal( | |
| 1032 int64 tracker_id, | |
| 1033 leveldb::WriteBatch* batch, | |
| 1034 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.
| |
| 966 scoped_ptr<FileTracker> tracker( | 1035 scoped_ptr<FileTracker> tracker( |
| 967 FindAndEraseItem(&tracker_by_id_, tracker_id)); | 1036 FindAndEraseItem(&tracker_by_id_, tracker_id)); |
| 968 if (!tracker) | 1037 if (!tracker) |
| 969 return; | 1038 return; |
| 970 | 1039 |
| 971 EraseTrackerFromFileIDIndex(tracker.get(), batch); | 1040 EraseTrackerFromFileIDIndex(tracker.get(), batch); |
| 972 if (IsAppRoot(*tracker)) | 1041 if (IsAppRoot(*tracker)) |
| 973 app_root_by_app_id_.erase(tracker->app_id()); | 1042 app_root_by_app_id_.erase(tracker->app_id()); |
| 974 EraseTrackerFromPathIndex(tracker.get()); | 1043 EraseTrackerFromPathIndex(tracker.get()); |
| 975 | 1044 |
| 976 MarkTrackersDirtyByFileID(tracker->file_id(), batch); | 1045 MarkTrackersDirtyByFileID(tracker->file_id(), batch); |
| 977 // Do not mark the same path trackers as dirty, since the caller is deleting | 1046 if (!ignore_name_conflicted_trackers) { |
| 978 // all its siblings. | 1047 MarkTrackersDirtyByPath(tracker->parent_tracker_id(), |
| 1048 GetTrackerTitle(*tracker), | |
| 1049 batch); | |
| 1050 } | |
| 979 PutTrackerDeletionToBatch(tracker_id, batch); | 1051 PutTrackerDeletionToBatch(tracker_id, batch); |
| 980 } | 1052 } |
| 981 | 1053 |
| 982 void MetadataDatabase::MaybeAddTrackersForNewFile( | 1054 void MetadataDatabase::MaybeAddTrackersForNewFile( |
| 983 const FileMetadata& file, | 1055 const FileMetadata& file, |
| 984 leveldb::WriteBatch* batch) { | 1056 leveldb::WriteBatch* batch) { |
| 985 std::set<int64> known_parents; | 1057 std::set<int64> known_parents; |
| 986 TrackersByFileID::iterator found = trackers_by_file_id_.find(file.file_id()); | 1058 TrackersByFileID::iterator found = trackers_by_file_id_.find(file.file_id()); |
| 987 if (found != trackers_by_file_id_.end()) { | 1059 if (found != trackers_by_file_id_.end()) { |
| 988 for (TrackerSet::const_iterator itr = found->second.begin(); | 1060 for (TrackerSet::const_iterator itr = found->second.begin(); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1131 | 1203 |
| 1132 FileTracker* tracker = tracker_by_id_[tracker_id]; | 1204 FileTracker* tracker = tracker_by_id_[tracker_id]; |
| 1133 if (!tracker->dirty()) { | 1205 if (!tracker->dirty()) { |
| 1134 tracker->set_dirty(true); | 1206 tracker->set_dirty(true); |
| 1135 PutTrackerToBatch(*tracker, batch); | 1207 PutTrackerToBatch(*tracker, batch); |
| 1136 dirty_trackers_.insert(tracker); | 1208 dirty_trackers_.insert(tracker); |
| 1137 } | 1209 } |
| 1138 } | 1210 } |
| 1139 } | 1211 } |
| 1140 | 1212 |
| 1213 bool MetadataDatabase::CanActivateTracker(const FileTracker& tracker) { | |
| 1214 DCHECK(!tracker.active()); | |
| 1215 DCHECK_NE(service_metadata_->sync_root_tracker_id(), tracker.tracker_id()); | |
| 1216 | |
| 1217 if (HasActiveTrackerForFileID(tracker.file_id())) | |
| 1218 return false; | |
| 1219 | |
| 1220 if (tracker.app_id().empty()) | |
| 1221 return false; | |
| 1222 if (!tracker.has_synced_details()) | |
| 1223 return false; | |
| 1224 DCHECK(tracker.parent_tracker_id()); | |
| 1225 | |
| 1226 return !HasActiveTrackerForPath(tracker.parent_tracker_id(), | |
| 1227 tracker.synced_details().title()); | |
| 1228 } | |
| 1229 | |
| 1141 bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const { | 1230 bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const { |
| 1231 if (HasDisabledAppRoot(tracker)) | |
| 1232 return false; | |
| 1233 | |
| 1142 DCHECK(tracker.dirty()); | 1234 DCHECK(tracker.dirty()); |
| 1143 if (!tracker.has_synced_details()) | 1235 if (!tracker.has_synced_details()) |
| 1144 return true; | 1236 return true; |
| 1145 | 1237 |
| 1146 FileByID::const_iterator found = file_by_id_.find(tracker.file_id()); | 1238 FileByID::const_iterator found = file_by_id_.find(tracker.file_id()); |
| 1147 if (found == file_by_id_.end()) | 1239 if (found == file_by_id_.end()) |
| 1148 return true; | 1240 return true; |
| 1149 const FileMetadata& file = *found->second; | 1241 const FileMetadata* file = found->second; |
| 1242 DCHECK(file); | |
| 1150 | 1243 |
| 1151 if (tracker.active()) { | 1244 if (tracker.active()) { |
| 1152 if (tracker.needs_folder_listing()) | 1245 if (tracker.needs_folder_listing()) |
| 1153 return true; | 1246 return true; |
| 1154 if (tracker.synced_details().md5() != file.details().md5()) | 1247 if (tracker.synced_details().md5() != file->details().md5()) |
| 1155 return true; | 1248 return true; |
| 1156 } | 1249 } |
| 1157 | 1250 |
| 1158 const FileDetails& local_details = tracker.synced_details(); | 1251 const FileDetails& local_details = tracker.synced_details(); |
| 1159 const FileDetails& remote_details = file.details(); | 1252 const FileDetails& remote_details = file->details(); |
| 1160 | 1253 |
| 1161 if (local_details.title() != remote_details.title()) | 1254 if (local_details.title() != remote_details.title()) |
| 1162 return true; | 1255 return true; |
| 1163 if (local_details.deleted() != remote_details.deleted()) | 1256 if (local_details.deleted() != remote_details.deleted()) |
| 1164 return true; | 1257 return true; |
| 1165 | 1258 |
| 1166 return false; | 1259 return false; |
| 1167 } | 1260 } |
| 1168 | 1261 |
| 1262 bool MetadataDatabase::HasDisabledAppRoot(const FileTracker& tracker) const { | |
| 1263 TrackerByAppID::const_iterator found = | |
| 1264 app_root_by_app_id_.find(tracker.app_id()); | |
| 1265 if (found == app_root_by_app_id_.end()) | |
| 1266 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
| |
| 1267 | |
| 1268 const FileTracker* app_root_tracker = found->second; | |
| 1269 DCHECK(app_root_tracker); | |
| 1270 return app_root_tracker->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT; | |
| 1271 } | |
| 1272 | |
| 1273 bool MetadataDatabase::HasActiveTrackerForFileID( | |
| 1274 const std::string& file_id) const { | |
| 1275 TrackersByFileID::const_iterator found = trackers_by_file_id_.find(file_id); | |
| 1276 return found != trackers_by_file_id_.end() && found->second.has_active(); | |
| 1277 } | |
| 1278 | |
| 1279 bool MetadataDatabase::HasActiveTrackerForPath(int64 parent_tracker_id, | |
| 1280 const std::string& title) const { | |
| 1281 TrackersByParentAndTitle::const_iterator found_by_parent = | |
| 1282 trackers_by_parent_and_title_.find(parent_tracker_id); | |
| 1283 if (found_by_parent == trackers_by_parent_and_title_.end()) | |
| 1284 return false; | |
| 1285 | |
| 1286 const TrackersByTitle& trackers_by_title = found_by_parent->second; | |
| 1287 TrackersByTitle::const_iterator found = trackers_by_title.find(title); | |
| 1288 return found != trackers_by_title.end() && found->second.has_active(); | |
| 1289 } | |
| 1290 | |
| 1291 void MetadataDatabase::UpdateTrackerTitle(FileTracker* tracker, | |
| 1292 const std::string& new_title, | |
| 1293 leveldb::WriteBatch* batch) { | |
| 1294 int64 parent_id = tracker->parent_tracker_id(); | |
| 1295 std::string old_title = GetTrackerTitle(*tracker); | |
| 1296 DCHECK_NE(old_title, new_title); | |
| 1297 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
| |
| 1298 | |
| 1299 TrackersByTitle* trackers_by_title = | |
| 1300 &trackers_by_parent_and_title_[parent_id]; | |
| 1301 TrackerSet* old_siblings = &(*trackers_by_title)[old_title]; | |
| 1302 TrackerSet* new_siblings = &(*trackers_by_title)[new_title]; | |
| 1303 | |
| 1304 old_siblings->Erase(tracker); | |
| 1305 if (old_siblings->empty()) | |
| 1306 trackers_by_title->erase(old_title); | |
| 1307 else | |
| 1308 MarkTrackerSetDirty(old_siblings, batch); | |
| 1309 | |
| 1310 if (tracker->active() && new_siblings->has_active()) { | |
| 1311 // 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
| |
| 1312 FileTracker* obstacle = new_siblings->active_tracker(); | |
| 1313 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.
| |
| 1314 | |
| 1315 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.
| |
| 1316 chain->Inactivate(obstacle); | |
| 1317 MarkTrackerSetDirty(chain, batch); | |
| 1318 | |
| 1319 obstacle->set_active(false); | |
| 1320 PutTrackerToBatch(*obstacle, batch); | |
| 1321 | |
| 1322 RemoveAllDescendantTrackers(obstacle->tracker_id(), batch); | |
| 1323 new_siblings->Insert(tracker); | |
|
kinuko
2013/08/27 13:20:19
duplicated with line 1327?
tzik
2013/08/30 05:51:57
Done.
| |
| 1324 } | |
| 1325 | |
| 1326 tracker->mutable_synced_details()->set_title(new_title); | |
| 1327 new_siblings->Insert(tracker); | |
| 1328 PutTrackerToBatch(*tracker, batch); | |
| 1329 } | |
| 1330 | |
| 1169 void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch, | 1331 void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch, |
| 1170 const SyncStatusCallback& callback) { | 1332 const SyncStatusCallback& callback) { |
| 1171 base::PostTaskAndReplyWithResult( | 1333 base::PostTaskAndReplyWithResult( |
| 1172 task_runner_.get(), | 1334 task_runner_.get(), |
| 1173 FROM_HERE, | 1335 FROM_HERE, |
| 1174 base::Bind(&leveldb::DB::Write, | 1336 base::Bind(&leveldb::DB::Write, |
| 1175 base::Unretained(db_.get()), | 1337 base::Unretained(db_.get()), |
| 1176 leveldb::WriteOptions(), | 1338 leveldb::WriteOptions(), |
| 1177 base::Owned(batch.release())), | 1339 base::Owned(batch.release())), |
| 1178 base::Bind(&AdaptLevelDBStatusToSyncStatusCode, callback)); | 1340 base::Bind(&AdaptLevelDBStatusToSyncStatusCode, callback)); |
| 1179 } | 1341 } |
| 1180 | 1342 |
| 1181 } // namespace drive_backend | 1343 } // namespace drive_backend |
| 1182 } // namespace sync_file_system | 1344 } // namespace sync_file_system |
| OLD | NEW |