metadata_database_index.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 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 223scoped_ptr<MetadataDatabaseIndex> 224MetadataDatabaseIndex::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 231void 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 250MetadataDatabaseIndex::MetadataDatabaseIndex(LevelDBWrapper* db) : db_(db) {} 251MetadataDatabaseIndex::~MetadataDatabaseIndex() {} 252 253bool 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 263bool 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 273void 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 285void 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 317void MetadataDatabaseIndex::RemoveFileMetadata(const std::string& file_id) { 318 PutFileMetadataDeletionToDB(file_id, db_); 319 metadata_by_id_.erase(file_id); 320} 321 322void 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 342TrackerIDSet MetadataDatabaseIndex::GetFileTrackerIDsByFileID( 343 const std::string& file_id) const { 344 return FindItem(trackers_by_file_id_, file_id); 345} 346 347int64 MetadataDatabaseIndex::GetAppRootTracker( 348 const std::string& app_id) const { 349 return FindItem(app_root_by_app_id_, app_id); 350} 351 352TrackerIDSet 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 362std::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 378std::string MetadataDatabaseIndex::PickMultiTrackerFileID() const { 379 if (multi_tracker_file_ids_.empty()) 380 return std::string(); 381 return *multi_tracker_file_ids_.begin(); 382} 383 384ParentIDAndTitle 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 390int64 MetadataDatabaseIndex::PickDirtyTracker() const { 391 if (dirty_trackers_.empty()) 392 return kInvalidTrackerID; 393 return *dirty_trackers_.begin(); 394} 395 396void MetadataDatabaseIndex::DemoteDirtyTracker(int64 tracker_id) { 397 if (dirty_trackers_.erase(tracker_id)) 398 demoted_dirty_trackers_.insert(tracker_id); 399} 400 401bool MetadataDatabaseIndex::HasDemotedDirtyTracker() const { 402 return !demoted_dirty_trackers_.empty(); 403} 404 405void MetadataDatabaseIndex::PromoteDemotedDirtyTracker(int64 tracker_id) { 406 if (demoted_dirty_trackers_.erase(tracker_id) == 1) 407 dirty_trackers_.insert(tracker_id); 408} 409 410bool MetadataDatabaseIndex::PromoteDemotedDirtyTrackers() { 411 bool promoted = !demoted_dirty_trackers_.empty(); 412 dirty_trackers_.insert(demoted_dirty_trackers_.begin(), 413 demoted_dirty_trackers_.end()); 414 demoted_dirty_trackers_.clear(); 415 return promoted; 416} 417 418size_t MetadataDatabaseIndex::CountDirtyTracker() const { 419 return dirty_trackers_.size(); 420} 421 422size_t MetadataDatabaseIndex::CountFileMetadata() const { 423 return metadata_by_id_.size(); 424} 425 426size_t MetadataDatabaseIndex::CountFileTracker() const { 427 return tracker_by_id_.size(); 428} 429 430void MetadataDatabaseIndex::SetSyncRootTrackerID( 431 int64 sync_root_id) const { 432 service_metadata_->set_sync_root_tracker_id(sync_root_id); 433 PutServiceMetadataToDB(*service_metadata_, db_); 434} 435 436void MetadataDatabaseIndex::SetLargestChangeID( 437 int64 largest_change_id) const { 438 service_metadata_->set_largest_change_id(largest_change_id); 439 PutServiceMetadataToDB(*service_metadata_, db_); 440} 441 442void MetadataDatabaseIndex::SetNextTrackerID( 443 int64 next_tracker_id) const { 444 service_metadata_->set_next_tracker_id(next_tracker_id); 445 PutServiceMetadataToDB(*service_metadata_, db_); 446} 447 448int64 MetadataDatabaseIndex::GetSyncRootTrackerID() const { 449 if (!service_metadata_->has_sync_root_tracker_id()) 450 return kInvalidTrackerID; 451 return service_metadata_->sync_root_tracker_id(); 452} 453 454int64 MetadataDatabaseIndex::GetLargestChangeID() const { 455 if (!service_metadata_->has_largest_change_id()) 456 return kInvalidTrackerID; 457 return service_metadata_->largest_change_id(); 458} 459 460int64 MetadataDatabaseIndex::GetNextTrackerID() const { 461 if (!service_metadata_->has_next_tracker_id()) { 462 NOTREACHED(); 463 return kInvalidTrackerID; 464 } 465 return service_metadata_->next_tracker_id(); 466} 467 468std::vector<std::string> MetadataDatabaseIndex::GetRegisteredAppIDs() const { 469 std::vector<std::string> result; 470 result.reserve(app_root_by_app_id_.size()); 471 for (TrackerIDByAppID::const_iterator itr = app_root_by_app_id_.begin(); 472 itr != app_root_by_app_id_.end(); ++itr) 473 result.push_back(itr->first); 474 return result; 475} 476 477std::vector<int64> MetadataDatabaseIndex::GetAllTrackerIDs() const { 478 std::vector<int64> result; 479 for (TrackerByID::const_iterator itr = tracker_by_id_.begin(); 480 itr != tracker_by_id_.end(); ++itr) { 481 result.push_back(itr->first); 482 } 483 return result; 484} 485 486std::vector<std::string> MetadataDatabaseIndex::GetAllMetadataIDs() const { 487 std::vector<std::string> result; 488 for (MetadataByID::const_iterator itr = metadata_by_id_.begin(); 489 itr != metadata_by_id_.end(); ++itr) { 490 result.push_back(itr->first); 491 } 492 return result; 493} 494 495void MetadataDatabaseIndex::AddToAppIDIndex( 496 const FileTracker& new_tracker) { 497 if (!IsAppRoot(new_tracker)) 498 return; 499 500 DVLOG(3) << " Add to app_root_by_app_id_: " << new_tracker.app_id(); 501 502 DCHECK(new_tracker.active()); 503 DCHECK(!ContainsKey(app_root_by_app_id_, new_tracker.app_id())); 504 app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id(); 505} 506 507void MetadataDatabaseIndex::UpdateInAppIDIndex( 508 const FileTracker& old_tracker, 509 const FileTracker& new_tracker) { 510 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 511 512 if (IsAppRoot(old_tracker) && !IsAppRoot(new_tracker)) { 513 DCHECK(old_tracker.active()); 514 DCHECK(!new_tracker.active()); 515 DCHECK(ContainsKey(app_root_by_app_id_, old_tracker.app_id())); 516 517 DVLOG(3) << " Remove from app_root_by_app_id_: " << old_tracker.app_id(); 518 519 app_root_by_app_id_.erase(old_tracker.app_id()); 520 } else if (!IsAppRoot(old_tracker) && IsAppRoot(new_tracker)) { 521 DCHECK(!old_tracker.active()); 522 DCHECK(new_tracker.active()); 523 DCHECK(!ContainsKey(app_root_by_app_id_, new_tracker.app_id())); 524 525 DVLOG(3) << " Add to app_root_by_app_id_: " << new_tracker.app_id(); 526 527 app_root_by_app_id_[new_tracker.app_id()] = new_tracker.tracker_id(); 528 } 529} 530 531void MetadataDatabaseIndex::RemoveFromAppIDIndex( 532 const FileTracker& tracker) { 533 if (IsAppRoot(tracker)) { 534 DCHECK(tracker.active()); 535 DCHECK(ContainsKey(app_root_by_app_id_, tracker.app_id())); 536 537 DVLOG(3) << " Remove from app_root_by_app_id_: " << tracker.app_id(); 538 539 app_root_by_app_id_.erase(tracker.app_id()); 540 } 541} 542 543void MetadataDatabaseIndex::AddToFileIDIndexes( 544 const FileTracker& new_tracker) { 545 DVLOG(3) << " Add to trackers_by_file_id_: " << new_tracker.file_id(); 546 547 trackers_by_file_id_[new_tracker.file_id()].Insert(new_tracker); 548 549 if (trackers_by_file_id_[new_tracker.file_id()].size() > 1) { 550 DVLOG_IF(3, !ContainsKey(multi_tracker_file_ids_, new_tracker.file_id())) 551 << " Add to multi_tracker_file_ids_: " << new_tracker.file_id(); 552 multi_tracker_file_ids_.insert(new_tracker.file_id()); 553 } 554} 555 556void MetadataDatabaseIndex::UpdateInFileIDIndexes( 557 const FileTracker& old_tracker, 558 const FileTracker& new_tracker) { 559 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 560 DCHECK_EQ(old_tracker.file_id(), new_tracker.file_id()); 561 562 std::string file_id = new_tracker.file_id(); 563 DCHECK(ContainsKey(trackers_by_file_id_, file_id)); 564 565 if (old_tracker.active() && !new_tracker.active()) 566 trackers_by_file_id_[file_id].Deactivate(new_tracker.tracker_id()); 567 else if (!old_tracker.active() && new_tracker.active()) 568 trackers_by_file_id_[file_id].Activate(new_tracker.tracker_id()); 569} 570 571void MetadataDatabaseIndex::RemoveFromFileIDIndexes( 572 const FileTracker& tracker) { 573 TrackerIDsByFileID::iterator found = 574 trackers_by_file_id_.find(tracker.file_id()); 575 if (found == trackers_by_file_id_.end()) { 576 NOTREACHED(); 577 return; 578 } 579 580 DVLOG(3) << " Remove from trackers_by_file_id_: " 581 << tracker.tracker_id(); 582 found->second.Erase(tracker.tracker_id()); 583 584 if (trackers_by_file_id_[tracker.file_id()].size() <= 1) { 585 DVLOG_IF(3, ContainsKey(multi_tracker_file_ids_, tracker.file_id())) 586 << " Remove from multi_tracker_file_ids_: " << tracker.file_id(); 587 multi_tracker_file_ids_.erase(tracker.file_id()); 588 } 589 590 if (found->second.empty()) 591 trackers_by_file_id_.erase(found); 592} 593 594void MetadataDatabaseIndex::AddToPathIndexes( 595 const FileTracker& new_tracker) { 596 int64 parent = new_tracker.parent_tracker_id(); 597 std::string title = GetTrackerTitle(new_tracker); 598 599 DVLOG(3) << " Add to trackers_by_parent_and_title_: " 600 << parent << " " << title; 601 602 trackers_by_parent_and_title_[parent][title].Insert(new_tracker); 603 604 if (trackers_by_parent_and_title_[parent][title].size() > 1 && 605 !title.empty()) { 606 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_, 607 ParentIDAndTitle(parent, title))) 608 << " Add to multi_backing_file_paths_: " << parent << " " << title; 609 multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title)); 610 } 611} 612 613void MetadataDatabaseIndex::UpdateInPathIndexes( 614 const FileTracker& old_tracker, 615 const FileTracker& new_tracker) { 616 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 617 DCHECK_EQ(old_tracker.parent_tracker_id(), new_tracker.parent_tracker_id()); 618 DCHECK(GetTrackerTitle(old_tracker) == GetTrackerTitle(new_tracker) || 619 !old_tracker.has_synced_details()); 620 621 int64 tracker_id = new_tracker.tracker_id(); 622 int64 parent = new_tracker.parent_tracker_id(); 623 std::string old_title = GetTrackerTitle(old_tracker); 624 std::string title = GetTrackerTitle(new_tracker); 625 626 TrackerIDsByTitle* trackers_by_title = &trackers_by_parent_and_title_[parent]; 627 628 if (old_title != title) { 629 TrackerIDsByTitle::iterator found = trackers_by_title->find(old_title); 630 if (found != trackers_by_title->end()) { 631 DVLOG(3) << " Remove from trackers_by_parent_and_title_: " 632 << parent << " " << old_title; 633 634 found->second.Erase(tracker_id); 635 if (found->second.empty()) 636 trackers_by_title->erase(found); 637 } else { 638 NOTREACHED(); 639 } 640 641 DVLOG(3) << " Add to trackers_by_parent_and_title_: " 642 << parent << " " << title; 643 644 (*trackers_by_title)[title].Insert(new_tracker); 645 646 if (trackers_by_parent_and_title_[parent][old_title].size() <= 1 && 647 !old_title.empty()) { 648 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_, 649 ParentIDAndTitle(parent, old_title))) 650 << " Remove from multi_backing_file_paths_: " 651 << parent << " " << old_title; 652 multi_backing_file_paths_.erase(ParentIDAndTitle(parent, old_title)); 653 } 654 655 if (trackers_by_parent_and_title_[parent][title].size() > 1 && 656 !title.empty()) { 657 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_, 658 ParentIDAndTitle(parent, title))) 659 << " Add to multi_backing_file_paths_: " << parent << " " << title; 660 multi_backing_file_paths_.insert(ParentIDAndTitle(parent, title)); 661 } 662 663 return; 664 } 665 666 if (old_tracker.active() && !new_tracker.active()) 667 trackers_by_parent_and_title_[parent][title].Deactivate(tracker_id); 668 else if (!old_tracker.active() && new_tracker.active()) 669 trackers_by_parent_and_title_[parent][title].Activate(tracker_id); 670} 671 672void MetadataDatabaseIndex::RemoveFromPathIndexes( 673 const FileTracker& tracker) { 674 int64 tracker_id = tracker.tracker_id(); 675 int64 parent = tracker.parent_tracker_id(); 676 std::string title = GetTrackerTitle(tracker); 677 678 DCHECK(ContainsKey(trackers_by_parent_and_title_, parent)); 679 DCHECK(ContainsKey(trackers_by_parent_and_title_[parent], title)); 680 681 DVLOG(3) << " Remove from trackers_by_parent_and_title_: " 682 << parent << " " << title; 683 684 trackers_by_parent_and_title_[parent][title].Erase(tracker_id); 685 686 if (trackers_by_parent_and_title_[parent][title].size() <= 1 && 687 !title.empty()) { 688 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_, 689 ParentIDAndTitle(parent, title))) 690 << " Remove from multi_backing_file_paths_: " 691 << parent << " " << title; 692 multi_backing_file_paths_.erase(ParentIDAndTitle(parent, title)); 693 } 694 695 if (trackers_by_parent_and_title_[parent][title].empty()) { 696 trackers_by_parent_and_title_[parent].erase(title); 697 if (trackers_by_parent_and_title_[parent].empty()) 698 trackers_by_parent_and_title_.erase(parent); 699 } 700} 701 702void MetadataDatabaseIndex::AddToDirtyTrackerIndexes( 703 const FileTracker& new_tracker) { 704 DCHECK(!ContainsKey(dirty_trackers_, new_tracker.tracker_id())); 705 DCHECK(!ContainsKey(demoted_dirty_trackers_, new_tracker.tracker_id())); 706 707 if (new_tracker.dirty()) { 708 DVLOG(3) << " Add to dirty_trackers_: " << new_tracker.tracker_id(); 709 dirty_trackers_.insert(new_tracker.tracker_id()); 710 } 711} 712 713void MetadataDatabaseIndex::UpdateInDirtyTrackerIndexes( 714 const FileTracker& old_tracker, 715 const FileTracker& new_tracker) { 716 DCHECK_EQ(old_tracker.tracker_id(), new_tracker.tracker_id()); 717 718 int64 tracker_id = new_tracker.tracker_id(); 719 if (old_tracker.dirty() && !new_tracker.dirty()) { 720 DCHECK(ContainsKey(dirty_trackers_, tracker_id) || 721 ContainsKey(demoted_dirty_trackers_, tracker_id)); 722 723 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id; 724 725 dirty_trackers_.erase(tracker_id); 726 demoted_dirty_trackers_.erase(tracker_id); 727 } else if (!old_tracker.dirty() && new_tracker.dirty()) { 728 DCHECK(!ContainsKey(dirty_trackers_, tracker_id)); 729 DCHECK(!ContainsKey(demoted_dirty_trackers_, tracker_id)); 730 731 DVLOG(3) << " Add to dirty_trackers_: " << tracker_id; 732 733 dirty_trackers_.insert(tracker_id); 734 } 735} 736 737void MetadataDatabaseIndex::RemoveFromDirtyTrackerIndexes( 738 const FileTracker& tracker) { 739 if (tracker.dirty()) { 740 int64 tracker_id = tracker.tracker_id(); 741 DCHECK(ContainsKey(dirty_trackers_, tracker_id) || 742 ContainsKey(demoted_dirty_trackers_, tracker_id)); 743 744 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id; 745 dirty_trackers_.erase(tracker_id); 746 747 demoted_dirty_trackers_.erase(tracker_id); 748 } 749} 750 751} // namespace drive_backend 752} // namespace sync_file_system 753