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.
5 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index.h"
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"
20 // LevelDB database schema
21 // =======================
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.
30 // # Version of this schema
34 // # Metadata of the SyncFS service
36 // value: <ServiceMetadata 'service_metadata'>
38 // # Metadata of remote files
39 // key: "FILE: " + <string 'file_id'>
40 // value: <FileMetadata 'metadata'>
42 // # Trackers of local file updates
43 // key: "TRACKER: " + <int64 'tracker_id'>
44 // value: <FileTracker 'tracker'>
46 namespace sync_file_system
{
47 namespace drive_backend
{
49 ParentIDAndTitle::ParentIDAndTitle() : parent_id(0) {}
50 ParentIDAndTitle::ParentIDAndTitle(int64 parent_id
,
51 const std::string
& title
)
52 : parent_id(parent_id
), title(title
) {}
54 bool operator==(const ParentIDAndTitle
& left
, const ParentIDAndTitle
& right
) {
55 return left
.parent_id
== right
.parent_id
&& left
.title
== right
.title
;
58 bool 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
;
64 DatabaseContents::DatabaseContents() {}
66 DatabaseContents::~DatabaseContents() {}
70 template <typename Container
>
71 typename
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();
80 void ReadDatabaseContents(LevelDBWrapper
* db
, DatabaseContents
* contents
) {
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();
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");
98 contents
->file_metadata
.push_back(metadata
.release());
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");
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");
117 contents
->file_trackers
.push_back(tracker
.release());
123 void 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
;
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();
135 trackers_by_parent
[parent_tracker_id
].insert(tracker_id
);
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
];
142 if (!tracker
.active())
143 trackers_by_parent
.erase(tracker
.tracker_id());
146 std::vector
<int64
> pending
;
147 if (sync_root_tracker_id
!= kInvalidTrackerID
)
148 pending
.push_back(sync_root_tracker_id
);
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
);
157 if (!visited_trackers
.insert(tracker_id
).second
) {
163 LookUpMap(trackers_by_parent
, tracker_id
, std::set
<int64
>()),
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
] = nullptr;
175 PutFileTrackerDeletionToDB(tracker
->tracker_id(), db
);
178 contents
->file_trackers
= reachable_trackers
.Pass();
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());
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
] = nullptr;
193 PutFileMetadataDeletionToDB(metadata
->file_id(), db
);
196 contents
->file_metadata
= referred_file_metadata
.Pass();
202 scoped_ptr
<MetadataDatabaseIndex
>
203 MetadataDatabaseIndex::Create(LevelDBWrapper
* db
) {
206 scoped_ptr
<ServiceMetadata
> service_metadata
= InitializeServiceMetadata(db
);
207 if (!service_metadata
)
208 return scoped_ptr
<MetadataDatabaseIndex
>();
210 DatabaseContents contents
;
211 PutVersionToDB(kCurrentDatabaseVersion
, db
);
212 ReadDatabaseContents(db
, &contents
);
213 RemoveUnreachableItems(&contents
,
214 service_metadata
->sync_root_tracker_id(),
217 scoped_ptr
<MetadataDatabaseIndex
> index(new MetadataDatabaseIndex(db
));
218 index
->Initialize(service_metadata
.Pass(), &contents
);
223 scoped_ptr
<MetadataDatabaseIndex
>
224 MetadataDatabaseIndex::CreateForTesting(DatabaseContents
* contents
,
225 LevelDBWrapper
* db
) {
226 scoped_ptr
<MetadataDatabaseIndex
> index(new MetadataDatabaseIndex(db
));
227 index
->Initialize(make_scoped_ptr(new ServiceMetadata
), contents
);
231 void MetadataDatabaseIndex::Initialize(
232 scoped_ptr
<ServiceMetadata
> service_metadata
,
233 DatabaseContents
* contents
) {
234 service_metadata_
= service_metadata
.Pass();
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();
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();
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());
250 MetadataDatabaseIndex::MetadataDatabaseIndex(LevelDBWrapper
* db
) : db_(db
) {}
251 MetadataDatabaseIndex::~MetadataDatabaseIndex() {}
253 bool MetadataDatabaseIndex::GetFileMetadata(
254 const std::string
& file_id
, FileMetadata
* metadata
) const {
255 FileMetadata
* identified
= metadata_by_id_
.get(file_id
);
259 metadata
->CopyFrom(*identified
);
263 bool MetadataDatabaseIndex::GetFileTracker(
264 int64 tracker_id
, FileTracker
* tracker
) const {
265 FileTracker
* identified
= tracker_by_id_
.get(tracker_id
);
269 tracker
->CopyFrom(*identified
);
273 void MetadataDatabaseIndex::StoreFileMetadata(
274 scoped_ptr
<FileMetadata
> metadata
) {
275 PutFileMetadataToDB(*metadata
.get(), db_
);
281 std::string file_id
= metadata
->file_id();
282 metadata_by_id_
.set(file_id
, metadata
.Pass());
285 void MetadataDatabaseIndex::StoreFileTracker(
286 scoped_ptr
<FileTracker
> tracker
) {
287 PutFileTrackerToDB(*tracker
.get(), db_
);
293 int64 tracker_id
= tracker
->tracker_id();
294 FileTracker
* old_tracker
= tracker_by_id_
.get(tracker_id
);
297 DVLOG(3) << "Adding new tracker: " << tracker
->tracker_id()
298 << " " << GetTrackerTitle(*tracker
);
300 AddToAppIDIndex(*tracker
);
301 AddToPathIndexes(*tracker
);
302 AddToFileIDIndexes(*tracker
);
303 AddToDirtyTrackerIndexes(*tracker
);
305 DVLOG(3) << "Updating tracker: " << tracker
->tracker_id()
306 << " " << GetTrackerTitle(*tracker
);
308 UpdateInAppIDIndex(*old_tracker
, *tracker
);
309 UpdateInPathIndexes(*old_tracker
, *tracker
);
310 UpdateInFileIDIndexes(*old_tracker
, *tracker
);
311 UpdateInDirtyTrackerIndexes(*old_tracker
, *tracker
);
314 tracker_by_id_
.set(tracker_id
, tracker
.Pass());
317 void MetadataDatabaseIndex::RemoveFileMetadata(const std::string
& file_id
) {
318 PutFileMetadataDeletionToDB(file_id
, db_
);
319 metadata_by_id_
.erase(file_id
);
322 void MetadataDatabaseIndex::RemoveFileTracker(int64 tracker_id
) {
323 PutFileTrackerDeletionToDB(tracker_id
, db_
);
325 FileTracker
* tracker
= tracker_by_id_
.get(tracker_id
);
331 DVLOG(3) << "Removing tracker: "
332 << tracker
->tracker_id() << " " << GetTrackerTitle(*tracker
);
334 RemoveFromAppIDIndex(*tracker
);
335 RemoveFromPathIndexes(*tracker
);
336 RemoveFromFileIDIndexes(*tracker
);
337 RemoveFromDirtyTrackerIndexes(*tracker
);
339 tracker_by_id_
.erase(tracker_id
);
342 TrackerIDSet
MetadataDatabaseIndex::GetFileTrackerIDsByFileID(
343 const std::string
& file_id
) const {
344 return FindItem(trackers_by_file_id_
, file_id
);
347 int64
MetadataDatabaseIndex::GetAppRootTracker(
348 const std::string
& app_id
) const {
349 return FindItem(app_root_by_app_id_
, app_id
);
352 TrackerIDSet
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
);
362 std::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())
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());
378 std::string
MetadataDatabaseIndex::PickMultiTrackerFileID() const {
379 if (multi_tracker_file_ids_
.empty())
380 return std::string();
381 return *multi_tracker_file_ids_
.begin();
384 ParentIDAndTitle
MetadataDatabaseIndex::PickMultiBackingFilePath() const {
385 if (multi_backing_file_paths_
.empty())
386 return ParentIDAndTitle(kInvalidTrackerID
, std::string());
387 return *multi_backing_file_paths_
.begin();
390 int64
MetadataDatabaseIndex::PickDirtyTracker() const {
391 if (dirty_trackers_
.empty())
392 return kInvalidTrackerID
;
393 return *dirty_trackers_
.begin();
396 void MetadataDatabaseIndex::DemoteDirtyTracker(int64 tracker_id
) {
397 if (dirty_trackers_
.erase(tracker_id
))
398 demoted_dirty_trackers_
.insert(tracker_id
);
401 bool MetadataDatabaseIndex::HasDemotedDirtyTracker() const {
402 return !demoted_dirty_trackers_
.empty();
405 bool MetadataDatabaseIndex::IsDemotedDirtyTracker(int64 tracker_id
) const {
406 return demoted_dirty_trackers_
.find(tracker_id
) !=
407 demoted_dirty_trackers_
.end();
410 void MetadataDatabaseIndex::PromoteDemotedDirtyTracker(int64 tracker_id
) {
411 if (demoted_dirty_trackers_
.erase(tracker_id
) == 1)
412 dirty_trackers_
.insert(tracker_id
);
415 bool MetadataDatabaseIndex::PromoteDemotedDirtyTrackers() {
416 bool promoted
= !demoted_dirty_trackers_
.empty();
417 dirty_trackers_
.insert(demoted_dirty_trackers_
.begin(),
418 demoted_dirty_trackers_
.end());
419 demoted_dirty_trackers_
.clear();
423 size_t MetadataDatabaseIndex::CountDirtyTracker() const {
424 return dirty_trackers_
.size();
427 size_t MetadataDatabaseIndex::CountFileMetadata() const {
428 return metadata_by_id_
.size();
431 size_t MetadataDatabaseIndex::CountFileTracker() const {
432 return tracker_by_id_
.size();
435 void MetadataDatabaseIndex::SetSyncRootTrackerID(
436 int64 sync_root_id
) const {
437 service_metadata_
->set_sync_root_tracker_id(sync_root_id
);
438 PutServiceMetadataToDB(*service_metadata_
, db_
);
441 void MetadataDatabaseIndex::SetLargestChangeID(
442 int64 largest_change_id
) const {
443 service_metadata_
->set_largest_change_id(largest_change_id
);
444 PutServiceMetadataToDB(*service_metadata_
, db_
);
447 void MetadataDatabaseIndex::SetNextTrackerID(
448 int64 next_tracker_id
) const {
449 service_metadata_
->set_next_tracker_id(next_tracker_id
);
450 PutServiceMetadataToDB(*service_metadata_
, db_
);
453 int64
MetadataDatabaseIndex::GetSyncRootTrackerID() const {
454 if (!service_metadata_
->has_sync_root_tracker_id())
455 return kInvalidTrackerID
;
456 return service_metadata_
->sync_root_tracker_id();
459 int64
MetadataDatabaseIndex::GetLargestChangeID() const {
460 if (!service_metadata_
->has_largest_change_id())
461 return kInvalidTrackerID
;
462 return service_metadata_
->largest_change_id();
465 int64
MetadataDatabaseIndex::GetNextTrackerID() const {
466 if (!service_metadata_
->has_next_tracker_id()) {
468 return kInvalidTrackerID
;
470 return service_metadata_
->next_tracker_id();
473 std::vector
<std::string
> MetadataDatabaseIndex::GetRegisteredAppIDs() const {
474 std::vector
<std::string
> result
;
475 result
.reserve(app_root_by_app_id_
.size());
476 for (TrackerIDByAppID::const_iterator itr
= app_root_by_app_id_
.begin();
477 itr
!= app_root_by_app_id_
.end(); ++itr
)
478 result
.push_back(itr
->first
);
482 std::vector
<int64
> MetadataDatabaseIndex::GetAllTrackerIDs() const {
483 std::vector
<int64
> result
;
484 for (TrackerByID::const_iterator itr
= tracker_by_id_
.begin();
485 itr
!= tracker_by_id_
.end(); ++itr
) {
486 result
.push_back(itr
->first
);
491 std::vector
<std::string
> MetadataDatabaseIndex::GetAllMetadataIDs() const {
492 std::vector
<std::string
> result
;
493 for (MetadataByID::const_iterator itr
= metadata_by_id_
.begin();
494 itr
!= metadata_by_id_
.end(); ++itr
) {
495 result
.push_back(itr
->first
);
500 void MetadataDatabaseIndex::AddToAppIDIndex(
501 const FileTracker
& new_tracker
) {
502 if (!IsAppRoot(new_tracker
))
505 DVLOG(3) << " Add to app_root_by_app_id_: " << new_tracker
.app_id();
507 DCHECK(new_tracker
.active());
508 DCHECK(!ContainsKey(app_root_by_app_id_
, new_tracker
.app_id()));
509 app_root_by_app_id_
[new_tracker
.app_id()] = new_tracker
.tracker_id();
512 void MetadataDatabaseIndex::UpdateInAppIDIndex(
513 const FileTracker
& old_tracker
,
514 const FileTracker
& new_tracker
) {
515 DCHECK_EQ(old_tracker
.tracker_id(), new_tracker
.tracker_id());
517 if (IsAppRoot(old_tracker
) && !IsAppRoot(new_tracker
)) {
518 DCHECK(old_tracker
.active());
519 DCHECK(!new_tracker
.active());
520 DCHECK(ContainsKey(app_root_by_app_id_
, old_tracker
.app_id()));
522 DVLOG(3) << " Remove from app_root_by_app_id_: " << old_tracker
.app_id();
524 app_root_by_app_id_
.erase(old_tracker
.app_id());
525 } else if (!IsAppRoot(old_tracker
) && IsAppRoot(new_tracker
)) {
526 DCHECK(!old_tracker
.active());
527 DCHECK(new_tracker
.active());
528 DCHECK(!ContainsKey(app_root_by_app_id_
, new_tracker
.app_id()));
530 DVLOG(3) << " Add to app_root_by_app_id_: " << new_tracker
.app_id();
532 app_root_by_app_id_
[new_tracker
.app_id()] = new_tracker
.tracker_id();
536 void MetadataDatabaseIndex::RemoveFromAppIDIndex(
537 const FileTracker
& tracker
) {
538 if (IsAppRoot(tracker
)) {
539 DCHECK(tracker
.active());
540 DCHECK(ContainsKey(app_root_by_app_id_
, tracker
.app_id()));
542 DVLOG(3) << " Remove from app_root_by_app_id_: " << tracker
.app_id();
544 app_root_by_app_id_
.erase(tracker
.app_id());
548 void MetadataDatabaseIndex::AddToFileIDIndexes(
549 const FileTracker
& new_tracker
) {
550 DVLOG(3) << " Add to trackers_by_file_id_: " << new_tracker
.file_id();
552 trackers_by_file_id_
[new_tracker
.file_id()].Insert(new_tracker
);
554 if (trackers_by_file_id_
[new_tracker
.file_id()].size() > 1) {
555 DVLOG_IF(3, !ContainsKey(multi_tracker_file_ids_
, new_tracker
.file_id()))
556 << " Add to multi_tracker_file_ids_: " << new_tracker
.file_id();
557 multi_tracker_file_ids_
.insert(new_tracker
.file_id());
561 void MetadataDatabaseIndex::UpdateInFileIDIndexes(
562 const FileTracker
& old_tracker
,
563 const FileTracker
& new_tracker
) {
564 DCHECK_EQ(old_tracker
.tracker_id(), new_tracker
.tracker_id());
565 DCHECK_EQ(old_tracker
.file_id(), new_tracker
.file_id());
567 std::string file_id
= new_tracker
.file_id();
568 DCHECK(ContainsKey(trackers_by_file_id_
, file_id
));
570 if (old_tracker
.active() && !new_tracker
.active())
571 trackers_by_file_id_
[file_id
].Deactivate(new_tracker
.tracker_id());
572 else if (!old_tracker
.active() && new_tracker
.active())
573 trackers_by_file_id_
[file_id
].Activate(new_tracker
.tracker_id());
576 void MetadataDatabaseIndex::RemoveFromFileIDIndexes(
577 const FileTracker
& tracker
) {
578 TrackerIDsByFileID::iterator found
=
579 trackers_by_file_id_
.find(tracker
.file_id());
580 if (found
== trackers_by_file_id_
.end()) {
585 DVLOG(3) << " Remove from trackers_by_file_id_: "
586 << tracker
.tracker_id();
587 found
->second
.Erase(tracker
.tracker_id());
589 if (trackers_by_file_id_
[tracker
.file_id()].size() <= 1) {
590 DVLOG_IF(3, ContainsKey(multi_tracker_file_ids_
, tracker
.file_id()))
591 << " Remove from multi_tracker_file_ids_: " << tracker
.file_id();
592 multi_tracker_file_ids_
.erase(tracker
.file_id());
595 if (found
->second
.empty())
596 trackers_by_file_id_
.erase(found
);
599 void MetadataDatabaseIndex::AddToPathIndexes(
600 const FileTracker
& new_tracker
) {
601 int64 parent
= new_tracker
.parent_tracker_id();
602 std::string title
= GetTrackerTitle(new_tracker
);
604 DVLOG(3) << " Add to trackers_by_parent_and_title_: "
605 << parent
<< " " << title
;
607 trackers_by_parent_and_title_
[parent
][title
].Insert(new_tracker
);
609 if (trackers_by_parent_and_title_
[parent
][title
].size() > 1 &&
611 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_
,
612 ParentIDAndTitle(parent
, title
)))
613 << " Add to multi_backing_file_paths_: " << parent
<< " " << title
;
614 multi_backing_file_paths_
.insert(ParentIDAndTitle(parent
, title
));
618 void MetadataDatabaseIndex::UpdateInPathIndexes(
619 const FileTracker
& old_tracker
,
620 const FileTracker
& new_tracker
) {
621 DCHECK_EQ(old_tracker
.tracker_id(), new_tracker
.tracker_id());
622 DCHECK_EQ(old_tracker
.parent_tracker_id(), new_tracker
.parent_tracker_id());
623 DCHECK(GetTrackerTitle(old_tracker
) == GetTrackerTitle(new_tracker
) ||
624 !old_tracker
.has_synced_details());
626 int64 tracker_id
= new_tracker
.tracker_id();
627 int64 parent
= new_tracker
.parent_tracker_id();
628 std::string old_title
= GetTrackerTitle(old_tracker
);
629 std::string title
= GetTrackerTitle(new_tracker
);
631 TrackerIDsByTitle
* trackers_by_title
= &trackers_by_parent_and_title_
[parent
];
633 if (old_title
!= title
) {
634 TrackerIDsByTitle::iterator found
= trackers_by_title
->find(old_title
);
635 if (found
!= trackers_by_title
->end()) {
636 DVLOG(3) << " Remove from trackers_by_parent_and_title_: "
637 << parent
<< " " << old_title
;
639 found
->second
.Erase(tracker_id
);
640 if (found
->second
.empty())
641 trackers_by_title
->erase(found
);
646 DVLOG(3) << " Add to trackers_by_parent_and_title_: "
647 << parent
<< " " << title
;
649 (*trackers_by_title
)[title
].Insert(new_tracker
);
651 if (trackers_by_parent_and_title_
[parent
][old_title
].size() <= 1 &&
652 !old_title
.empty()) {
653 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_
,
654 ParentIDAndTitle(parent
, old_title
)))
655 << " Remove from multi_backing_file_paths_: "
656 << parent
<< " " << old_title
;
657 multi_backing_file_paths_
.erase(ParentIDAndTitle(parent
, old_title
));
660 if (trackers_by_parent_and_title_
[parent
][title
].size() > 1 &&
662 DVLOG_IF(3, !ContainsKey(multi_backing_file_paths_
,
663 ParentIDAndTitle(parent
, title
)))
664 << " Add to multi_backing_file_paths_: " << parent
<< " " << title
;
665 multi_backing_file_paths_
.insert(ParentIDAndTitle(parent
, title
));
671 if (old_tracker
.active() && !new_tracker
.active())
672 trackers_by_parent_and_title_
[parent
][title
].Deactivate(tracker_id
);
673 else if (!old_tracker
.active() && new_tracker
.active())
674 trackers_by_parent_and_title_
[parent
][title
].Activate(tracker_id
);
677 void MetadataDatabaseIndex::RemoveFromPathIndexes(
678 const FileTracker
& tracker
) {
679 int64 tracker_id
= tracker
.tracker_id();
680 int64 parent
= tracker
.parent_tracker_id();
681 std::string title
= GetTrackerTitle(tracker
);
683 DCHECK(ContainsKey(trackers_by_parent_and_title_
, parent
));
684 DCHECK(ContainsKey(trackers_by_parent_and_title_
[parent
], title
));
686 DVLOG(3) << " Remove from trackers_by_parent_and_title_: "
687 << parent
<< " " << title
;
689 trackers_by_parent_and_title_
[parent
][title
].Erase(tracker_id
);
691 if (trackers_by_parent_and_title_
[parent
][title
].size() <= 1 &&
693 DVLOG_IF(3, ContainsKey(multi_backing_file_paths_
,
694 ParentIDAndTitle(parent
, title
)))
695 << " Remove from multi_backing_file_paths_: "
696 << parent
<< " " << title
;
697 multi_backing_file_paths_
.erase(ParentIDAndTitle(parent
, title
));
700 if (trackers_by_parent_and_title_
[parent
][title
].empty()) {
701 trackers_by_parent_and_title_
[parent
].erase(title
);
702 if (trackers_by_parent_and_title_
[parent
].empty())
703 trackers_by_parent_and_title_
.erase(parent
);
707 void MetadataDatabaseIndex::AddToDirtyTrackerIndexes(
708 const FileTracker
& new_tracker
) {
709 DCHECK(!ContainsKey(dirty_trackers_
, new_tracker
.tracker_id()));
710 DCHECK(!ContainsKey(demoted_dirty_trackers_
, new_tracker
.tracker_id()));
712 if (new_tracker
.dirty()) {
713 DVLOG(3) << " Add to dirty_trackers_: " << new_tracker
.tracker_id();
714 dirty_trackers_
.insert(new_tracker
.tracker_id());
718 void MetadataDatabaseIndex::UpdateInDirtyTrackerIndexes(
719 const FileTracker
& old_tracker
,
720 const FileTracker
& new_tracker
) {
721 DCHECK_EQ(old_tracker
.tracker_id(), new_tracker
.tracker_id());
723 int64 tracker_id
= new_tracker
.tracker_id();
724 if (old_tracker
.dirty() && !new_tracker
.dirty()) {
725 DCHECK(ContainsKey(dirty_trackers_
, tracker_id
) ||
726 ContainsKey(demoted_dirty_trackers_
, tracker_id
));
728 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id
;
730 dirty_trackers_
.erase(tracker_id
);
731 demoted_dirty_trackers_
.erase(tracker_id
);
732 } else if (!old_tracker
.dirty() && new_tracker
.dirty()) {
733 DCHECK(!ContainsKey(dirty_trackers_
, tracker_id
));
734 DCHECK(!ContainsKey(demoted_dirty_trackers_
, tracker_id
));
736 DVLOG(3) << " Add to dirty_trackers_: " << tracker_id
;
738 dirty_trackers_
.insert(tracker_id
);
742 void MetadataDatabaseIndex::RemoveFromDirtyTrackerIndexes(
743 const FileTracker
& tracker
) {
744 if (tracker
.dirty()) {
745 int64 tracker_id
= tracker
.tracker_id();
746 DCHECK(ContainsKey(dirty_trackers_
, tracker_id
) ||
747 ContainsKey(demoted_dirty_trackers_
, tracker_id
));
749 DVLOG(3) << " Remove from dirty_trackers_: " << tracker_id
;
750 dirty_trackers_
.erase(tracker_id
);
752 demoted_dirty_trackers_
.erase(tracker_id
);
756 } // namespace drive_backend
757 } // namespace sync_file_system