Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / sync_file_system / drive_backend / metadata_database_index.cc
blobd157f0154a84e718b1f6141fddd92432d4df51ed
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index.h"
7 #include "base/metrics/histogram.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
12 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
13 #include "chrome/browser/sync_file_system/drive_backend/leveldb_wrapper.h"
14 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
15 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
16 #include "chrome/browser/sync_file_system/logger.h"
17 #include "third_party/leveldatabase/src/include/leveldb/db.h"
18 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
20 // LevelDB database schema
21 // =======================
23 // NOTE
24 // - Entries are sorted by keys.
25 // - int64 value is serialized as a string by base::Int64ToString().
26 // - ServiceMetadata, FileMetadata, and FileTracker values are serialized
27 // as a string by SerializeToString() of protocol buffers.
29 // Version 3
30 // # Version of this schema
31 // key: "VERSION"
32 // value: "3"
34 // # Metadata of the SyncFS service
35 // key: "SERVICE"
36 // value: <ServiceMetadata 'service_metadata'>
38 // # Metadata of remote files
39 // key: "FILE: " + <string 'file_id'>
40 // value: <FileMetadata 'metadata'>
42 // # Trackers of local file updates
43 // key: "TRACKER: " + <int64 'tracker_id'>
44 // value: <FileTracker 'tracker'>
46 namespace sync_file_system {
47 namespace drive_backend {
49 ParentIDAndTitle::ParentIDAndTitle() : parent_id(0) {}
50 ParentIDAndTitle::ParentIDAndTitle(int64 parent_id,
51 const std::string& title)
52 : parent_id(parent_id), title(title) {}
54 bool operator==(const ParentIDAndTitle& left, const ParentIDAndTitle& right) {
55 return left.parent_id == right.parent_id && left.title == right.title;
58 bool operator<(const ParentIDAndTitle& left, const ParentIDAndTitle& right) {
59 if (left.parent_id != right.parent_id)
60 return left.parent_id < right.parent_id;
61 return left.title < right.title;
64 DatabaseContents::DatabaseContents() {}
66 DatabaseContents::~DatabaseContents() {}
68 namespace {
70 template <typename Container>
71 typename Container::mapped_type FindItem(
72 const Container& container,
73 const typename Container::key_type& key) {
74 typename Container::const_iterator found = container.find(key);
75 if (found == container.end())
76 return typename Container::mapped_type();
77 return found->second;
80 void ReadDatabaseContents(LevelDBWrapper* db, DatabaseContents* contents) {
81 DCHECK(db);
82 DCHECK(contents);
84 scoped_ptr<LevelDBWrapper::Iterator> itr(db->NewIterator());
85 for (itr->SeekToFirst(); itr->Valid(); itr->Next()) {
86 std::string key = itr->key().ToString();
87 std::string value = itr->value().ToString();
89 std::string file_id;
90 if (RemovePrefix(key, kFileMetadataKeyPrefix, &file_id)) {
91 scoped_ptr<FileMetadata> metadata(new FileMetadata);
92 if (!metadata->ParseFromString(itr->value().ToString())) {
93 util::Log(logging::LOG_WARNING, FROM_HERE,
94 "Failed to parse a FileMetadata");
95 continue;
98 contents->file_metadata.push_back(metadata.release());
99 continue;
102 std::string tracker_id_str;
103 if (RemovePrefix(key, kFileTrackerKeyPrefix, &tracker_id_str)) {
104 int64 tracker_id = 0;
105 if (!base::StringToInt64(tracker_id_str, &tracker_id)) {
106 util::Log(logging::LOG_WARNING, FROM_HERE,
107 "Failed to parse TrackerID");
108 continue;
111 scoped_ptr<FileTracker> tracker(new FileTracker);
112 if (!tracker->ParseFromString(itr->value().ToString())) {
113 util::Log(logging::LOG_WARNING, FROM_HERE,
114 "Failed to parse a Tracker");
115 continue;
117 contents->file_trackers.push_back(tracker.release());
118 continue;
123 void RemoveUnreachableItems(DatabaseContents* contents,
124 int64 sync_root_tracker_id,
125 LevelDBWrapper* db) {
126 typedef std::map<int64, std::set<int64> > ChildTrackersByParent;
127 ChildTrackersByParent trackers_by_parent;
129 // Set up links from parent tracker to child trackers.
130 for (size_t i = 0; i < contents->file_trackers.size(); ++i) {
131 const FileTracker& tracker = *contents->file_trackers[i];
132 int64 parent_tracker_id = tracker.parent_tracker_id();
133 int64 tracker_id = tracker.tracker_id();
135 trackers_by_parent[parent_tracker_id].insert(tracker_id);
138 // Drop links from inactive trackers.
139 for (size_t i = 0; i < contents->file_trackers.size(); ++i) {
140 const FileTracker& tracker = *contents->file_trackers[i];
142 if (!tracker.active())
143 trackers_by_parent.erase(tracker.tracker_id());
146 std::vector<int64> pending;
147 if (sync_root_tracker_id != kInvalidTrackerID)
148 pending.push_back(sync_root_tracker_id);
150 // Traverse tracker tree from sync-root.
151 std::set<int64> visited_trackers;
152 while (!pending.empty()) {
153 int64 tracker_id = pending.back();
154 DCHECK_NE(kInvalidTrackerID, tracker_id);
155 pending.pop_back();
157 if (!visited_trackers.insert(tracker_id).second) {
158 NOTREACHED();
159 continue;
162 AppendContents(
163 LookUpMap(trackers_by_parent, tracker_id, std::set<int64>()),
164 &pending);
167 // Delete all unreachable trackers.
168 ScopedVector<FileTracker> reachable_trackers;
169 for (size_t i = 0; i < contents->file_trackers.size(); ++i) {
170 FileTracker* tracker = contents->file_trackers[i];
171 if (ContainsKey(visited_trackers, tracker->tracker_id())) {
172 reachable_trackers.push_back(tracker);
173 contents->file_trackers[i] = nullptr;
174 } else {
175 PutFileTrackerDeletionToDB(tracker->tracker_id(), db);
178 contents->file_trackers = reachable_trackers.Pass();
180 // List all |file_id| referred by a tracker.
181 base::hash_set<std::string> referred_file_ids;
182 for (size_t i = 0; i < contents->file_trackers.size(); ++i)
183 referred_file_ids.insert(contents->file_trackers[i]->file_id());
185 // Delete all unreferred metadata.
186 ScopedVector<FileMetadata> referred_file_metadata;
187 for (size_t i = 0; i < contents->file_metadata.size(); ++i) {
188 FileMetadata* metadata = contents->file_metadata[i];
189 if (ContainsKey(referred_file_ids, metadata->file_id())) {
190 referred_file_metadata.push_back(metadata);
191 contents->file_metadata[i] = nullptr;
192 } else {
193 PutFileMetadataDeletionToDB(metadata->file_id(), db);
196 contents->file_metadata = referred_file_metadata.Pass();
199 } // namespace
201 // static
202 scoped_ptr<MetadataDatabaseIndex>
203 MetadataDatabaseIndex::Create(LevelDBWrapper* db) {
204 DCHECK(db);
206 scoped_ptr<ServiceMetadata> service_metadata = InitializeServiceMetadata(db);
207 if (!service_metadata)
208 return scoped_ptr<MetadataDatabaseIndex>();
210 DatabaseContents contents;
211 PutVersionToDB(kCurrentDatabaseVersion, db);
212 ReadDatabaseContents(db, &contents);
213 RemoveUnreachableItems(&contents,
214 service_metadata->sync_root_tracker_id(),
215 db);
217 scoped_ptr<MetadataDatabaseIndex> index(new MetadataDatabaseIndex(db));
218 index->Initialize(service_metadata.Pass(), &contents);
219 return index.Pass();
222 // static
223 scoped_ptr<MetadataDatabaseIndex>
224 MetadataDatabaseIndex::CreateForTesting(DatabaseContents* contents,
225 LevelDBWrapper* db) {
226 scoped_ptr<MetadataDatabaseIndex> index(new MetadataDatabaseIndex(db));
227 index->Initialize(make_scoped_ptr(new ServiceMetadata), contents);
228 return index.Pass();
231 void MetadataDatabaseIndex::Initialize(
232 scoped_ptr<ServiceMetadata> service_metadata,
233 DatabaseContents* contents) {
234 service_metadata_ = service_metadata.Pass();
236 for (size_t i = 0; i < contents->file_metadata.size(); ++i)
237 StoreFileMetadata(make_scoped_ptr(contents->file_metadata[i]));
238 contents->file_metadata.weak_clear();
240 for (size_t i = 0; i < contents->file_trackers.size(); ++i)
241 StoreFileTracker(make_scoped_ptr(contents->file_trackers[i]));
242 contents->file_trackers.weak_clear();
244 UMA_HISTOGRAM_COUNTS("SyncFileSystem.MetadataNumber", metadata_by_id_.size());
245 UMA_HISTOGRAM_COUNTS("SyncFileSystem.TrackerNumber", tracker_by_id_.size());
246 UMA_HISTOGRAM_COUNTS_100("SyncFileSystem.RegisteredAppNumber",
247 app_root_by_app_id_.size());
250 MetadataDatabaseIndex::MetadataDatabaseIndex(LevelDBWrapper* db) : db_(db) {}
251 MetadataDatabaseIndex::~MetadataDatabaseIndex() {}
253 bool MetadataDatabaseIndex::GetFileMetadata(
254 const std::string& file_id, FileMetadata* metadata) const {
255 FileMetadata* identified = metadata_by_id_.get(file_id);
256 if (!identified)
257 return false;
258 if (metadata)
259 metadata->CopyFrom(*identified);
260 return true;
263 bool MetadataDatabaseIndex::GetFileTracker(
264 int64 tracker_id, FileTracker* tracker) const {
265 FileTracker* identified = tracker_by_id_.get(tracker_id);
266 if (!identified)
267 return false;
268 if (tracker)
269 tracker->CopyFrom(*identified);
270 return true;
273 void MetadataDatabaseIndex::StoreFileMetadata(
274 scoped_ptr<FileMetadata> metadata) {
275 PutFileMetadataToDB(*metadata.get(), db_);
276 if (!metadata) {
277 NOTREACHED();
278 return;
281 std::string file_id = metadata->file_id();
282 metadata_by_id_.set(file_id, metadata.Pass());
285 void MetadataDatabaseIndex::StoreFileTracker(
286 scoped_ptr<FileTracker> tracker) {
287 PutFileTrackerToDB(*tracker.get(), db_);
288 if (!tracker) {
289 NOTREACHED();
290 return;
293 int64 tracker_id = tracker->tracker_id();
294 FileTracker* old_tracker = tracker_by_id_.get(tracker_id);
296 if (!old_tracker) {
297 DVLOG(3) << "Adding new tracker: " << tracker->tracker_id()
298 << " " << GetTrackerTitle(*tracker);
300 AddToAppIDIndex(*tracker);
301 AddToPathIndexes(*tracker);
302 AddToFileIDIndexes(*tracker);
303 AddToDirtyTrackerIndexes(*tracker);
304 } else {
305 DVLOG(3) << "Updating tracker: " << tracker->tracker_id()
306 << " " << GetTrackerTitle(*tracker);
308 UpdateInAppIDIndex(*old_tracker, *tracker);
309 UpdateInPathIndexes(*old_tracker, *tracker);
310 UpdateInFileIDIndexes(*old_tracker, *tracker);
311 UpdateInDirtyTrackerIndexes(*old_tracker, *tracker);
314 tracker_by_id_.set(tracker_id, tracker.Pass());
317 void MetadataDatabaseIndex::RemoveFileMetadata(const std::string& file_id) {
318 PutFileMetadataDeletionToDB(file_id, db_);
319 metadata_by_id_.erase(file_id);
322 void MetadataDatabaseIndex::RemoveFileTracker(int64 tracker_id) {
323 PutFileTrackerDeletionToDB(tracker_id, db_);
325 FileTracker* tracker = tracker_by_id_.get(tracker_id);
326 if (!tracker) {
327 NOTREACHED();
328 return;
331 DVLOG(3) << "Removing tracker: "
332 << tracker->tracker_id() << " " << GetTrackerTitle(*tracker);
334 RemoveFromAppIDIndex(*tracker);
335 RemoveFromPathIndexes(*tracker);
336 RemoveFromFileIDIndexes(*tracker);
337 RemoveFromDirtyTrackerIndexes(*tracker);
339 tracker_by_id_.erase(tracker_id);
342 TrackerIDSet MetadataDatabaseIndex::GetFileTrackerIDsByFileID(
343 const std::string& file_id) const {
344 return FindItem(trackers_by_file_id_, file_id);
347 int64 MetadataDatabaseIndex::GetAppRootTracker(
348 const std::string& app_id) const {
349 return FindItem(app_root_by_app_id_, app_id);
352 TrackerIDSet MetadataDatabaseIndex::GetFileTrackerIDsByParentAndTitle(
353 int64 parent_tracker_id,
354 const std::string& title) const {
355 TrackerIDsByParentAndTitle::const_iterator found =
356 trackers_by_parent_and_title_.find(parent_tracker_id);
357 if (found == trackers_by_parent_and_title_.end())
358 return TrackerIDSet();
359 return FindItem(found->second, title);
362 std::vector<int64> MetadataDatabaseIndex::GetFileTrackerIDsByParent(
363 int64 parent_tracker_id) const {
364 std::vector<int64> result;
365 TrackerIDsByParentAndTitle::const_iterator found =
366 trackers_by_parent_and_title_.find(parent_tracker_id);
367 if (found == trackers_by_parent_and_title_.end())
368 return result;
370 for (TrackerIDsByTitle::const_iterator itr = found->second.begin();
371 itr != found->second.end(); ++itr) {
372 result.insert(result.end(), itr->second.begin(), itr->second.end());
375 return result;
378 std::string MetadataDatabaseIndex::PickMultiTrackerFileID() const {
379 if (multi_tracker_file_ids_.empty())
380 return std::string();
381 return *multi_tracker_file_ids_.begin();
384 ParentIDAndTitle MetadataDatabaseIndex::PickMultiBackingFilePath() const {
385 if (multi_backing_file_paths_.empty())
386 return ParentIDAndTitle(kInvalidTrackerID, std::string());
387 return *multi_backing_file_paths_.begin();
390 int64 MetadataDatabaseIndex::PickDirtyTracker() const {
391 if (dirty_trackers_.empty())
392 return kInvalidTrackerID;
393 return *dirty_trackers_.begin();
396 void MetadataDatabaseIndex::DemoteDirtyTracker(int64 tracker_id) {
397 if (dirty_trackers_.erase(tracker_id))
398 demoted_dirty_trackers_.insert(tracker_id);
401 bool MetadataDatabaseIndex::HasDemotedDirtyTracker() const {
402 return !demoted_dirty_trackers_.empty();
405 bool MetadataDatabaseIndex::IsDemotedDirtyTracker(int64 tracker_id) const {
406 return demoted_dirty_trackers_.find(tracker_id) !=
407 demoted_dirty_trackers_.end();
410 void MetadataDatabaseIndex::PromoteDemotedDirtyTracker(int64 tracker_id) {
411 if (demoted_dirty_trackers_.erase(tracker_id) == 1)
412 dirty_trackers_.insert(tracker_id);
415 bool MetadataDatabaseIndex::PromoteDemotedDirtyTrackers() {
416 bool promoted = !demoted_dirty_trackers_.empty();
417 dirty_trackers_.insert(demoted_dirty_trackers_.begin(),
418 demoted_dirty_trackers_.end());
419 demoted_dirty_trackers_.clear();
420 return promoted;
423 size_t MetadataDatabaseIndex::CountDirtyTracker() const {
424 return dirty_trackers_.size();
427 size_t MetadataDatabaseIndex::CountFileMetadata() const {
428 return metadata_by_id_.size();
431 size_t MetadataDatabaseIndex::CountFileTracker() const {
432 return tracker_by_id_.size();
435 void MetadataDatabaseIndex::SetSyncRootTrackerID(
436 int64 sync_root_id) const {
437 service_metadata_->set_sync_root_tracker_id(sync_root_id);
438 PutServiceMetadataToDB(*service_metadata_, db_);
441 void MetadataDatabaseIndex::SetLargestChangeID(
442 int64 largest_change_id) const {
443 service_metadata_->set_largest_change_id(largest_change_id);
444 PutServiceMetadataToDB(*service_metadata_, db_);
447 void MetadataDatabaseIndex::SetNextTrackerID(
448 int64 next_tracker_id) const {
449 service_metadata_->set_next_tracker_id(next_tracker_id);
450 PutServiceMetadataToDB(*service_metadata_, db_);
453 int64 MetadataDatabaseIndex::GetSyncRootTrackerID() const {
454 if (!service_metadata_->has_sync_root_tracker_id())
455 return kInvalidTrackerID;
456 return service_metadata_->sync_root_tracker_id();
459 int64 MetadataDatabaseIndex::GetLargestChangeID() const {
460 if (!service_metadata_->has_largest_change_id())
461 return kInvalidTrackerID;
462 return service_metadata_->largest_change_id();
465 int64 MetadataDatabaseIndex::GetNextTrackerID() const {
466 if (!service_metadata_->has_next_tracker_id()) {
467 NOTREACHED();
468 return kInvalidTrackerID;
470 return service_metadata_->next_tracker_id();
473 std::vector<std::string> MetadataDatabaseIndex::GetRegisteredAppIDs() const {
474 std::vector<std::string> result;
475 result.reserve(app_root_by_app_id_.size());
476 for (TrackerIDByAppID::const_iterator itr = app_root_by_app_id_.begin();
477 itr != app_root_by_app_id_.end(); ++itr)
478 result.push_back(itr->first);
479 return result;
482 std::vector<int64> MetadataDatabaseIndex::GetAllTrackerIDs() const {
483 std::vector<int64> result;
484 for (TrackerByID::const_iterator itr = tracker_by_id_.begin();
485 itr != tracker_by_id_.end(); ++itr) {
486 result.push_back(itr->first);
488 return result;
491 std::vector<std::string> MetadataDatabaseIndex::GetAllMetadataIDs() const {
492 std::vector<std::string> result;
493 for (MetadataByID::const_iterator itr = metadata_by_id_.begin();
494 itr != metadata_by_id_.end(); ++itr) {
495 result.push_back(itr->first);
497 return result;
500 void MetadataDatabaseIndex::AddToAppIDIndex(
501 const FileTracker& new_tracker) {
502 if (!IsAppRoot(new_tracker))
503 return;
505 DVLOG(3) << " Add to app_root_by_app_id_: " << new_tracker.app_id();
507 DCHECK(new_tracker.active());
508 DCHECK(!ContainsKey(app_root_by_app_id_, new_tracker.app_id()));
509 app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id();
512 void MetadataDatabaseIndex::UpdateInAppIDIndex(
513 const FileTracker& old_tracker,
514 const FileTracker& new_tracker) {
515 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id());
517 if (IsAppRoot(old_tracker) && !IsAppRoot(new_tracker)) {
518 DCHECK(old_tracker.active());
519 DCHECK(!new_tracker.active());
520 DCHECK(ContainsKey(app_root_by_app_id_, old_tracker.app_id()));
522 DVLOG(3) << " Remove from app_root_by_app_id_: " << old_tracker.app_id();
524 app_root_by_app_id_.erase(old_tracker.app_id());
525 } else if (!IsAppRoot(old_tracker) && IsAppRoot(new_tracker)) {
526 DCHECK(!old_tracker.active());
527 DCHECK(new_tracker.active());
528 DCHECK(!ContainsKey(app_root_by_app_id_, new_tracker.app_id()));
530 DVLOG(3) << " Add to app_root_by_app_id_: " << new_tracker.app_id();
532 app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id();
536 void MetadataDatabaseIndex::RemoveFromAppIDIndex(
537 const FileTracker& tracker) {
538 if (IsAppRoot(tracker)) {
539 DCHECK(tracker.active());
540 DCHECK(ContainsKey(app_root_by_app_id_, tracker.app_id()));
542 DVLOG(3) << " Remove from app_root_by_app_id_: " << tracker.app_id();
544 app_root_by_app_id_.erase(tracker.app_id());
548 void MetadataDatabaseIndex::AddToFileIDIndexes(
549 const FileTracker& new_tracker) {
550 DVLOG(3) << " Add to trackers_by_file_id_: " << new_tracker.file_id();
552 trackers_by_file_id_[new_tracker.file_id()].Insert(new_tracker);
554 if (trackers_by_file_id_[new_tracker.file_id()].size() > 1) {
555 DVLOG_IF(3, !ContainsKey(multi_tracker_file_ids_, new_tracker.file_id()))
556 << " Add to multi_tracker_file_ids_: " << new_tracker.file_id();
557 multi_tracker_file_ids_.insert(new_tracker.file_id());
561 void MetadataDatabaseIndex::UpdateInFileIDIndexes(
562 const FileTracker& old_tracker,
563 const FileTracker& new_tracker) {
564 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id());
565 DCHECK_EQ(old_tracker.file_id(), new_tracker.file_id());
567 std::string file_id = new_tracker.file_id();
568 DCHECK(ContainsKey(trackers_by_file_id_, file_id));
570 if (old_tracker.active() && !new_tracker.active())
571 trackers_by_file_id_[file_id].Deactivate(new_tracker.tracker_id());
572 else if (!old_tracker.active() && new_tracker.active())
573 trackers_by_file_id_[file_id].Activate(new_tracker.tracker_id());
576 void MetadataDatabaseIndex::RemoveFromFileIDIndexes(
577 const FileTracker& tracker) {
578 TrackerIDsByFileID::iterator found =
579 trackers_by_file_id_.find(tracker.file_id());
580 if (found == trackers_by_file_id_.end()) {
581 NOTREACHED();
582 return;
585 DVLOG(3) << " Remove from trackers_by_file_id_: "
586 << tracker.tracker_id();
587 found->second.Erase(tracker.tracker_id());
589 if (trackers_by_file_id_[tracker.file_id()].size() <= 1) {
590 DVLOG_IF(3, ContainsKey(multi_tracker_file_ids_, tracker.file_id()))
591 << " Remove from multi_tracker_file_ids_: " << tracker.file_id();
592 multi_tracker_file_ids_.erase(tracker.file_id());
595 if (found->second.empty())
596 trackers_by_file_id_.erase(found);
599 void MetadataDatabaseIndex::AddToPathIndexes(
600 const FileTracker& new_tracker) {
601 int64 parent = new_tracker.parent_tracker_id();
602 std::string title = GetTrackerTitle(new_tracker);
604 DVLOG(3) << " Add to trackers_by_parent_and_title_: "
605 << parent << " " << title;
607 trackers_by_parent_and_title_[parent][title].Insert(new_tracker);
609 if (trackers_by_parent_and_title_[parent][title].size() > 1 &&
610 !title.empty()) {
611 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_,
612 ParentIDAndTitle(parent, title)))
613 << " Add to multi_backing_file_paths_: " << parent << " " << title;
614 multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title));
618 void MetadataDatabaseIndex::UpdateInPathIndexes(
619 const FileTracker& old_tracker,
620 const FileTracker& new_tracker) {
621 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id());
622 DCHECK_EQ(old_tracker.parent_tracker_id(), new_tracker.parent_tracker_id());
623 DCHECK(GetTrackerTitle(old_tracker) == GetTrackerTitle(new_tracker) ||
624 !old_tracker.has_synced_details());
626 int64 tracker_id = new_tracker.tracker_id();
627 int64 parent = new_tracker.parent_tracker_id();
628 std::string old_title = GetTrackerTitle(old_tracker);
629 std::string title = GetTrackerTitle(new_tracker);
631 TrackerIDsByTitle* trackers_by_title = &trackers_by_parent_and_title_[parent];
633 if (old_title != title) {
634 TrackerIDsByTitle::iterator found = trackers_by_title->find(old_title);
635 if (found != trackers_by_title->end()) {
636 DVLOG(3) << " Remove from trackers_by_parent_and_title_: "
637 << parent << " " << old_title;
639 found->second.Erase(tracker_id);
640 if (found->second.empty())
641 trackers_by_title->erase(found);
642 } else {
643 NOTREACHED();
646 DVLOG(3) << " Add to trackers_by_parent_and_title_: "
647 << parent << " " << title;
649 (*trackers_by_title)[title].Insert(new_tracker);
651 if (trackers_by_parent_and_title_[parent][old_title].size() <= 1 &&
652 !old_title.empty()) {
653 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_,
654 ParentIDAndTitle(parent, old_title)))
655 << " Remove from multi_backing_file_paths_: "
656 << parent << " " << old_title;
657 multi_backing_file_paths_.erase(ParentIDAndTitle(parent, old_title));
660 if (trackers_by_parent_and_title_[parent][title].size() > 1 &&
661 !title.empty()) {
662 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_,
663 ParentIDAndTitle(parent, title)))
664 << " Add to multi_backing_file_paths_: " << parent << " " << title;
665 multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title));
668 return;
671 if (old_tracker.active() && !new_tracker.active())
672 trackers_by_parent_and_title_[parent][title].Deactivate(tracker_id);
673 else if (!old_tracker.active() && new_tracker.active())
674 trackers_by_parent_and_title_[parent][title].Activate(tracker_id);
677 void MetadataDatabaseIndex::RemoveFromPathIndexes(
678 const FileTracker& tracker) {
679 int64 tracker_id = tracker.tracker_id();
680 int64 parent = tracker.parent_tracker_id();
681 std::string title = GetTrackerTitle(tracker);
683 DCHECK(ContainsKey(trackers_by_parent_and_title_, parent));
684 DCHECK(ContainsKey(trackers_by_parent_and_title_[parent], title));
686 DVLOG(3) << " Remove from trackers_by_parent_and_title_: "
687 << parent << " " << title;
689 trackers_by_parent_and_title_[parent][title].Erase(tracker_id);
691 if (trackers_by_parent_and_title_[parent][title].size() <= 1 &&
692 !title.empty()) {
693 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_,
694 ParentIDAndTitle(parent, title)))
695 << " Remove from multi_backing_file_paths_: "
696 << parent << " " << title;
697 multi_backing_file_paths_.erase(ParentIDAndTitle(parent, title));
700 if (trackers_by_parent_and_title_[parent][title].empty()) {
701 trackers_by_parent_and_title_[parent].erase(title);
702 if (trackers_by_parent_and_title_[parent].empty())
703 trackers_by_parent_and_title_.erase(parent);
707 void MetadataDatabaseIndex::AddToDirtyTrackerIndexes(
708 const FileTracker& new_tracker) {
709 DCHECK(!ContainsKey(dirty_trackers_, new_tracker.tracker_id()));
710 DCHECK(!ContainsKey(demoted_dirty_trackers_, new_tracker.tracker_id()));
712 if (new_tracker.dirty()) {
713 DVLOG(3) << " Add to dirty_trackers_: " << new_tracker.tracker_id();
714 dirty_trackers_.insert(new_tracker.tracker_id());
718 void MetadataDatabaseIndex::UpdateInDirtyTrackerIndexes(
719 const FileTracker& old_tracker,
720 const FileTracker& new_tracker) {
721 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id());
723 int64 tracker_id = new_tracker.tracker_id();
724 if (old_tracker.dirty() && !new_tracker.dirty()) {
725 DCHECK(ContainsKey(dirty_trackers_, tracker_id) ||
726 ContainsKey(demoted_dirty_trackers_, tracker_id));
728 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id;
730 dirty_trackers_.erase(tracker_id);
731 demoted_dirty_trackers_.erase(tracker_id);
732 } else if (!old_tracker.dirty() && new_tracker.dirty()) {
733 DCHECK(!ContainsKey(dirty_trackers_, tracker_id));
734 DCHECK(!ContainsKey(demoted_dirty_trackers_, tracker_id));
736 DVLOG(3) << " Add to dirty_trackers_: " << tracker_id;
738 dirty_trackers_.insert(tracker_id);
742 void MetadataDatabaseIndex::RemoveFromDirtyTrackerIndexes(
743 const FileTracker& tracker) {
744 if (tracker.dirty()) {
745 int64 tracker_id = tracker.tracker_id();
746 DCHECK(ContainsKey(dirty_trackers_, tracker_id) ||
747 ContainsKey(demoted_dirty_trackers_, tracker_id));
749 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id;
750 dirty_trackers_.erase(tracker_id);
752 demoted_dirty_trackers_.erase(tracker_id);
756 } // namespace drive_backend
757 } // namespace sync_file_system