metadata_database_index.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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 46namespace sync_file_system { 47namespace drive_backend { 48 49ParentIDAndTitle::ParentIDAndTitle() : parent_id(0) {} 50ParentIDAndTitle::ParentIDAndTitle(int64 parent_id, 51 const std::string& title) 52 : parent_id(parent_id), title(title) {} 53 54bool operator==(const ParentIDAndTitle& left, const ParentIDAndTitle& right) { 55 return left.parent_id == right.parent_id && left.title == right.title; 56} 57 58bool 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 64DatabaseContents::DatabaseContents() {} 65 66DatabaseContents::~DatabaseContents() {} 67 68namespace { 69 70template <typename Container> 71typename 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 80void 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 123void 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] = NULL; 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] = NULL; 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 202scoped_ptr<MetadataDatabaseIndex> 203MetadataDatabaseIndex::Create(LevelDBWrapper* db) { 204 DCHECK(db); 205 206 scoped_ptr<ServiceMetadata> service_metadata = InitializeServiceMetadata(db); 207 DatabaseContents contents; 208 209 PutVersionToDB(kCurrentDatabaseVersion, db); 210 ReadDatabaseContents(db, &contents); 211 RemoveUnreachableItems(&contents, 212 service_metadata->sync_root_tracker_id(), 213 db); 214 215 scoped_ptr<MetadataDatabaseIndex> index(new MetadataDatabaseIndex(db)); 216 index->Initialize(service_metadata.Pass(), &contents); 217 return index.Pass(); 218} 219 220// static 221scoped_ptr<MetadataDatabaseIndex> 222MetadataDatabaseIndex::CreateForTesting(DatabaseContents* contents, 223 LevelDBWrapper* db) { 224 scoped_ptr<MetadataDatabaseIndex> index(new MetadataDatabaseIndex(db)); 225 index->Initialize(make_scoped_ptr(new ServiceMetadata), contents); 226 return index.Pass(); 227} 228 229void MetadataDatabaseIndex::Initialize( 230 scoped_ptr<ServiceMetadata> service_metadata, 231 DatabaseContents* contents) { 232 service_metadata_ = service_metadata.Pass(); 233 234 for (size_t i = 0; i < contents->file_metadata.size(); ++i) 235 StoreFileMetadata(make_scoped_ptr(contents->file_metadata[i])); 236 contents->file_metadata.weak_clear(); 237 238 for (size_t i = 0; i < contents->file_trackers.size(); ++i) 239 StoreFileTracker(make_scoped_ptr(contents->file_trackers[i])); 240 contents->file_trackers.weak_clear(); 241 242 UMA_HISTOGRAM_COUNTS("SyncFileSystem.MetadataNumber", metadata_by_id_.size()); 243 UMA_HISTOGRAM_COUNTS("SyncFileSystem.TrackerNumber", tracker_by_id_.size()); 244 UMA_HISTOGRAM_COUNTS_100("SyncFileSystem.RegisteredAppNumber", 245 app_root_by_app_id_.size()); 246} 247 248MetadataDatabaseIndex::MetadataDatabaseIndex(LevelDBWrapper* db) : db_(db) {} 249MetadataDatabaseIndex::~MetadataDatabaseIndex() {} 250 251bool MetadataDatabaseIndex::GetFileMetadata( 252 const std::string& file_id, FileMetadata* metadata) const { 253 FileMetadata* identified = metadata_by_id_.get(file_id); 254 if (!identified) 255 return false; 256 if (metadata) 257 metadata->CopyFrom(*identified); 258 return true; 259} 260 261bool MetadataDatabaseIndex::GetFileTracker( 262 int64 tracker_id, FileTracker* tracker) const { 263 FileTracker* identified = tracker_by_id_.get(tracker_id); 264 if (!identified) 265 return false; 266 if (tracker) 267 tracker->CopyFrom(*identified); 268 return true; 269} 270 271void MetadataDatabaseIndex::StoreFileMetadata( 272 scoped_ptr<FileMetadata> metadata) { 273 PutFileMetadataToDB(*metadata.get(), db_); 274 if (!metadata) { 275 NOTREACHED(); 276 return; 277 } 278 279 std::string file_id = metadata->file_id(); 280 metadata_by_id_.set(file_id, metadata.Pass()); 281} 282 283void MetadataDatabaseIndex::StoreFileTracker( 284 scoped_ptr<FileTracker> tracker) { 285 PutFileTrackerToDB(*tracker.get(), db_); 286 if (!tracker) { 287 NOTREACHED(); 288 return; 289 } 290 291 int64 tracker_id = tracker->tracker_id(); 292 FileTracker* old_tracker = tracker_by_id_.get(tracker_id); 293 294 if (!old_tracker) { 295 DVLOG(3) << "Adding new tracker: " << tracker->tracker_id() 296 << " " << GetTrackerTitle(*tracker); 297 298 AddToAppIDIndex(*tracker); 299 AddToPathIndexes(*tracker); 300 AddToFileIDIndexes(*tracker); 301 AddToDirtyTrackerIndexes(*tracker); 302 } else { 303 DVLOG(3) << "Updating tracker: " << tracker->tracker_id() 304 << " " << GetTrackerTitle(*tracker); 305 306 UpdateInAppIDIndex(*old_tracker, *tracker); 307 UpdateInPathIndexes(*old_tracker, *tracker); 308 UpdateInFileIDIndexes(*old_tracker, *tracker); 309 UpdateInDirtyTrackerIndexes(*old_tracker, *tracker); 310 } 311 312 tracker_by_id_.set(tracker_id, tracker.Pass()); 313} 314 315void MetadataDatabaseIndex::RemoveFileMetadata(const std::string& file_id) { 316 PutFileMetadataDeletionToDB(file_id, db_); 317 metadata_by_id_.erase(file_id); 318} 319 320void MetadataDatabaseIndex::RemoveFileTracker(int64 tracker_id) { 321 PutFileTrackerDeletionToDB(tracker_id, db_); 322 323 FileTracker* tracker = tracker_by_id_.get(tracker_id); 324 if (!tracker) { 325 NOTREACHED(); 326 return; 327 } 328 329 DVLOG(3) << "Removing tracker: " 330 << tracker->tracker_id() << " " << GetTrackerTitle(*tracker); 331 332 RemoveFromAppIDIndex(*tracker); 333 RemoveFromPathIndexes(*tracker); 334 RemoveFromFileIDIndexes(*tracker); 335 RemoveFromDirtyTrackerIndexes(*tracker); 336 337 tracker_by_id_.erase(tracker_id); 338} 339 340TrackerIDSet MetadataDatabaseIndex::GetFileTrackerIDsByFileID( 341 const std::string& file_id) const { 342 return FindItem(trackers_by_file_id_, file_id); 343} 344 345int64 MetadataDatabaseIndex::GetAppRootTracker( 346 const std::string& app_id) const { 347 return FindItem(app_root_by_app_id_, app_id); 348} 349 350TrackerIDSet MetadataDatabaseIndex::GetFileTrackerIDsByParentAndTitle( 351 int64 parent_tracker_id, 352 const std::string& title) const { 353 TrackerIDsByParentAndTitle::const_iterator found = 354 trackers_by_parent_and_title_.find(parent_tracker_id); 355 if (found == trackers_by_parent_and_title_.end()) 356 return TrackerIDSet(); 357 return FindItem(found->second, title); 358} 359 360std::vector<int64> MetadataDatabaseIndex::GetFileTrackerIDsByParent( 361 int64 parent_tracker_id) const { 362 std::vector<int64> result; 363 TrackerIDsByParentAndTitle::const_iterator found = 364 trackers_by_parent_and_title_.find(parent_tracker_id); 365 if (found == trackers_by_parent_and_title_.end()) 366 return result; 367 368 for (TrackerIDsByTitle::const_iterator itr = found->second.begin(); 369 itr != found->second.end(); ++itr) { 370 result.insert(result.end(), itr->second.begin(), itr->second.end()); 371 } 372 373 return result; 374} 375 376std::string MetadataDatabaseIndex::PickMultiTrackerFileID() const { 377 if (multi_tracker_file_ids_.empty()) 378 return std::string(); 379 return *multi_tracker_file_ids_.begin(); 380} 381 382ParentIDAndTitle MetadataDatabaseIndex::PickMultiBackingFilePath() const { 383 if (multi_backing_file_paths_.empty()) 384 return ParentIDAndTitle(kInvalidTrackerID, std::string()); 385 return *multi_backing_file_paths_.begin(); 386} 387 388int64 MetadataDatabaseIndex::PickDirtyTracker() const { 389 if (dirty_trackers_.empty()) 390 return kInvalidTrackerID; 391 return *dirty_trackers_.begin(); 392} 393 394void MetadataDatabaseIndex::DemoteDirtyTracker(int64 tracker_id) { 395 if (dirty_trackers_.erase(tracker_id)) 396 demoted_dirty_trackers_.insert(tracker_id); 397} 398 399bool MetadataDatabaseIndex::HasDemotedDirtyTracker() const { 400 return !demoted_dirty_trackers_.empty(); 401} 402 403void MetadataDatabaseIndex::PromoteDemotedDirtyTracker(int64 tracker_id) { 404 if (demoted_dirty_trackers_.erase(tracker_id) == 1) 405 dirty_trackers_.insert(tracker_id); 406} 407 408bool MetadataDatabaseIndex::PromoteDemotedDirtyTrackers() { 409 bool promoted = !demoted_dirty_trackers_.empty(); 410 dirty_trackers_.insert(demoted_dirty_trackers_.begin(), 411 demoted_dirty_trackers_.end()); 412 demoted_dirty_trackers_.clear(); 413 return promoted; 414} 415 416size_t MetadataDatabaseIndex::CountDirtyTracker() const { 417 return dirty_trackers_.size() + demoted_dirty_trackers_.size(); 418} 419 420size_t MetadataDatabaseIndex::CountFileMetadata() const { 421 return metadata_by_id_.size(); 422} 423 424size_t MetadataDatabaseIndex::CountFileTracker() const { 425 return tracker_by_id_.size(); 426} 427 428void MetadataDatabaseIndex::SetSyncRootTrackerID( 429 int64 sync_root_id) const { 430 service_metadata_->set_sync_root_tracker_id(sync_root_id); 431 PutServiceMetadataToDB(*service_metadata_, db_); 432} 433 434void MetadataDatabaseIndex::SetLargestChangeID( 435 int64 largest_change_id) const { 436 service_metadata_->set_largest_change_id(largest_change_id); 437 PutServiceMetadataToDB(*service_metadata_, db_); 438} 439 440void MetadataDatabaseIndex::SetNextTrackerID( 441 int64 next_tracker_id) const { 442 service_metadata_->set_next_tracker_id(next_tracker_id); 443 PutServiceMetadataToDB(*service_metadata_, db_); 444} 445 446int64 MetadataDatabaseIndex::GetSyncRootTrackerID() const { 447 if (!service_metadata_->has_sync_root_tracker_id()) 448 return kInvalidTrackerID; 449 return service_metadata_->sync_root_tracker_id(); 450} 451 452int64 MetadataDatabaseIndex::GetLargestChangeID() const { 453 if (!service_metadata_->has_largest_change_id()) 454 return kInvalidTrackerID; 455 return service_metadata_->largest_change_id(); 456} 457 458int64 MetadataDatabaseIndex::GetNextTrackerID() const { 459 if (!service_metadata_->has_next_tracker_id()) { 460 NOTREACHED(); 461 return kInvalidTrackerID; 462 } 463 return service_metadata_->next_tracker_id(); 464} 465 466std::vector<std::string> MetadataDatabaseIndex::GetRegisteredAppIDs() const { 467 std::vector<std::string> result; 468 result.reserve(app_root_by_app_id_.size()); 469 for (TrackerIDByAppID::const_iterator itr = app_root_by_app_id_.begin(); 470 itr != app_root_by_app_id_.end(); ++itr) 471 result.push_back(itr->first); 472 return result; 473} 474 475std::vector<int64> MetadataDatabaseIndex::GetAllTrackerIDs() const { 476 std::vector<int64> result; 477 for (TrackerByID::const_iterator itr = tracker_by_id_.begin(); 478 itr != tracker_by_id_.end(); ++itr) { 479 result.push_back(itr->first); 480 } 481 return result; 482} 483 484std::vector<std::string> MetadataDatabaseIndex::GetAllMetadataIDs() const { 485 std::vector<std::string> result; 486 for (MetadataByID::const_iterator itr = metadata_by_id_.begin(); 487 itr != metadata_by_id_.end(); ++itr) { 488 result.push_back(itr->first); 489 } 490 return result; 491} 492 493void MetadataDatabaseIndex::AddToAppIDIndex( 494 const FileTracker& new_tracker) { 495 if (!IsAppRoot(new_tracker)) 496 return; 497 498 DVLOG(3) << " Add to app_root_by_app_id_: " << new_tracker.app_id(); 499 500 DCHECK(new_tracker.active()); 501 DCHECK(!ContainsKey(app_root_by_app_id_, new_tracker.app_id())); 502 app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id(); 503} 504 505void MetadataDatabaseIndex::UpdateInAppIDIndex( 506 const FileTracker& old_tracker, 507 const FileTracker& new_tracker) { 508 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 509 510 if (IsAppRoot(old_tracker) && !IsAppRoot(new_tracker)) { 511 DCHECK(old_tracker.active()); 512 DCHECK(!new_tracker.active()); 513 DCHECK(ContainsKey(app_root_by_app_id_, old_tracker.app_id())); 514 515 DVLOG(3) << " Remove from app_root_by_app_id_: " << old_tracker.app_id(); 516 517 app_root_by_app_id_.erase(old_tracker.app_id()); 518 } else if (!IsAppRoot(old_tracker) && IsAppRoot(new_tracker)) { 519 DCHECK(!old_tracker.active()); 520 DCHECK(new_tracker.active()); 521 DCHECK(!ContainsKey(app_root_by_app_id_, new_tracker.app_id())); 522 523 DVLOG(3) << " Add to app_root_by_app_id_: " << new_tracker.app_id(); 524 525 app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id(); 526 } 527} 528 529void MetadataDatabaseIndex::RemoveFromAppIDIndex( 530 const FileTracker& tracker) { 531 if (IsAppRoot(tracker)) { 532 DCHECK(tracker.active()); 533 DCHECK(ContainsKey(app_root_by_app_id_, tracker.app_id())); 534 535 DVLOG(3) << " Remove from app_root_by_app_id_: " << tracker.app_id(); 536 537 app_root_by_app_id_.erase(tracker.app_id()); 538 } 539} 540 541void MetadataDatabaseIndex::AddToFileIDIndexes( 542 const FileTracker& new_tracker) { 543 DVLOG(3) << " Add to trackers_by_file_id_: " << new_tracker.file_id(); 544 545 trackers_by_file_id_[new_tracker.file_id()].Insert(new_tracker); 546 547 if (trackers_by_file_id_[new_tracker.file_id()].size() > 1) { 548 DVLOG_IF(3, !ContainsKey(multi_tracker_file_ids_, new_tracker.file_id())) 549 << " Add to multi_tracker_file_ids_: " << new_tracker.file_id(); 550 multi_tracker_file_ids_.insert(new_tracker.file_id()); 551 } 552} 553 554void MetadataDatabaseIndex::UpdateInFileIDIndexes( 555 const FileTracker& old_tracker, 556 const FileTracker& new_tracker) { 557 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 558 DCHECK_EQ(old_tracker.file_id(), new_tracker.file_id()); 559 560 std::string file_id = new_tracker.file_id(); 561 DCHECK(ContainsKey(trackers_by_file_id_, file_id)); 562 563 if (old_tracker.active() && !new_tracker.active()) 564 trackers_by_file_id_[file_id].Deactivate(new_tracker.tracker_id()); 565 else if (!old_tracker.active() && new_tracker.active()) 566 trackers_by_file_id_[file_id].Activate(new_tracker.tracker_id()); 567} 568 569void MetadataDatabaseIndex::RemoveFromFileIDIndexes( 570 const FileTracker& tracker) { 571 TrackerIDsByFileID::iterator found = 572 trackers_by_file_id_.find(tracker.file_id()); 573 if (found == trackers_by_file_id_.end()) { 574 NOTREACHED(); 575 return; 576 } 577 578 DVLOG(3) << " Remove from trackers_by_file_id_: " 579 << tracker.tracker_id(); 580 found->second.Erase(tracker.tracker_id()); 581 582 if (trackers_by_file_id_[tracker.file_id()].size() <= 1) { 583 DVLOG_IF(3, ContainsKey(multi_tracker_file_ids_, tracker.file_id())) 584 << " Remove from multi_tracker_file_ids_: " << tracker.file_id(); 585 multi_tracker_file_ids_.erase(tracker.file_id()); 586 } 587 588 if (found->second.empty()) 589 trackers_by_file_id_.erase(found); 590} 591 592void MetadataDatabaseIndex::AddToPathIndexes( 593 const FileTracker& new_tracker) { 594 int64 parent = new_tracker.parent_tracker_id(); 595 std::string title = GetTrackerTitle(new_tracker); 596 597 DVLOG(3) << " Add to trackers_by_parent_and_title_: " 598 << parent << " " << title; 599 600 trackers_by_parent_and_title_[parent][title].Insert(new_tracker); 601 602 if (trackers_by_parent_and_title_[parent][title].size() > 1 && 603 !title.empty()) { 604 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_, 605 ParentIDAndTitle(parent, title))) 606 << " Add to multi_backing_file_paths_: " << parent << " " << title; 607 multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title)); 608 } 609} 610 611void MetadataDatabaseIndex::UpdateInPathIndexes( 612 const FileTracker& old_tracker, 613 const FileTracker& new_tracker) { 614 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 615 DCHECK_EQ(old_tracker.parent_tracker_id(), new_tracker.parent_tracker_id()); 616 DCHECK(GetTrackerTitle(old_tracker) == GetTrackerTitle(new_tracker) || 617 !old_tracker.has_synced_details()); 618 619 int64 tracker_id = new_tracker.tracker_id(); 620 int64 parent = new_tracker.parent_tracker_id(); 621 std::string old_title = GetTrackerTitle(old_tracker); 622 std::string title = GetTrackerTitle(new_tracker); 623 624 TrackerIDsByTitle* trackers_by_title = &trackers_by_parent_and_title_[parent]; 625 626 if (old_title != title) { 627 TrackerIDsByTitle::iterator found = trackers_by_title->find(old_title); 628 if (found != trackers_by_title->end()) { 629 DVLOG(3) << " Remove from trackers_by_parent_and_title_: " 630 << parent << " " << old_title; 631 632 found->second.Erase(tracker_id); 633 if (found->second.empty()) 634 trackers_by_title->erase(found); 635 } else { 636 NOTREACHED(); 637 } 638 639 DVLOG(3) << " Add to trackers_by_parent_and_title_: " 640 << parent << " " << title; 641 642 (*trackers_by_title)[title].Insert(new_tracker); 643 644 if (trackers_by_parent_and_title_[parent][old_title].size() <= 1 && 645 !old_title.empty()) { 646 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_, 647 ParentIDAndTitle(parent, old_title))) 648 << " Remove from multi_backing_file_paths_: " 649 << parent << " " << old_title; 650 multi_backing_file_paths_.erase(ParentIDAndTitle(parent, old_title)); 651 } 652 653 if (trackers_by_parent_and_title_[parent][title].size() > 1 && 654 !title.empty()) { 655 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_, 656 ParentIDAndTitle(parent, title))) 657 << " Add to multi_backing_file_paths_: " << parent << " " << title; 658 multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title)); 659 } 660 661 return; 662 } 663 664 if (old_tracker.active() && !new_tracker.active()) 665 trackers_by_parent_and_title_[parent][title].Deactivate(tracker_id); 666 else if (!old_tracker.active() && new_tracker.active()) 667 trackers_by_parent_and_title_[parent][title].Activate(tracker_id); 668} 669 670void MetadataDatabaseIndex::RemoveFromPathIndexes( 671 const FileTracker& tracker) { 672 int64 tracker_id = tracker.tracker_id(); 673 int64 parent = tracker.parent_tracker_id(); 674 std::string title = GetTrackerTitle(tracker); 675 676 DCHECK(ContainsKey(trackers_by_parent_and_title_, parent)); 677 DCHECK(ContainsKey(trackers_by_parent_and_title_[parent], title)); 678 679 DVLOG(3) << " Remove from trackers_by_parent_and_title_: " 680 << parent << " " << title; 681 682 trackers_by_parent_and_title_[parent][title].Erase(tracker_id); 683 684 if (trackers_by_parent_and_title_[parent][title].size() <= 1 && 685 !title.empty()) { 686 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_, 687 ParentIDAndTitle(parent, title))) 688 << " Remove from multi_backing_file_paths_: " 689 << parent << " " << title; 690 multi_backing_file_paths_.erase(ParentIDAndTitle(parent, title)); 691 } 692 693 if (trackers_by_parent_and_title_[parent][title].empty()) { 694 trackers_by_parent_and_title_[parent].erase(title); 695 if (trackers_by_parent_and_title_[parent].empty()) 696 trackers_by_parent_and_title_.erase(parent); 697 } 698} 699 700void MetadataDatabaseIndex::AddToDirtyTrackerIndexes( 701 const FileTracker& new_tracker) { 702 DCHECK(!ContainsKey(dirty_trackers_, new_tracker.tracker_id())); 703 DCHECK(!ContainsKey(demoted_dirty_trackers_, new_tracker.tracker_id())); 704 705 if (new_tracker.dirty()) { 706 DVLOG(3) << " Add to dirty_trackers_: " << new_tracker.tracker_id(); 707 dirty_trackers_.insert(new_tracker.tracker_id()); 708 } 709} 710 711void MetadataDatabaseIndex::UpdateInDirtyTrackerIndexes( 712 const FileTracker& old_tracker, 713 const FileTracker& new_tracker) { 714 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 715 716 int64 tracker_id = new_tracker.tracker_id(); 717 if (old_tracker.dirty() && !new_tracker.dirty()) { 718 DCHECK(ContainsKey(dirty_trackers_, tracker_id) || 719 ContainsKey(demoted_dirty_trackers_, tracker_id)); 720 721 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id; 722 723 dirty_trackers_.erase(tracker_id); 724 demoted_dirty_trackers_.erase(tracker_id); 725 } else if (!old_tracker.dirty() && new_tracker.dirty()) { 726 DCHECK(!ContainsKey(dirty_trackers_, tracker_id)); 727 DCHECK(!ContainsKey(demoted_dirty_trackers_, tracker_id)); 728 729 DVLOG(3) << " Add to dirty_trackers_: " << tracker_id; 730 731 dirty_trackers_.insert(tracker_id); 732 } 733} 734 735void MetadataDatabaseIndex::RemoveFromDirtyTrackerIndexes( 736 const FileTracker& tracker) { 737 if (tracker.dirty()) { 738 int64 tracker_id = tracker.tracker_id(); 739 DCHECK(ContainsKey(dirty_trackers_, tracker_id) || 740 ContainsKey(demoted_dirty_trackers_, tracker_id)); 741 742 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id; 743 dirty_trackers_.erase(tracker_id); 744 745 demoted_dirty_trackers_.erase(tracker_id); 746 } 747} 748 749} // namespace drive_backend 750} // namespace sync_file_system 751