metadata_database_index.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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 !title.empty()) { 333 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_, 334 ParentIDAndTitle(parent, title))) 335 << " Add to multi_backing_file_paths_: " << parent << " " << title; 336 multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title)); 337 } 338} 339 340void MetadataDatabaseIndex::UpdateInPathIndexes( 341 const FileTracker& old_tracker, 342 const FileTracker& new_tracker) { 343 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 344 DCHECK_EQ(old_tracker.parent_tracker_id(), new_tracker.parent_tracker_id()); 345 DCHECK(GetTrackerTitle(old_tracker) == GetTrackerTitle(new_tracker) || 346 !old_tracker.has_synced_details()); 347 348 int64 tracker_id = new_tracker.tracker_id(); 349 int64 parent = new_tracker.parent_tracker_id(); 350 std::string old_title = GetTrackerTitle(old_tracker); 351 std::string title = GetTrackerTitle(new_tracker); 352 353 TrackerIDsByTitle* trackers_by_title = &trackers_by_parent_and_title_[parent]; 354 355 if (old_title != title) { 356 TrackerIDsByTitle::iterator found = trackers_by_title->find(old_title); 357 if (found != trackers_by_title->end()) { 358 DVLOG(3) << " Remove from trackers_by_parent_and_title_: " 359 << parent << " " << old_title; 360 361 found->second.Erase(tracker_id); 362 if (found->second.empty()) 363 trackers_by_title->erase(found); 364 } else { 365 NOTREACHED(); 366 } 367 368 DVLOG(3) << " Add to trackers_by_parent_and_title_: " 369 << parent << " " << title; 370 371 (*trackers_by_title)[title].Insert(new_tracker); 372 373 if (trackers_by_parent_and_title_[parent][old_title].size() <= 1 && 374 !old_title.empty()) { 375 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_, 376 ParentIDAndTitle(parent, old_title))) 377 << " Remove from multi_backing_file_paths_: " 378 << parent << " " << old_title; 379 multi_backing_file_paths_.erase(ParentIDAndTitle(parent, old_title)); 380 } 381 382 if (trackers_by_parent_and_title_[parent][title].size() > 1 && 383 !title.empty()) { 384 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_, 385 ParentIDAndTitle(parent, title))) 386 << " Add to multi_backing_file_paths_: " << parent << " " << title; 387 multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title)); 388 } 389 390 return; 391 } 392 393 if (old_tracker.active() && !new_tracker.active()) 394 trackers_by_parent_and_title_[parent][title].Deactivate(tracker_id); 395 else if (!old_tracker.active() && new_tracker.active()) 396 trackers_by_parent_and_title_[parent][title].Activate(tracker_id); 397} 398 399void MetadataDatabaseIndex::RemoveFromPathIndexes( 400 const FileTracker& tracker) { 401 int64 tracker_id = tracker.tracker_id(); 402 int64 parent = tracker.parent_tracker_id(); 403 std::string title = GetTrackerTitle(tracker); 404 405 DCHECK(ContainsKey(trackers_by_parent_and_title_, parent)); 406 DCHECK(ContainsKey(trackers_by_parent_and_title_[parent], title)); 407 408 DVLOG(3) << " Remove from trackers_by_parent_and_title_: " 409 << parent << " " << title; 410 411 trackers_by_parent_and_title_[parent][title].Erase(tracker_id); 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 << " Remove from multi_backing_file_paths_: " 418 << parent << " " << title; 419 multi_backing_file_paths_.erase(ParentIDAndTitle(parent, title)); 420 } 421 422 if (trackers_by_parent_and_title_[parent][title].empty()) { 423 trackers_by_parent_and_title_[parent].erase(title); 424 if (trackers_by_parent_and_title_[parent].empty()) 425 trackers_by_parent_and_title_.erase(parent); 426 } 427} 428 429void MetadataDatabaseIndex::AddToDirtyTrackerIndexes( 430 const FileTracker& new_tracker) { 431 DCHECK(!ContainsKey(dirty_trackers_, new_tracker.tracker_id())); 432 DCHECK(!ContainsKey(demoted_dirty_trackers_, new_tracker.tracker_id())); 433 434 if (new_tracker.dirty()) { 435 DVLOG(3) << " Add to dirty_trackers_: " << new_tracker.tracker_id(); 436 dirty_trackers_.insert(new_tracker.tracker_id()); 437 } 438} 439 440void MetadataDatabaseIndex::UpdateInDirtyTrackerIndexes( 441 const FileTracker& old_tracker, 442 const FileTracker& new_tracker) { 443 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 444 445 int64 tracker_id = new_tracker.tracker_id(); 446 if (old_tracker.dirty() && !new_tracker.dirty()) { 447 DCHECK(ContainsKey(dirty_trackers_, tracker_id) || 448 ContainsKey(demoted_dirty_trackers_, tracker_id)); 449 450 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id; 451 452 dirty_trackers_.erase(tracker_id); 453 demoted_dirty_trackers_.erase(tracker_id); 454 } else if (!old_tracker.dirty() && new_tracker.dirty()) { 455 DCHECK(!ContainsKey(dirty_trackers_, tracker_id)); 456 DCHECK(!ContainsKey(demoted_dirty_trackers_, tracker_id)); 457 458 DVLOG(3) << " Add to dirty_trackers_: " << tracker_id; 459 460 dirty_trackers_.insert(tracker_id); 461 } 462} 463 464void MetadataDatabaseIndex::RemoveFromDirtyTrackerIndexes( 465 const FileTracker& tracker) { 466 if (tracker.dirty()) { 467 int64 tracker_id = tracker.tracker_id(); 468 DCHECK(ContainsKey(dirty_trackers_, tracker_id) || 469 ContainsKey(demoted_dirty_trackers_, tracker_id)); 470 471 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id; 472 dirty_trackers_.erase(tracker_id); 473 474 demoted_dirty_trackers_.erase(tracker_id); 475 } 476} 477 478} // namespace drive_backend 479} // namespace sync_file_system 480