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 |