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