Home | History | Annotate | Download | only in drive_backend
      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 "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
      9 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
     10 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
     11 
     12 namespace sync_file_system {
     13 namespace drive_backend {
     14 
     15 ParentIDAndTitle::ParentIDAndTitle() : parent_id(0) {}
     16 ParentIDAndTitle::ParentIDAndTitle(int64 parent_id,
     17                                    const std::string& title)
     18     : parent_id(parent_id), title(title) {}
     19 
     20 bool operator==(const ParentIDAndTitle& left, const ParentIDAndTitle& right) {
     21   return left.parent_id == right.parent_id && left.title == right.title;
     22 }
     23 
     24 bool operator<(const ParentIDAndTitle& left, const ParentIDAndTitle& right) {
     25   if (left.parent_id != right.parent_id)
     26     return left.parent_id < right.parent_id;
     27   return left.title < right.title;
     28 }
     29 
     30 namespace {
     31 
     32 template <typename Container>
     33 typename Container::mapped_type FindItem(
     34     const Container& container,
     35     const typename Container::key_type& key) {
     36   typename Container::const_iterator found = container.find(key);
     37   if (found == container.end())
     38     return typename Container::mapped_type();
     39   return found->second;
     40 }
     41 
     42 bool IsAppRoot(const FileTracker& tracker) {
     43   return tracker.tracker_kind() == TRACKER_KIND_APP_ROOT ||
     44       tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT;
     45 }
     46 
     47 std::string GetTrackerTitle(const FileTracker& tracker) {
     48   if (tracker.has_synced_details())
     49     return tracker.synced_details().title();
     50   return std::string();
     51 }
     52 
     53 }  // namespace
     54 
     55 MetadataDatabaseIndex::MetadataDatabaseIndex(DatabaseContents* content) {
     56   for (size_t i = 0; i < content->file_metadata.size(); ++i)
     57     StoreFileMetadata(make_scoped_ptr(content->file_metadata[i]));
     58   content->file_metadata.weak_clear();
     59 
     60   for (size_t i = 0; i < content->file_trackers.size(); ++i)
     61     StoreFileTracker(make_scoped_ptr(content->file_trackers[i]));
     62   content->file_trackers.weak_clear();
     63 
     64   UMA_HISTOGRAM_COUNTS("SyncFileSystem.MetadataNumber", metadata_by_id_.size());
     65   UMA_HISTOGRAM_COUNTS("SyncFileSystem.TrackerNumber", tracker_by_id_.size());
     66   UMA_HISTOGRAM_COUNTS_100("SyncFileSystem.RegisteredAppNumber",
     67                            app_root_by_app_id_.size());
     68 }
     69 
     70 MetadataDatabaseIndex::~MetadataDatabaseIndex() {}
     71 
     72 const FileTracker* MetadataDatabaseIndex::GetFileTracker(
     73     int64 tracker_id) const {
     74   return tracker_by_id_.get(tracker_id);
     75 }
     76 
     77 const FileMetadata* MetadataDatabaseIndex::GetFileMetadata(
     78     const std::string& file_id) const {
     79   return metadata_by_id_.get(file_id);
     80 }
     81 
     82 void MetadataDatabaseIndex::StoreFileMetadata(
     83     scoped_ptr<FileMetadata> metadata) {
     84   if (!metadata) {
     85     NOTREACHED();
     86     return;
     87   }
     88 
     89   std::string file_id = metadata->file_id();
     90   metadata_by_id_.set(file_id, metadata.Pass());
     91 }
     92 
     93 void MetadataDatabaseIndex::StoreFileTracker(scoped_ptr<FileTracker> tracker) {
     94   if (!tracker) {
     95     NOTREACHED();
     96     return;
     97   }
     98 
     99   int64 tracker_id = tracker->tracker_id();
    100   FileTracker* old_tracker = tracker_by_id_.get(tracker_id);
    101 
    102   if (!old_tracker) {
    103     DVLOG(3) << "Adding new tracker: " << tracker->tracker_id()
    104              << " " << GetTrackerTitle(*tracker);
    105 
    106     AddToAppIDIndex(*tracker);
    107     AddToPathIndexes(*tracker);
    108     AddToFileIDIndexes(*tracker);
    109     AddToDirtyTrackerIndexes(*tracker);
    110   } else {
    111     DVLOG(3) << "Updating tracker: " << tracker->tracker_id()
    112              << " " << GetTrackerTitle(*tracker);
    113 
    114     UpdateInAppIDIndex(*old_tracker, *tracker);
    115     UpdateInPathIndexes(*old_tracker, *tracker);
    116     UpdateInFileIDIndexes(*old_tracker, *tracker);
    117     UpdateInDirtyTrackerIndexes(*old_tracker, *tracker);
    118   }
    119 
    120   tracker_by_id_.set(tracker_id, tracker.Pass());
    121 }
    122 
    123 void MetadataDatabaseIndex::RemoveFileMetadata(const std::string& file_id) {
    124   metadata_by_id_.erase(file_id);
    125 }
    126 
    127 void MetadataDatabaseIndex::RemoveFileTracker(int64 tracker_id) {
    128   FileTracker* tracker = tracker_by_id_.get(tracker_id);
    129   if (!tracker) {
    130     NOTREACHED();
    131     return;
    132   }
    133 
    134   DVLOG(3) << "Removing tracker: "
    135            << tracker->tracker_id() << " " << GetTrackerTitle(*tracker);
    136 
    137   RemoveFromAppIDIndex(*tracker);
    138   RemoveFromPathIndexes(*tracker);
    139   RemoveFromFileIDIndexes(*tracker);
    140   RemoveFromDirtyTrackerIndexes(*tracker);
    141 
    142   tracker_by_id_.erase(tracker_id);
    143 }
    144 
    145 TrackerIDSet MetadataDatabaseIndex::GetFileTrackerIDsByFileID(
    146     const std::string& file_id) const {
    147   return FindItem(trackers_by_file_id_, file_id);
    148 }
    149 
    150 int64 MetadataDatabaseIndex::GetAppRootTracker(
    151     const std::string& app_id) const {
    152   return FindItem(app_root_by_app_id_, app_id);
    153 }
    154 
    155 TrackerIDSet MetadataDatabaseIndex::GetFileTrackerIDsByParentAndTitle(
    156     int64 parent_tracker_id,
    157     const std::string& title) const {
    158   TrackerIDsByParentAndTitle::const_iterator found =
    159       trackers_by_parent_and_title_.find(parent_tracker_id);
    160   if (found == trackers_by_parent_and_title_.end())
    161     return TrackerIDSet();
    162   return FindItem(found->second, title);
    163 }
    164 
    165 std::vector<int64> MetadataDatabaseIndex::GetFileTrackerIDsByParent(
    166     int64 parent_tracker_id) const {
    167   std::vector<int64> result;
    168   TrackerIDsByParentAndTitle::const_iterator found =
    169       trackers_by_parent_and_title_.find(parent_tracker_id);
    170   if (found == trackers_by_parent_and_title_.end())
    171     return result;
    172 
    173   for (TrackerIDsByTitle::const_iterator itr = found->second.begin();
    174        itr != found->second.end(); ++itr) {
    175     result.insert(result.end(), itr->second.begin(), itr->second.end());
    176   }
    177 
    178   return result;
    179 }
    180 
    181 std::string MetadataDatabaseIndex::PickMultiTrackerFileID() const {
    182   if (multi_tracker_file_ids_.empty())
    183     return std::string();
    184   return *multi_tracker_file_ids_.begin();
    185 }
    186 
    187 ParentIDAndTitle MetadataDatabaseIndex::PickMultiBackingFilePath() const {
    188   if (multi_backing_file_paths_.empty())
    189     return ParentIDAndTitle(kInvalidTrackerID, std::string());
    190   return *multi_backing_file_paths_.begin();
    191 }
    192 
    193 int64 MetadataDatabaseIndex::PickDirtyTracker() const {
    194   if (dirty_trackers_.empty())
    195     return kInvalidTrackerID;
    196   return *dirty_trackers_.begin();
    197 }
    198 
    199 void MetadataDatabaseIndex::DemoteDirtyTracker(int64 tracker_id) {
    200   if (dirty_trackers_.erase(tracker_id))
    201     demoted_dirty_trackers_.insert(tracker_id);
    202 }
    203 
    204 bool MetadataDatabaseIndex::HasDemotedDirtyTracker() const {
    205   return !demoted_dirty_trackers_.empty();
    206 }
    207 
    208 void MetadataDatabaseIndex::PromoteDemotedDirtyTrackers() {
    209   dirty_trackers_.insert(demoted_dirty_trackers_.begin(),
    210                          demoted_dirty_trackers_.end());
    211   demoted_dirty_trackers_.clear();
    212 }
    213 
    214 size_t MetadataDatabaseIndex::CountDirtyTracker() const {
    215   return dirty_trackers_.size() + demoted_dirty_trackers_.size();
    216 }
    217 
    218 size_t MetadataDatabaseIndex::CountFileMetadata() const {
    219   return metadata_by_id_.size();
    220 }
    221 
    222 size_t MetadataDatabaseIndex::CountFileTracker() const {
    223   return tracker_by_id_.size();
    224 }
    225 
    226 std::vector<std::string> MetadataDatabaseIndex::GetRegisteredAppIDs() const {
    227   std::vector<std::string> result;
    228   result.reserve(app_root_by_app_id_.size());
    229   for (TrackerIDByAppID::const_iterator itr = app_root_by_app_id_.begin();
    230        itr != app_root_by_app_id_.end(); ++itr)
    231     result.push_back(itr->first);
    232   return result;
    233 }
    234 
    235 std::vector<int64> MetadataDatabaseIndex::GetAllTrackerIDs() const {
    236   std::vector<int64> result;
    237   for (TrackerByID::const_iterator itr = tracker_by_id_.begin();
    238        itr != tracker_by_id_.end(); ++itr) {
    239     result.push_back(itr->first);
    240   }
    241   return result;
    242 }
    243 
    244 std::vector<std::string> MetadataDatabaseIndex::GetAllMetadataIDs() const {
    245   std::vector<std::string> result;
    246   for (MetadataByID::const_iterator itr = metadata_by_id_.begin();
    247        itr != metadata_by_id_.end(); ++itr) {
    248     result.push_back(itr->first);
    249   }
    250   return result;
    251 }
    252 
    253 void MetadataDatabaseIndex::AddToAppIDIndex(
    254     const FileTracker& new_tracker) {
    255   if (!IsAppRoot(new_tracker))
    256     return;
    257 
    258   DVLOG(3) << "  Add to app_root_by_app_id_: " << new_tracker.app_id();
    259 
    260   DCHECK(new_tracker.active());
    261   DCHECK(!ContainsKey(app_root_by_app_id_, new_tracker.app_id()));
    262   app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id();
    263 }
    264 
    265 void MetadataDatabaseIndex::UpdateInAppIDIndex(
    266     const FileTracker& old_tracker,
    267     const FileTracker& new_tracker) {
    268   DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id());
    269 
    270   if (IsAppRoot(old_tracker) && !IsAppRoot(new_tracker)) {
    271     DCHECK(old_tracker.active());
    272     DCHECK(!new_tracker.active());
    273     DCHECK(ContainsKey(app_root_by_app_id_, old_tracker.app_id()));
    274 
    275     DVLOG(3) << "  Remove from app_root_by_app_id_: " << old_tracker.app_id();
    276 
    277     app_root_by_app_id_.erase(old_tracker.app_id());
    278   } else if (!IsAppRoot(old_tracker) && IsAppRoot(new_tracker)) {
    279     DCHECK(!old_tracker.active());
    280     DCHECK(new_tracker.active());
    281     DCHECK(!ContainsKey(app_root_by_app_id_, new_tracker.app_id()));
    282 
    283     DVLOG(3) << "  Add to app_root_by_app_id_: " << new_tracker.app_id();
    284 
    285     app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id();
    286   }
    287 }
    288 
    289 void MetadataDatabaseIndex::RemoveFromAppIDIndex(
    290     const FileTracker& tracker) {
    291   if (IsAppRoot(tracker)) {
    292     DCHECK(tracker.active());
    293     DCHECK(ContainsKey(app_root_by_app_id_, tracker.app_id()));
    294 
    295     DVLOG(3) << "  Remove from app_root_by_app_id_: " << tracker.app_id();
    296 
    297     app_root_by_app_id_.erase(tracker.app_id());
    298   }
    299 }
    300 
    301 void MetadataDatabaseIndex::AddToFileIDIndexes(
    302     const FileTracker& new_tracker) {
    303   DVLOG(3) << "  Add to trackers_by_file_id_: " << new_tracker.file_id();
    304 
    305   trackers_by_file_id_[new_tracker.file_id()].Insert(new_tracker);
    306 
    307   if (trackers_by_file_id_[new_tracker.file_id()].size() > 1) {
    308     DVLOG_IF(3, !ContainsKey(multi_tracker_file_ids_, new_tracker.file_id()))
    309         << "  Add to multi_tracker_file_ids_: " << new_tracker.file_id();
    310     multi_tracker_file_ids_.insert(new_tracker.file_id());
    311   }
    312 }
    313 
    314 void MetadataDatabaseIndex::UpdateInFileIDIndexes(
    315     const FileTracker& old_tracker,
    316     const FileTracker& new_tracker) {
    317   DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id());
    318   DCHECK_EQ(old_tracker.file_id(), new_tracker.file_id());
    319 
    320   std::string file_id = new_tracker.file_id();
    321   DCHECK(ContainsKey(trackers_by_file_id_, file_id));
    322 
    323   if (old_tracker.active() && !new_tracker.active())
    324     trackers_by_file_id_[file_id].Deactivate(new_tracker.tracker_id());
    325   else if (!old_tracker.active() && new_tracker.active())
    326     trackers_by_file_id_[file_id].Activate(new_tracker.tracker_id());
    327 }
    328 
    329 void MetadataDatabaseIndex::RemoveFromFileIDIndexes(
    330     const FileTracker& tracker) {
    331   TrackerIDsByFileID::iterator found =
    332       trackers_by_file_id_.find(tracker.file_id());
    333   if (found == trackers_by_file_id_.end()) {
    334     NOTREACHED();
    335     return;
    336   }
    337 
    338   DVLOG(3) << "  Remove from trackers_by_file_id_: "
    339            << tracker.tracker_id();
    340   found->second.Erase(tracker.tracker_id());
    341 
    342   if (trackers_by_file_id_[tracker.file_id()].size() <= 1) {
    343     DVLOG_IF(3, ContainsKey(multi_tracker_file_ids_, tracker.file_id()))
    344         << "  Remove from multi_tracker_file_ids_: " << tracker.file_id();
    345     multi_tracker_file_ids_.erase(tracker.file_id());
    346   }
    347 
    348   if (found->second.empty())
    349     trackers_by_file_id_.erase(found);
    350 }
    351 
    352 void MetadataDatabaseIndex::AddToPathIndexes(
    353     const FileTracker& new_tracker) {
    354   int64 parent = new_tracker.parent_tracker_id();
    355   std::string title = GetTrackerTitle(new_tracker);
    356 
    357   DVLOG(3) << "  Add to trackers_by_parent_and_title_: "
    358            << parent << " " << title;
    359 
    360   trackers_by_parent_and_title_[parent][title].Insert(new_tracker);
    361 
    362   if (trackers_by_parent_and_title_[parent][title].size() > 1 &&
    363       !title.empty()) {
    364     DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_,
    365                              ParentIDAndTitle(parent, title)))
    366         << "  Add to multi_backing_file_paths_: " << parent << " " << title;
    367     multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title));
    368   }
    369 }
    370 
    371 void MetadataDatabaseIndex::UpdateInPathIndexes(
    372     const FileTracker& old_tracker,
    373     const FileTracker& new_tracker) {
    374   DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id());
    375   DCHECK_EQ(old_tracker.parent_tracker_id(), new_tracker.parent_tracker_id());
    376   DCHECK(GetTrackerTitle(old_tracker) == GetTrackerTitle(new_tracker) ||
    377          !old_tracker.has_synced_details());
    378 
    379   int64 tracker_id = new_tracker.tracker_id();
    380   int64 parent = new_tracker.parent_tracker_id();
    381   std::string old_title = GetTrackerTitle(old_tracker);
    382   std::string title = GetTrackerTitle(new_tracker);
    383 
    384   TrackerIDsByTitle* trackers_by_title = &trackers_by_parent_and_title_[parent];
    385 
    386   if (old_title != title) {
    387     TrackerIDsByTitle::iterator found = trackers_by_title->find(old_title);
    388     if (found != trackers_by_title->end()) {
    389       DVLOG(3) << "  Remove from trackers_by_parent_and_title_: "
    390              << parent << " " << old_title;
    391 
    392       found->second.Erase(tracker_id);
    393       if (found->second.empty())
    394         trackers_by_title->erase(found);
    395     } else {
    396       NOTREACHED();
    397     }
    398 
    399     DVLOG(3) << "  Add to trackers_by_parent_and_title_: "
    400              << parent << " " << title;
    401 
    402     (*trackers_by_title)[title].Insert(new_tracker);
    403 
    404     if (trackers_by_parent_and_title_[parent][old_title].size() <= 1 &&
    405         !old_title.empty()) {
    406       DVLOG_IF(3, ContainsKey(multi_backing_file_paths_,
    407                               ParentIDAndTitle(parent, old_title)))
    408           << "  Remove from multi_backing_file_paths_: "
    409           << parent << " " << old_title;
    410       multi_backing_file_paths_.erase(ParentIDAndTitle(parent, old_title));
    411     }
    412 
    413     if (trackers_by_parent_and_title_[parent][title].size() > 1 &&
    414         !title.empty()) {
    415       DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_,
    416                                ParentIDAndTitle(parent, title)))
    417           << "  Add to multi_backing_file_paths_: " << parent << " " << title;
    418       multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title));
    419     }
    420 
    421     return;
    422   }
    423 
    424   if (old_tracker.active() && !new_tracker.active())
    425     trackers_by_parent_and_title_[parent][title].Deactivate(tracker_id);
    426   else if (!old_tracker.active() && new_tracker.active())
    427     trackers_by_parent_and_title_[parent][title].Activate(tracker_id);
    428 }
    429 
    430 void MetadataDatabaseIndex::RemoveFromPathIndexes(
    431     const FileTracker& tracker) {
    432   int64 tracker_id = tracker.tracker_id();
    433   int64 parent = tracker.parent_tracker_id();
    434   std::string title = GetTrackerTitle(tracker);
    435 
    436   DCHECK(ContainsKey(trackers_by_parent_and_title_, parent));
    437   DCHECK(ContainsKey(trackers_by_parent_and_title_[parent], title));
    438 
    439   DVLOG(3) << "  Remove from trackers_by_parent_and_title_: "
    440            << parent << " " << title;
    441 
    442   trackers_by_parent_and_title_[parent][title].Erase(tracker_id);
    443 
    444   if (trackers_by_parent_and_title_[parent][title].size() <= 1 &&
    445       !title.empty()) {
    446     DVLOG_IF(3, ContainsKey(multi_backing_file_paths_,
    447                             ParentIDAndTitle(parent, title)))
    448         << "  Remove from multi_backing_file_paths_: "
    449         << parent << " " << title;
    450     multi_backing_file_paths_.erase(ParentIDAndTitle(parent, title));
    451   }
    452 
    453   if (trackers_by_parent_and_title_[parent][title].empty()) {
    454     trackers_by_parent_and_title_[parent].erase(title);
    455     if (trackers_by_parent_and_title_[parent].empty())
    456       trackers_by_parent_and_title_.erase(parent);
    457   }
    458 }
    459 
    460 void MetadataDatabaseIndex::AddToDirtyTrackerIndexes(
    461     const FileTracker& new_tracker) {
    462   DCHECK(!ContainsKey(dirty_trackers_, new_tracker.tracker_id()));
    463   DCHECK(!ContainsKey(demoted_dirty_trackers_, new_tracker.tracker_id()));
    464 
    465   if (new_tracker.dirty()) {
    466     DVLOG(3) << "  Add to dirty_trackers_: " << new_tracker.tracker_id();
    467     dirty_trackers_.insert(new_tracker.tracker_id());
    468   }
    469 }
    470 
    471 void MetadataDatabaseIndex::UpdateInDirtyTrackerIndexes(
    472     const FileTracker& old_tracker,
    473     const FileTracker& new_tracker) {
    474   DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id());
    475 
    476   int64 tracker_id = new_tracker.tracker_id();
    477   if (old_tracker.dirty() && !new_tracker.dirty()) {
    478     DCHECK(ContainsKey(dirty_trackers_, tracker_id) ||
    479            ContainsKey(demoted_dirty_trackers_, tracker_id));
    480 
    481     DVLOG(3) << "  Remove from dirty_trackers_: " << tracker_id;
    482 
    483     dirty_trackers_.erase(tracker_id);
    484     demoted_dirty_trackers_.erase(tracker_id);
    485   } else if (!old_tracker.dirty() && new_tracker.dirty()) {
    486     DCHECK(!ContainsKey(dirty_trackers_, tracker_id));
    487     DCHECK(!ContainsKey(demoted_dirty_trackers_, tracker_id));
    488 
    489     DVLOG(3) << "  Add to dirty_trackers_: " << tracker_id;
    490 
    491     dirty_trackers_.insert(tracker_id);
    492   }
    493 }
    494 
    495 void MetadataDatabaseIndex::RemoveFromDirtyTrackerIndexes(
    496     const FileTracker& tracker) {
    497   if (tracker.dirty()) {
    498     int64 tracker_id = tracker.tracker_id();
    499     DCHECK(ContainsKey(dirty_trackers_, tracker_id) ||
    500            ContainsKey(demoted_dirty_trackers_, tracker_id));
    501 
    502     DVLOG(3) << "  Remove from dirty_trackers_: " << tracker_id;
    503     dirty_trackers_.erase(tracker_id);
    504 
    505     demoted_dirty_trackers_.erase(tracker_id);
    506   }
    507 }
    508 
    509 }  // namespace drive_backend
    510 }  // namespace sync_file_system
    511