Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / drive_backend / metadata_database_index.cc
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.
4
5 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index.h"
6
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"
19
20 // LevelDB database schema
21 // =======================
22 //
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.
28 //
29 // Version 3
30 //   # Version of this schema
31 //   key: "VERSION"
32 //   value: "3"
33 //
34 //   # Metadata of the SyncFS service
35 //   key: "SERVICE"
36 //   value: <ServiceMetadata 'service_metadata'>
37 //
38 //   # Metadata of remote files
39 //   key: "FILE: " + <string 'file_id'>
40 //   value: <FileMetadata 'metadata'>
41 //
42 //   # Trackers of local file updates
43 //   key: "TRACKER: " + <int64 'tracker_id'>
44 //   value: <FileTracker 'tracker'>
45
46 namespace sync_file_system {
47 namespace drive_backend {
48
49 ParentIDAndTitle::ParentIDAndTitle() : parent_id(0) {}
50 ParentIDAndTitle::ParentIDAndTitle(int64 parent_id,
51                                    const std::string& title)
52     : parent_id(parent_id), title(title) {}
53
54 bool operator==(const ParentIDAndTitle& left, const ParentIDAndTitle& right) {
55   return left.parent_id == right.parent_id && left.title == right.title;
56 }
57
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;
62 }
63
64 DatabaseContents::DatabaseContents() {}
65
66 DatabaseContents::~DatabaseContents() {}
67
68 namespace {
69
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;
78 }
79
80 void ReadDatabaseContents(LevelDBWrapper* db, DatabaseContents* contents) {
81   DCHECK(db);
82   DCHECK(contents);
83
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();
88
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;
96       }
97
98       contents->file_metadata.push_back(metadata.release());
99       continue;
100     }
101
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;
109       }
110
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;
116       }
117       contents->file_trackers.push_back(tracker.release());
118       continue;
119     }
120   }
121 }
122
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;
128
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();
134
135     trackers_by_parent[parent_tracker_id].insert(tracker_id);
136   }
137
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];
141
142     if (!tracker.active())
143       trackers_by_parent.erase(tracker.tracker_id());
144   }
145
146   std::vector<int64> pending;
147   if (sync_root_tracker_id != kInvalidTrackerID)
148     pending.push_back(sync_root_tracker_id);
149
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();
156
157     if (!visited_trackers.insert(tracker_id).second) {
158       NOTREACHED();
159       continue;
160     }
161
162     AppendContents(
163         LookUpMap(trackers_by_parent, tracker_id, std::set<int64>()),
164         &pending);
165   }
166
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);
176     }
177   }
178   contents->file_trackers = reachable_trackers.Pass();
179
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());
184
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);
194     }
195   }
196   contents->file_metadata = referred_file_metadata.Pass();
197 }
198
199 }  // namespace
200
201 // static
202 scoped_ptr<MetadataDatabaseIndex>
203 MetadataDatabaseIndex::Create(LevelDBWrapper* db) {
204   DCHECK(db);
205
206   scoped_ptr<ServiceMetadata> service_metadata = InitializeServiceMetadata(db);
207   if (!service_metadata)
208     return scoped_ptr<MetadataDatabaseIndex>();
209
210   DatabaseContents contents;
211   PutVersionToDB(kCurrentDatabaseVersion, db);
212   ReadDatabaseContents(db, &contents);
213   RemoveUnreachableItems(&contents,
214                          service_metadata->sync_root_tracker_id(),
215                          db);
216
217   scoped_ptr<MetadataDatabaseIndex> index(new MetadataDatabaseIndex(db));
218   index->Initialize(service_metadata.Pass(), &contents);
219   return index.Pass();
220 }
221
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();
229 }
230
231 void MetadataDatabaseIndex::Initialize(
232     scoped_ptr<ServiceMetadata> service_metadata,
233     DatabaseContents* contents) {
234   service_metadata_ = service_metadata.Pass();
235
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();
239
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();
243
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());
248 }
249
250 MetadataDatabaseIndex::MetadataDatabaseIndex(LevelDBWrapper* db) : db_(db) {}
251 MetadataDatabaseIndex::~MetadataDatabaseIndex() {}
252
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;
261 }
262
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;
271 }
272
273 void MetadataDatabaseIndex::StoreFileMetadata(
274     scoped_ptr<FileMetadata> metadata) {
275   PutFileMetadataToDB(*metadata.get(), db_);
276   if (!metadata) {
277     NOTREACHED();
278     return;
279   }
280
281   std::string file_id = metadata->file_id();
282   metadata_by_id_.set(file_id, metadata.Pass());
283 }
284
285 void MetadataDatabaseIndex::StoreFileTracker(
286     scoped_ptr<FileTracker> tracker) {
287   PutFileTrackerToDB(*tracker.get(), db_);
288   if (!tracker) {
289     NOTREACHED();
290     return;
291   }
292
293   int64 tracker_id = tracker->tracker_id();
294   FileTracker* old_tracker = tracker_by_id_.get(tracker_id);
295
296   if (!old_tracker) {
297     DVLOG(3) << "Adding new tracker: " << tracker->tracker_id()
298              << " " << GetTrackerTitle(*tracker);
299
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);
307
308     UpdateInAppIDIndex(*old_tracker, *tracker);
309     UpdateInPathIndexes(*old_tracker, *tracker);
310     UpdateInFileIDIndexes(*old_tracker, *tracker);
311     UpdateInDirtyTrackerIndexes(*old_tracker, *tracker);
312   }
313
314   tracker_by_id_.set(tracker_id, tracker.Pass());
315 }
316
317 void MetadataDatabaseIndex::RemoveFileMetadata(const std::string& file_id) {
318   PutFileMetadataDeletionToDB(file_id, db_);
319   metadata_by_id_.erase(file_id);
320 }
321
322 void MetadataDatabaseIndex::RemoveFileTracker(int64 tracker_id) {
323   PutFileTrackerDeletionToDB(tracker_id, db_);
324
325   FileTracker* tracker = tracker_by_id_.get(tracker_id);
326   if (!tracker) {
327     NOTREACHED();
328     return;
329   }
330
331   DVLOG(3) << "Removing tracker: "
332            << tracker->tracker_id() << " " << GetTrackerTitle(*tracker);
333
334   RemoveFromAppIDIndex(*tracker);
335   RemoveFromPathIndexes(*tracker);
336   RemoveFromFileIDIndexes(*tracker);
337   RemoveFromDirtyTrackerIndexes(*tracker);
338
339   tracker_by_id_.erase(tracker_id);
340 }
341
342 TrackerIDSet MetadataDatabaseIndex::GetFileTrackerIDsByFileID(
343     const std::string& file_id) const {
344   return FindItem(trackers_by_file_id_, file_id);
345 }
346
347 int64 MetadataDatabaseIndex::GetAppRootTracker(
348     const std::string& app_id) const {
349   return FindItem(app_root_by_app_id_, app_id);
350 }
351
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);
360 }
361
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;
369
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());
373   }
374
375   return result;
376 }
377
378 std::string MetadataDatabaseIndex::PickMultiTrackerFileID() const {
379   if (multi_tracker_file_ids_.empty())
380     return std::string();
381   return *multi_tracker_file_ids_.begin();
382 }
383
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();
388 }
389
390 int64 MetadataDatabaseIndex::PickDirtyTracker() const {
391   if (dirty_trackers_.empty())
392     return kInvalidTrackerID;
393   return *dirty_trackers_.begin();
394 }
395
396 void MetadataDatabaseIndex::DemoteDirtyTracker(int64 tracker_id) {
397   if (dirty_trackers_.erase(tracker_id))
398     demoted_dirty_trackers_.insert(tracker_id);
399 }
400
401 bool MetadataDatabaseIndex::HasDemotedDirtyTracker() const {
402   return !demoted_dirty_trackers_.empty();
403 }
404
405 bool MetadataDatabaseIndex::IsDemotedDirtyTracker(int64 tracker_id) const {
406   return demoted_dirty_trackers_.find(tracker_id) !=
407       demoted_dirty_trackers_.end();
408 }
409
410 void MetadataDatabaseIndex::PromoteDemotedDirtyTracker(int64 tracker_id) {
411   if (demoted_dirty_trackers_.erase(tracker_id) == 1)
412     dirty_trackers_.insert(tracker_id);
413 }
414
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;
421 }
422
423 size_t MetadataDatabaseIndex::CountDirtyTracker() const {
424   return dirty_trackers_.size();
425 }
426
427 size_t MetadataDatabaseIndex::CountFileMetadata() const {
428   return metadata_by_id_.size();
429 }
430
431 size_t MetadataDatabaseIndex::CountFileTracker() const {
432   return tracker_by_id_.size();
433 }
434
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_);
439 }
440
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_);
445 }
446
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_);
451 }
452
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();
457 }
458
459 int64 MetadataDatabaseIndex::GetLargestChangeID() const {
460   if (!service_metadata_->has_largest_change_id())
461     return kInvalidTrackerID;
462   return service_metadata_->largest_change_id();
463 }
464
465 int64 MetadataDatabaseIndex::GetNextTrackerID() const {
466   if (!service_metadata_->has_next_tracker_id()) {
467     NOTREACHED();
468     return kInvalidTrackerID;
469   }
470   return service_metadata_->next_tracker_id();
471 }
472
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;
480 }
481
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);
487   }
488   return result;
489 }
490
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);
496   }
497   return result;
498 }
499
500 void MetadataDatabaseIndex::AddToAppIDIndex(
501     const FileTracker& new_tracker) {
502   if (!IsAppRoot(new_tracker))
503     return;
504
505   DVLOG(3) << "  Add to app_root_by_app_id_: " << new_tracker.app_id();
506
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();
510 }
511
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());
516
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()));
521
522     DVLOG(3) << "  Remove from app_root_by_app_id_: " << old_tracker.app_id();
523
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()));
529
530     DVLOG(3) << "  Add to app_root_by_app_id_: " << new_tracker.app_id();
531
532     app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id();
533   }
534 }
535
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()));
541
542     DVLOG(3) << "  Remove from app_root_by_app_id_: " << tracker.app_id();
543
544     app_root_by_app_id_.erase(tracker.app_id());
545   }
546 }
547
548 void MetadataDatabaseIndex::AddToFileIDIndexes(
549     const FileTracker& new_tracker) {
550   DVLOG(3) << "  Add to trackers_by_file_id_: " << new_tracker.file_id();
551
552   trackers_by_file_id_[new_tracker.file_id()].Insert(new_tracker);
553
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());
558   }
559 }
560
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());
566
567   std::string file_id = new_tracker.file_id();
568   DCHECK(ContainsKey(trackers_by_file_id_, file_id));
569
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());
574 }
575
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;
583   }
584
585   DVLOG(3) << "  Remove from trackers_by_file_id_: "
586            << tracker.tracker_id();
587   found->second.Erase(tracker.tracker_id());
588
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());
593   }
594
595   if (found->second.empty())
596     trackers_by_file_id_.erase(found);
597 }
598
599 void MetadataDatabaseIndex::AddToPathIndexes(
600     const FileTracker& new_tracker) {
601   int64 parent = new_tracker.parent_tracker_id();
602   std::string title = GetTrackerTitle(new_tracker);
603
604   DVLOG(3) << "  Add to trackers_by_parent_and_title_: "
605            << parent << " " << title;
606
607   trackers_by_parent_and_title_[parent][title].Insert(new_tracker);
608
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));
615   }
616 }
617
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());
625
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);
630
631   TrackerIDsByTitle* trackers_by_title = &trackers_by_parent_and_title_[parent];
632
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;
638
639       found->second.Erase(tracker_id);
640       if (found->second.empty())
641         trackers_by_title->erase(found);
642     } else {
643       NOTREACHED();
644     }
645
646     DVLOG(3) << "  Add to trackers_by_parent_and_title_: "
647              << parent << " " << title;
648
649     (*trackers_by_title)[title].Insert(new_tracker);
650
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));
658     }
659
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));
666     }
667
668     return;
669   }
670
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);
675 }
676
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);
682
683   DCHECK(ContainsKey(trackers_by_parent_and_title_, parent));
684   DCHECK(ContainsKey(trackers_by_parent_and_title_[parent], title));
685
686   DVLOG(3) << "  Remove from trackers_by_parent_and_title_: "
687            << parent << " " << title;
688
689   trackers_by_parent_and_title_[parent][title].Erase(tracker_id);
690
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));
698   }
699
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);
704   }
705 }
706
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()));
711
712   if (new_tracker.dirty()) {
713     DVLOG(3) << "  Add to dirty_trackers_: " << new_tracker.tracker_id();
714     dirty_trackers_.insert(new_tracker.tracker_id());
715   }
716 }
717
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());
722
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));
727
728     DVLOG(3) << "  Remove from dirty_trackers_: " << tracker_id;
729
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));
735
736     DVLOG(3) << "  Add to dirty_trackers_: " << tracker_id;
737
738     dirty_trackers_.insert(tracker_id);
739   }
740 }
741
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));
748
749     DVLOG(3) << "  Remove from dirty_trackers_: " << tracker_id;
750     dirty_trackers_.erase(tracker_id);
751
752     demoted_dirty_trackers_.erase(tracker_id);
753   }
754 }
755
756 }  // namespace drive_backend
757 }  // namespace sync_file_system