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 ignoring_siblings) { |
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 (!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 |