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