Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / drive_backend / metadata_database.cc
1 // Copyright 2013 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.h"
6
7 #include <algorithm>
8 #include <stack>
9
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/file_util.h"
14 #include "base/files/file_path.h"
15 #include "base/location.h"
16 #include "base/memory/scoped_vector.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/task_runner_util.h"
23 #include "base/thread_task_runner_handle.h"
24 #include "base/threading/thread_restrictions.h"
25 #include "chrome/browser/drive/drive_api_util.h"
26 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
27 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
28 #include "chrome/browser/sync_file_system/drive_backend/leveldb_wrapper.h"
29 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
30 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index.h"
31 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index_interface.h"
32 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.h"
33 #include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h"
34 #include "chrome/browser/sync_file_system/logger.h"
35 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
36 #include "google_apis/drive/drive_api_parser.h"
37 #include "third_party/leveldatabase/src/include/leveldb/db.h"
38 #include "third_party/leveldatabase/src/include/leveldb/env.h"
39 #include "third_party/leveldatabase/src/include/leveldb/status.h"
40 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
41 #include "webkit/common/fileapi/file_system_util.h"
42
43 namespace sync_file_system {
44 namespace drive_backend {
45
46 namespace {
47
48 // Command line flag to enable on-disk indexing.
49 const char kEnableMetadataDatabaseOnDisk[] = "enable-syncfs-on-disk-indexing";
50
51 void EmptyStatusCallback(SyncStatusCode status) {}
52
53 std::string FileKindToString(FileKind file_kind) {
54   switch (file_kind) {
55     case FILE_KIND_UNSUPPORTED:
56       return "unsupported";
57     case FILE_KIND_FILE:
58       return "file";
59     case FILE_KIND_FOLDER:
60       return "folder";
61   }
62
63   NOTREACHED();
64   return "unknown";
65 }
66
67 base::FilePath ReverseConcatPathComponents(
68     const std::vector<base::FilePath>& components) {
69   if (components.empty())
70     return base::FilePath(FILE_PATH_LITERAL("/")).NormalizePathSeparators();
71
72   size_t total_size = 0;
73   typedef std::vector<base::FilePath> PathComponents;
74   for (PathComponents::const_iterator itr = components.begin();
75        itr != components.end(); ++itr)
76     total_size += itr->value().size() + 1;
77
78   base::FilePath::StringType result;
79   result.reserve(total_size);
80   for (PathComponents::const_reverse_iterator itr = components.rbegin();
81        itr != components.rend(); ++itr) {
82     result.append(1, base::FilePath::kSeparators[0]);
83     result.append(itr->value());
84   }
85
86   return base::FilePath(result).NormalizePathSeparators();
87 }
88
89 void PopulateFileDetailsByFileResource(
90     const google_apis::FileResource& file_resource,
91     FileDetails* details) {
92   details->clear_parent_folder_ids();
93   for (std::vector<google_apis::ParentReference>::const_iterator itr =
94            file_resource.parents().begin();
95        itr != file_resource.parents().end();
96        ++itr) {
97     details->add_parent_folder_ids(itr->file_id());
98   }
99   details->set_title(file_resource.title());
100
101   if (file_resource.IsDirectory())
102     details->set_file_kind(FILE_KIND_FOLDER);
103   else if (file_resource.IsHostedDocument())
104     details->set_file_kind(FILE_KIND_UNSUPPORTED);
105   else
106     details->set_file_kind(FILE_KIND_FILE);
107
108   details->set_md5(file_resource.md5_checksum());
109   details->set_etag(file_resource.etag());
110   details->set_creation_time(file_resource.created_date().ToInternalValue());
111   details->set_modification_time(
112       file_resource.modified_date().ToInternalValue());
113   details->set_missing(file_resource.labels().is_trashed());
114 }
115
116 scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource(
117     int64 change_id,
118     const google_apis::FileResource& resource) {
119   scoped_ptr<FileMetadata> file(new FileMetadata);
120   file->set_file_id(resource.file_id());
121
122   FileDetails* details = file->mutable_details();
123   details->set_change_id(change_id);
124
125   if (resource.labels().is_trashed()) {
126     details->set_missing(true);
127     return file.Pass();
128   }
129
130   PopulateFileDetailsByFileResource(resource, details);
131   return file.Pass();
132 }
133
134 scoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource(
135     const google_apis::ChangeResource& change) {
136   scoped_ptr<FileMetadata> file(new FileMetadata);
137   file->set_file_id(change.file_id());
138
139   FileDetails* details = file->mutable_details();
140   details->set_change_id(change.change_id());
141
142   if (change.is_deleted()) {
143     details->set_missing(true);
144     return file.Pass();
145   }
146
147   PopulateFileDetailsByFileResource(*change.file(), details);
148   return file.Pass();
149 }
150
151 scoped_ptr<FileMetadata> CreateDeletedFileMetadata(
152     int64 change_id,
153     const std::string& file_id) {
154   scoped_ptr<FileMetadata> file(new FileMetadata);
155   file->set_file_id(file_id);
156
157   FileDetails* details = file->mutable_details();
158   details->set_change_id(change_id);
159   details->set_missing(true);
160   return file.Pass();
161 }
162
163 scoped_ptr<FileTracker> CreateSyncRootTracker(
164     int64 tracker_id,
165     const FileMetadata& sync_root_metadata) {
166   scoped_ptr<FileTracker> sync_root_tracker(new FileTracker);
167   sync_root_tracker->set_tracker_id(tracker_id);
168   sync_root_tracker->set_file_id(sync_root_metadata.file_id());
169   sync_root_tracker->set_parent_tracker_id(0);
170   sync_root_tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
171   sync_root_tracker->set_dirty(false);
172   sync_root_tracker->set_active(true);
173   sync_root_tracker->set_needs_folder_listing(false);
174   *sync_root_tracker->mutable_synced_details() = sync_root_metadata.details();
175   return sync_root_tracker.Pass();
176 }
177
178 scoped_ptr<FileTracker> CreateInitialAppRootTracker(
179     int64 tracker_id,
180     int64 parent_tracker_id,
181     const FileMetadata& app_root_metadata) {
182   scoped_ptr<FileTracker> app_root_tracker(new FileTracker);
183   app_root_tracker->set_tracker_id(tracker_id);
184   app_root_tracker->set_parent_tracker_id(parent_tracker_id);
185   app_root_tracker->set_file_id(app_root_metadata.file_id());
186   app_root_tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
187   app_root_tracker->set_dirty(false);
188   app_root_tracker->set_active(false);
189   app_root_tracker->set_needs_folder_listing(false);
190   *app_root_tracker->mutable_synced_details() = app_root_metadata.details();
191   return app_root_tracker.Pass();
192 }
193
194 scoped_ptr<FileTracker> CloneFileTracker(const FileTracker* obj) {
195   if (!obj)
196     return scoped_ptr<FileTracker>();
197   return scoped_ptr<FileTracker>(new FileTracker(*obj));
198 }
199
200 // Returns true if |db| has no content.
201 bool IsDatabaseEmpty(LevelDBWrapper* db) {
202   DCHECK(db);
203   scoped_ptr<LevelDBWrapper::Iterator> itr(db->NewIterator());
204   itr->SeekToFirst();
205   return !itr->Valid();
206 }
207
208 SyncStatusCode OpenDatabase(const base::FilePath& path,
209                             leveldb::Env* env_override,
210                             scoped_ptr<LevelDBWrapper>* db_out,
211                             bool* created) {
212   base::ThreadRestrictions::AssertIOAllowed();
213   DCHECK(db_out);
214   DCHECK(created);
215   DCHECK(path.IsAbsolute());
216
217   leveldb::Options options;
218   options.max_open_files = 0;  // Use minimum.
219   options.create_if_missing = true;
220   if (env_override)
221     options.env = env_override;
222   leveldb::DB* db = NULL;
223   leveldb::Status db_status =
224       leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db);
225   SyncStatusCode status = LevelDBStatusToSyncStatusCode(db_status);
226   if (status != SYNC_STATUS_OK) {
227     delete db;
228     return status;
229   }
230
231   db_out->reset(new LevelDBWrapper(make_scoped_ptr(db)));
232   *created = IsDatabaseEmpty(db_out->get());
233   return status;
234 }
235
236 SyncStatusCode MigrateDatabaseIfNeeded(LevelDBWrapper* db) {
237   // See metadata_database_index.cc for the database schema.
238   base::ThreadRestrictions::AssertIOAllowed();
239   DCHECK(db);
240   std::string value;
241   leveldb::Status status = db->Get(kDatabaseVersionKey, &value);
242   int64 version = 0;
243   if (status.ok()) {
244     if (!base::StringToInt64(value, &version))
245       return SYNC_DATABASE_ERROR_FAILED;
246   } else {
247     if (!status.IsNotFound())
248       return SYNC_DATABASE_ERROR_FAILED;
249   }
250
251   switch (version) {
252     case 0:
253       drive_backend::MigrateDatabaseFromV0ToV1(db->GetLevelDB());
254       // fall-through
255     case 1:
256       drive_backend::MigrateDatabaseFromV1ToV2(db->GetLevelDB());
257       // fall-through
258     case 2:
259       // TODO(tzik): Migrate database from version 2 to 3.
260       //   * Add sync-root folder as active, dirty and needs_folder_listing
261       //     folder.
262       //   * Add app-root folders for each origins.  Each app-root folder for
263       //     an enabled origin should be a active, dirty and
264       //     needs_folder_listing folder.  And Each app-root folder for a
265       //     disabled origin should be an inactive, dirty and
266       //     non-needs_folder_listing folder.
267       //   * Add a file metadata for each file in previous version.
268       NOTIMPLEMENTED();
269       return SYNC_DATABASE_ERROR_FAILED;
270       // fall-through
271     case 3:
272       DCHECK_EQ(3, kCurrentDatabaseVersion);
273       // If MetadataDatabaseOnDisk is enabled, migration will be done in
274       // MetadataDatabaseOnDisk::Create().
275       // TODO(peria): Move the migration code (from v3 to v4) here.
276       return SYNC_STATUS_OK;
277     case 4:
278       if (!CommandLine::ForCurrentProcess()->HasSwitch(
279               kEnableMetadataDatabaseOnDisk)) {
280         MigrateDatabaseFromV4ToV3(db->GetLevelDB());
281       }
282       return SYNC_STATUS_OK;
283     default:
284       return SYNC_DATABASE_ERROR_FAILED;
285   }
286 }
287
288 bool HasInvalidTitle(const std::string& title) {
289   return title.empty() ||
290       title.find('/') != std::string::npos ||
291       title.find('\\') != std::string::npos;
292 }
293
294 void MarkTrackerSetDirty(const TrackerIDSet& trackers,
295                          MetadataDatabaseIndexInterface* index) {
296   for (TrackerIDSet::const_iterator itr = trackers.begin();
297        itr != trackers.end(); ++itr) {
298     scoped_ptr<FileTracker> tracker(new FileTracker);
299     index->GetFileTracker(*itr, tracker.get());
300     if (tracker->dirty())
301       continue;
302     tracker->set_dirty(true);
303     index->StoreFileTracker(tracker.Pass());
304   }
305 }
306
307 void MarkTrackersDirtyByPath(int64 parent_tracker_id,
308                              const std::string& title,
309                              MetadataDatabaseIndexInterface* index) {
310   if (parent_tracker_id == kInvalidTrackerID || title.empty())
311     return;
312   MarkTrackerSetDirty(
313       index->GetFileTrackerIDsByParentAndTitle(parent_tracker_id, title),
314       index);
315 }
316
317 void MarkTrackersDirtyByFileID(const std::string& file_id,
318                                MetadataDatabaseIndexInterface* index) {
319   MarkTrackerSetDirty(index->GetFileTrackerIDsByFileID(file_id), index);
320 }
321
322 void MarkTrackersDirtyRecursively(int64 root_tracker_id,
323                                   MetadataDatabaseIndexInterface* index) {
324   std::vector<int64> stack;
325   stack.push_back(root_tracker_id);
326   while (!stack.empty()) {
327     int64 tracker_id = stack.back();
328     stack.pop_back();
329     AppendContents(index->GetFileTrackerIDsByParent(tracker_id), &stack);
330
331     scoped_ptr<FileTracker> tracker(new FileTracker);
332     index->GetFileTracker(tracker_id, tracker.get());
333     tracker->set_dirty(true);
334
335     index->StoreFileTracker(tracker.Pass());
336   }
337 }
338
339 void RemoveAllDescendantTrackers(int64 root_tracker_id,
340                                  MetadataDatabaseIndexInterface* index) {
341   std::vector<int64> pending_trackers;
342   AppendContents(index->GetFileTrackerIDsByParent(root_tracker_id),
343                  &pending_trackers);
344
345   std::vector<int64> to_be_removed;
346
347   // List trackers to remove.
348   while (!pending_trackers.empty()) {
349     int64 tracker_id = pending_trackers.back();
350     pending_trackers.pop_back();
351     AppendContents(index->GetFileTrackerIDsByParent(tracker_id),
352                    &pending_trackers);
353     to_be_removed.push_back(tracker_id);
354   }
355
356   // Remove trackers in the reversed order.
357   base::hash_set<std::string> affected_file_ids;
358   for (std::vector<int64>::reverse_iterator itr = to_be_removed.rbegin();
359        itr != to_be_removed.rend(); ++itr) {
360     FileTracker tracker;
361     index->GetFileTracker(*itr, &tracker);
362     affected_file_ids.insert(tracker.file_id());
363     index->RemoveFileTracker(*itr);
364   }
365
366   for (base::hash_set<std::string>::iterator itr = affected_file_ids.begin();
367        itr != affected_file_ids.end(); ++itr) {
368     TrackerIDSet trackers = index->GetFileTrackerIDsByFileID(*itr);
369     if (trackers.empty()) {
370       // Remove metadata that no longer has any tracker.
371       index->RemoveFileMetadata(*itr);
372     } else {
373       MarkTrackerSetDirty(trackers, index);
374     }
375   }
376 }
377
378 bool FilterFileTrackersByParent(
379     const MetadataDatabaseIndexInterface* index,
380     const TrackerIDSet& trackers,
381     int64 parent_tracker_id,
382     FileTracker* tracker_out) {
383   FileTracker tracker;
384   for (TrackerIDSet::const_iterator itr = trackers.begin();
385        itr != trackers.end(); ++itr) {
386     if (!index->GetFileTracker(*itr, &tracker)) {
387       NOTREACHED();
388       continue;
389     }
390
391     if (tracker.parent_tracker_id() == parent_tracker_id) {
392       if (tracker_out)
393         tracker_out->CopyFrom(tracker);
394       return true;
395     }
396   }
397   return false;
398 }
399
400 bool FilterFileTrackersByParentAndTitle(
401     const MetadataDatabaseIndexInterface* index,
402     const TrackerIDSet& trackers,
403     int64 parent_tracker_id,
404     const std::string& title,
405     FileTracker* result) {
406   bool found = false;
407   for (TrackerIDSet::const_iterator itr = trackers.begin();
408        itr != trackers.end(); ++itr) {
409     FileTracker tracker;
410     if (!index->GetFileTracker(*itr, &tracker)) {
411       NOTREACHED();
412       continue;
413     }
414
415     if (tracker.parent_tracker_id() != parent_tracker_id)
416       continue;
417
418     if (tracker.has_synced_details() &&
419         tracker.synced_details().title() != title)
420       continue;
421
422     // Prioritize trackers that has |synced_details| when |trackers| has
423     // multiple candidates.
424     if (!found || tracker.has_synced_details()) {
425       found = true;
426       if (result)
427         result->CopyFrom(tracker);
428       if (!result || result->has_synced_details())
429         return found;
430     }
431   }
432
433   return found;
434 }
435
436 bool FilterFileTrackersByFileID(
437     const MetadataDatabaseIndexInterface* index,
438     const TrackerIDSet& trackers,
439     const std::string& file_id,
440     FileTracker* tracker_out) {
441   FileTracker tracker;
442   for (TrackerIDSet::const_iterator itr = trackers.begin();
443        itr != trackers.end(); ++itr) {
444     if (!index->GetFileTracker(*itr, &tracker)) {
445       NOTREACHED();
446       continue;
447     }
448
449     if (tracker.file_id() == file_id) {
450       if (tracker_out)
451         tracker_out->CopyFrom(tracker);
452       return true;
453     }
454   }
455   return false;
456 }
457
458 enum DirtyingOption {
459   MARK_NOTHING_DIRTY = 0,
460   MARK_ITSELF_DIRTY = 1 << 0,
461   MARK_SAME_FILE_ID_TRACKERS_DIRTY = 1 << 1,
462   MARK_SAME_PATH_TRACKERS_DIRTY = 1 << 2,
463 };
464
465 void ActivateFileTracker(int64 tracker_id,
466                          int dirtying_options,
467                          MetadataDatabaseIndexInterface* index) {
468   DCHECK(dirtying_options == MARK_NOTHING_DIRTY ||
469          dirtying_options == MARK_ITSELF_DIRTY);
470
471   scoped_ptr<FileTracker> tracker(new FileTracker);
472   index->GetFileTracker(tracker_id, tracker.get());
473   tracker->set_active(true);
474   if (dirtying_options & MARK_ITSELF_DIRTY) {
475     tracker->set_dirty(true);
476     tracker->set_needs_folder_listing(
477         tracker->has_synced_details() &&
478         tracker->synced_details().file_kind() == FILE_KIND_FOLDER);
479   } else {
480     tracker->set_dirty(false);
481     tracker->set_needs_folder_listing(false);
482   }
483
484   index->StoreFileTracker(tracker.Pass());
485 }
486
487 void DeactivateFileTracker(int64 tracker_id,
488                            int dirtying_options,
489                            MetadataDatabaseIndexInterface* index) {
490   RemoveAllDescendantTrackers(tracker_id, index);
491
492   scoped_ptr<FileTracker> tracker(new FileTracker);
493   index->GetFileTracker(tracker_id, tracker.get());
494
495   if (dirtying_options & MARK_SAME_FILE_ID_TRACKERS_DIRTY)
496     MarkTrackersDirtyByFileID(tracker->file_id(), index);
497   if (dirtying_options & MARK_SAME_PATH_TRACKERS_DIRTY) {
498     MarkTrackersDirtyByPath(tracker->parent_tracker_id(),
499                             GetTrackerTitle(*tracker), index);
500   }
501
502   tracker->set_dirty(dirtying_options & MARK_ITSELF_DIRTY);
503   tracker->set_active(false);
504   index->StoreFileTracker(tracker.Pass());
505 }
506
507 void RemoveFileTracker(int64 tracker_id,
508                        int dirtying_options,
509                        MetadataDatabaseIndexInterface* index) {
510   DCHECK(!(dirtying_options & MARK_ITSELF_DIRTY));
511
512   FileTracker tracker;
513   if (!index->GetFileTracker(tracker_id, &tracker))
514     return;
515
516   std::string file_id = tracker.file_id();
517   int64 parent_tracker_id = tracker.parent_tracker_id();
518   std::string title = GetTrackerTitle(tracker);
519
520   RemoveAllDescendantTrackers(tracker_id, index);
521   index->RemoveFileTracker(tracker_id);
522
523   if (dirtying_options & MARK_SAME_FILE_ID_TRACKERS_DIRTY)
524     MarkTrackersDirtyByFileID(file_id, index);
525   if (dirtying_options & MARK_SAME_PATH_TRACKERS_DIRTY)
526     MarkTrackersDirtyByPath(parent_tracker_id, title, index);
527
528   if (index->GetFileTrackerIDsByFileID(file_id).empty()) {
529     index->RemoveFileMetadata(file_id);
530   }
531 }
532
533 }  // namespace
534
535 struct MetadataDatabase::CreateParam {
536   scoped_refptr<base::SequencedTaskRunner> worker_task_runner;
537   base::FilePath database_path;
538   leveldb::Env* env_override;
539
540   CreateParam(base::SequencedTaskRunner* worker_task_runner,
541               const base::FilePath& database_path,
542               leveldb::Env* env_override)
543       : worker_task_runner(worker_task_runner),
544         database_path(database_path),
545         env_override(env_override) {
546   }
547 };
548
549 // static
550 void MetadataDatabase::Create(base::SequencedTaskRunner* worker_task_runner,
551                               const base::FilePath& database_path,
552                               leveldb::Env* env_override,
553                               const CreateCallback& callback) {
554   worker_task_runner->PostTask(FROM_HERE, base::Bind(
555       &MetadataDatabase::CreateOnWorkerTaskRunner,
556       base::Passed(make_scoped_ptr(new CreateParam(
557           worker_task_runner,
558           database_path,
559           env_override))),
560       callback));
561 }
562
563 // static
564 SyncStatusCode MetadataDatabase::CreateForTesting(
565     scoped_ptr<LevelDBWrapper> db,
566     scoped_ptr<MetadataDatabase>* metadata_database_out) {
567   scoped_ptr<MetadataDatabase> metadata_database(
568       new MetadataDatabase(base::ThreadTaskRunnerHandle::Get(),
569                            base::FilePath(), NULL));
570   metadata_database->db_ = db.Pass();
571   SyncStatusCode status = metadata_database->Initialize();
572   if (status == SYNC_STATUS_OK)
573     *metadata_database_out = metadata_database.Pass();
574   return status;
575 }
576
577 MetadataDatabase::~MetadataDatabase() {
578   worker_task_runner_->DeleteSoon(FROM_HERE, db_.release());
579 }
580
581 // static
582 void MetadataDatabase::ClearDatabase(
583     scoped_ptr<MetadataDatabase> metadata_database) {
584   DCHECK(metadata_database);
585   scoped_refptr<base::SequencedTaskRunner> worker_task_runner =
586       metadata_database->worker_task_runner_;
587   base::FilePath database_path = metadata_database->database_path_;
588   DCHECK(!database_path.empty());
589   metadata_database.reset();
590
591   worker_task_runner->PostTask(
592       FROM_HERE,
593       base::Bind(base::IgnoreResult(base::DeleteFile),
594                  database_path, true /* recursive */));
595 }
596
597 int64 MetadataDatabase::GetLargestFetchedChangeID() const {
598   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
599   return index_->GetLargestChangeID();
600 }
601
602 int64 MetadataDatabase::GetSyncRootTrackerID() const {
603   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
604   return index_->GetSyncRootTrackerID();
605 }
606
607 int64 MetadataDatabase::GetLargestKnownChangeID() const {
608   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
609   DCHECK_LE(GetLargestFetchedChangeID(), largest_known_change_id_);
610   return largest_known_change_id_;
611 }
612
613 void MetadataDatabase::UpdateLargestKnownChangeID(int64 change_id) {
614   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
615   if (largest_known_change_id_ < change_id)
616     largest_known_change_id_ = change_id;
617 }
618
619 bool MetadataDatabase::HasSyncRoot() const {
620   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
621   return index_->GetSyncRootTrackerID() != kInvalidTrackerID;
622 }
623
624 void MetadataDatabase::PopulateInitialData(
625     int64 largest_change_id,
626     const google_apis::FileResource& sync_root_folder,
627     const ScopedVector<google_apis::FileResource>& app_root_folders,
628     const SyncStatusCallback& callback) {
629   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
630
631   index_->SetLargestChangeID(largest_change_id);
632   UpdateLargestKnownChangeID(largest_change_id);
633
634   AttachSyncRoot(sync_root_folder);
635   for (size_t i = 0; i < app_root_folders.size(); ++i)
636     AttachInitialAppRoot(*app_root_folders[i]);
637
638   WriteToDatabase(callback);
639 }
640
641 bool MetadataDatabase::IsAppEnabled(const std::string& app_id) const {
642   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
643
644   int64 tracker_id = index_->GetAppRootTracker(app_id);
645   if (tracker_id == kInvalidTrackerID)
646     return false;
647
648   FileTracker tracker;
649   if (!index_->GetFileTracker(tracker_id, &tracker))
650     return false;
651   return tracker.tracker_kind() == TRACKER_KIND_APP_ROOT;
652 }
653
654 void MetadataDatabase::RegisterApp(const std::string& app_id,
655                                    const std::string& folder_id,
656                                    const SyncStatusCallback& callback) {
657   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
658
659   if (index_->GetAppRootTracker(app_id)) {
660     // The app-root is already registered.
661     worker_task_runner_->PostTask(
662         FROM_HERE,
663         base::Bind(callback, SYNC_STATUS_OK));
664     return;
665   }
666
667   TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(folder_id);
668   if (trackers.empty()) {
669     worker_task_runner_->PostTask(
670         FROM_HERE,
671         base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
672     return;
673   }
674
675   if (trackers.has_active()) {
676     // The folder is tracked by another tracker.
677     util::Log(logging::LOG_WARNING, FROM_HERE,
678               "Failed to register App for %s", app_id.c_str());
679     worker_task_runner_->PostTask(
680         FROM_HERE,
681         base::Bind(callback, SYNC_STATUS_HAS_CONFLICT));
682     return;
683   }
684
685   int64 sync_root_tracker_id = index_->GetSyncRootTrackerID();
686   if (!sync_root_tracker_id) {
687     util::Log(logging::LOG_WARNING, FROM_HERE,
688               "Sync-root needs to be set up before registering app-root");
689     worker_task_runner_->PostTask(
690         FROM_HERE,
691         base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
692     return;
693   }
694
695   scoped_ptr<FileTracker> tracker(new FileTracker);
696   if (!FilterFileTrackersByParent(index_.get(), trackers,
697                                   sync_root_tracker_id, tracker.get())) {
698     worker_task_runner_->PostTask(
699         FROM_HERE,
700         base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
701     return;
702   }
703
704   tracker->set_app_id(app_id);
705   tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT);
706   tracker->set_active(true);
707   tracker->set_needs_folder_listing(true);
708   tracker->set_dirty(true);
709
710   index_->StoreFileTracker(tracker.Pass());
711   WriteToDatabase(callback);
712 }
713
714 void MetadataDatabase::DisableApp(const std::string& app_id,
715                                   const SyncStatusCallback& callback) {
716   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
717
718   int64 tracker_id = index_->GetAppRootTracker(app_id);
719   scoped_ptr<FileTracker> tracker(new FileTracker);
720   if (!index_->GetFileTracker(tracker_id, tracker.get())) {
721     callback.Run(SYNC_DATABASE_ERROR_NOT_FOUND);
722     return;
723   }
724
725   if (tracker->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT) {
726     callback.Run(SYNC_STATUS_OK);
727     return;
728   }
729
730   DCHECK_EQ(TRACKER_KIND_APP_ROOT, tracker->tracker_kind());
731   DCHECK(tracker->active());
732
733   // Keep the app-root tracker active (but change the tracker_kind) so that
734   // other conflicting trackers won't become active.
735   tracker->set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT);
736
737   index_->StoreFileTracker(tracker.Pass());
738   WriteToDatabase(callback);
739 }
740
741 void MetadataDatabase::EnableApp(const std::string& app_id,
742                                  const SyncStatusCallback& callback) {
743   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
744
745   int64 tracker_id = index_->GetAppRootTracker(app_id);
746   scoped_ptr<FileTracker> tracker(new FileTracker);
747   if (!index_->GetFileTracker(tracker_id, tracker.get())) {
748     callback.Run(SYNC_DATABASE_ERROR_NOT_FOUND);
749     return;
750   }
751
752   if (tracker->tracker_kind() == TRACKER_KIND_APP_ROOT) {
753     callback.Run(SYNC_STATUS_OK);
754     return;
755   }
756
757   DCHECK_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker->tracker_kind());
758   DCHECK(tracker->active());
759
760   tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT);
761   index_->StoreFileTracker(tracker.Pass());
762
763   MarkTrackersDirtyRecursively(tracker_id, index_.get());
764   WriteToDatabase(callback);
765 }
766
767 void MetadataDatabase::UnregisterApp(const std::string& app_id,
768                                      const SyncStatusCallback& callback) {
769   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
770
771   int64 tracker_id = index_->GetAppRootTracker(app_id);
772   scoped_ptr<FileTracker> tracker(new FileTracker);
773   if (!index_->GetFileTracker(tracker_id, tracker.get()) ||
774       tracker->tracker_kind() == TRACKER_KIND_REGULAR) {
775     worker_task_runner_->PostTask(
776         FROM_HERE,
777         base::Bind(callback, SYNC_STATUS_OK));
778     return;
779   }
780
781   RemoveAllDescendantTrackers(tracker_id, index_.get());
782
783   tracker->clear_app_id();
784   tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
785   tracker->set_active(false);
786   tracker->set_dirty(true);
787
788   index_->StoreFileTracker(tracker.Pass());
789   WriteToDatabase(callback);
790 }
791
792 bool MetadataDatabase::FindAppRootTracker(const std::string& app_id,
793                                           FileTracker* tracker_out) const {
794   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
795
796   int64 app_root_tracker_id = index_->GetAppRootTracker(app_id);
797   if (!app_root_tracker_id)
798     return false;
799
800   if (tracker_out &&
801       !index_->GetFileTracker(app_root_tracker_id, tracker_out)) {
802     NOTREACHED();
803     return false;
804   }
805
806   return true;
807 }
808
809 bool MetadataDatabase::FindFileByFileID(const std::string& file_id,
810                                         FileMetadata* metadata_out) const {
811   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
812   return index_->GetFileMetadata(file_id, metadata_out);
813 }
814
815 bool MetadataDatabase::FindTrackersByFileID(const std::string& file_id,
816                                             TrackerIDSet* trackers_out) const {
817   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
818
819   TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(file_id);
820   if (trackers.empty())
821     return false;
822
823   if (trackers_out)
824     std::swap(trackers, *trackers_out);
825   return true;
826 }
827
828 bool MetadataDatabase::FindTrackersByParentAndTitle(
829     int64 parent_tracker_id,
830     const std::string& title,
831     TrackerIDSet* trackers_out) const {
832   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
833
834   TrackerIDSet trackers =
835       index_->GetFileTrackerIDsByParentAndTitle(parent_tracker_id, title);
836   if (trackers.empty())
837     return false;
838
839   if (trackers_out)
840     std::swap(trackers, *trackers_out);
841   return true;
842 }
843
844 bool MetadataDatabase::FindTrackerByTrackerID(int64 tracker_id,
845                                               FileTracker* tracker_out) const {
846   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
847   return index_->GetFileTracker(tracker_id, tracker_out);
848 }
849
850 bool MetadataDatabase::BuildPathForTracker(int64 tracker_id,
851                                            base::FilePath* path) const {
852   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
853
854   FileTracker current;
855   if (!FindTrackerByTrackerID(tracker_id, &current) || !current.active())
856     return false;
857
858   std::vector<base::FilePath> components;
859   while (!IsAppRoot(current)) {
860     std::string title = GetTrackerTitle(current);
861     if (title.empty())
862       return false;
863     components.push_back(base::FilePath::FromUTF8Unsafe(title));
864     if (!FindTrackerByTrackerID(current.parent_tracker_id(), &current) ||
865         !current.active())
866       return false;
867   }
868
869   if (path)
870     *path = ReverseConcatPathComponents(components);
871
872   return true;
873 }
874
875 base::FilePath MetadataDatabase::BuildDisplayPathForTracker(
876     const FileTracker& tracker) const {
877   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
878
879   base::FilePath path;
880   if (tracker.active()) {
881     BuildPathForTracker(tracker.tracker_id(), &path);
882     return path;
883   }
884   BuildPathForTracker(tracker.parent_tracker_id(), &path);
885   if (tracker.has_synced_details()) {
886     path = path.Append(
887         base::FilePath::FromUTF8Unsafe(tracker.synced_details().title()));
888   } else {
889     path = path.Append(FILE_PATH_LITERAL("<unknown>"));
890   }
891   return path;
892 }
893
894 bool MetadataDatabase::FindNearestActiveAncestor(
895     const std::string& app_id,
896     const base::FilePath& full_path,
897     FileTracker* tracker_out,
898     base::FilePath* path_out) const {
899   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
900   DCHECK(tracker_out);
901   DCHECK(path_out);
902
903   if (full_path.IsAbsolute() ||
904       !FindAppRootTracker(app_id, tracker_out) ||
905       tracker_out->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT) {
906     return false;
907   }
908
909   std::vector<base::FilePath::StringType> components;
910   full_path.GetComponents(&components);
911   path_out->clear();
912
913   for (size_t i = 0; i < components.size(); ++i) {
914     const std::string title = base::FilePath(components[i]).AsUTF8Unsafe();
915     TrackerIDSet trackers;
916     if (!FindTrackersByParentAndTitle(
917             tracker_out->tracker_id(), title, &trackers) ||
918         !trackers.has_active()) {
919       return true;
920     }
921
922     FileTracker tracker;
923     index_->GetFileTracker(trackers.active_tracker(), &tracker);
924
925     DCHECK(tracker.has_synced_details());
926     const FileDetails& details = tracker.synced_details();
927     if (details.file_kind() != FILE_KIND_FOLDER && i != components.size() - 1) {
928       // This non-last component indicates file. Give up search.
929       return true;
930     }
931
932     tracker_out->CopyFrom(tracker);
933     *path_out = path_out->Append(components[i]);
934   }
935
936   return true;
937 }
938
939 void MetadataDatabase::UpdateByChangeList(
940     int64 largest_change_id,
941     ScopedVector<google_apis::ChangeResource> changes,
942     const SyncStatusCallback& callback) {
943   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
944   DCHECK_LE(index_->GetLargestChangeID(), largest_change_id);
945
946   for (size_t i = 0; i < changes.size(); ++i) {
947     const google_apis::ChangeResource& change = *changes[i];
948     if (HasNewerFileMetadata(change.file_id(), change.change_id()))
949       continue;
950
951     scoped_ptr<FileMetadata> metadata(
952         CreateFileMetadataFromChangeResource(change));
953     UpdateByFileMetadata(FROM_HERE, metadata.Pass(),
954                          UPDATE_TRACKER_FOR_UNSYNCED_FILE);
955   }
956
957   UpdateLargestKnownChangeID(largest_change_id);
958   index_->SetLargestChangeID(largest_change_id);
959   WriteToDatabase(callback);
960 }
961
962 void MetadataDatabase::UpdateByFileResource(
963     const google_apis::FileResource& resource,
964     const SyncStatusCallback& callback) {
965   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
966
967   scoped_ptr<FileMetadata> metadata(
968       CreateFileMetadataFromFileResource(
969           GetLargestKnownChangeID(), resource));
970   UpdateByFileMetadata(FROM_HERE, metadata.Pass(),
971                        UPDATE_TRACKER_FOR_UNSYNCED_FILE);
972   WriteToDatabase(callback);
973 }
974
975 void MetadataDatabase::UpdateByFileResourceList(
976     ScopedVector<google_apis::FileResource> resources,
977     const SyncStatusCallback& callback) {
978   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
979
980   for (size_t i = 0; i < resources.size(); ++i) {
981     scoped_ptr<FileMetadata> metadata(
982         CreateFileMetadataFromFileResource(
983             GetLargestKnownChangeID(), *resources[i]));
984     UpdateByFileMetadata(FROM_HERE, metadata.Pass(),
985                          UPDATE_TRACKER_FOR_UNSYNCED_FILE);
986   }
987   WriteToDatabase(callback);
988 }
989
990 void MetadataDatabase::UpdateByDeletedRemoteFile(
991     const std::string& file_id,
992     const SyncStatusCallback& callback) {
993   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
994
995   scoped_ptr<FileMetadata> metadata(
996       CreateDeletedFileMetadata(GetLargestKnownChangeID(), file_id));
997   UpdateByFileMetadata(FROM_HERE, metadata.Pass(),
998                        UPDATE_TRACKER_FOR_UNSYNCED_FILE);
999   WriteToDatabase(callback);
1000 }
1001
1002 void MetadataDatabase::UpdateByDeletedRemoteFileList(
1003     const FileIDList& file_ids,
1004     const SyncStatusCallback& callback) {
1005   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1006
1007   for (FileIDList::const_iterator itr = file_ids.begin();
1008        itr != file_ids.end(); ++itr) {
1009     scoped_ptr<FileMetadata> metadata(
1010         CreateDeletedFileMetadata(GetLargestKnownChangeID(), *itr));
1011     UpdateByFileMetadata(FROM_HERE, metadata.Pass(),
1012                          UPDATE_TRACKER_FOR_UNSYNCED_FILE);
1013   }
1014   WriteToDatabase(callback);
1015 }
1016
1017 void MetadataDatabase::ReplaceActiveTrackerWithNewResource(
1018     int64 parent_tracker_id,
1019     const google_apis::FileResource& resource,
1020     const SyncStatusCallback& callback) {
1021   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1022
1023   DCHECK(!index_->GetFileMetadata(resource.file_id(), NULL));
1024   DCHECK(index_->GetFileTracker(parent_tracker_id, NULL));
1025
1026   UpdateByFileMetadata(
1027       FROM_HERE,
1028       CreateFileMetadataFromFileResource(GetLargestKnownChangeID(), resource),
1029       UPDATE_TRACKER_FOR_SYNCED_FILE);
1030
1031   DCHECK(index_->GetFileMetadata(resource.file_id(), NULL));
1032   DCHECK(!index_->GetFileTrackerIDsByFileID(resource.file_id()).has_active());
1033
1034   TrackerIDSet same_path_trackers =
1035       index_->GetFileTrackerIDsByParentAndTitle(
1036           parent_tracker_id, resource.title());
1037   FileTracker to_be_activated;
1038   if (!FilterFileTrackersByFileID(index_.get(), same_path_trackers,
1039                                   resource.file_id(), &to_be_activated)) {
1040     NOTREACHED();
1041     worker_task_runner_->PostTask(
1042         FROM_HERE,
1043         base::Bind(callback, SYNC_STATUS_FAILED));
1044     return;
1045   }
1046
1047   int64 tracker_id = to_be_activated.tracker_id();
1048   if (same_path_trackers.has_active()) {
1049     DeactivateFileTracker(same_path_trackers.active_tracker(),
1050                           MARK_ITSELF_DIRTY |
1051                           MARK_SAME_FILE_ID_TRACKERS_DIRTY,
1052                           index_.get());
1053   }
1054
1055   ActivateFileTracker(tracker_id, MARK_NOTHING_DIRTY, index_.get());
1056   WriteToDatabase(callback);
1057 }
1058
1059 void MetadataDatabase::PopulateFolderByChildList(
1060     const std::string& folder_id,
1061     const FileIDList& child_file_ids,
1062     const SyncStatusCallback& callback) {
1063   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1064
1065   TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(folder_id);
1066   if (!trackers.has_active()) {
1067     // It's OK that there is no folder to populate its children.
1068     // Inactive folders should ignore their contents updates.
1069     worker_task_runner_->PostTask(
1070         FROM_HERE,
1071         base::Bind(callback, SYNC_STATUS_OK));
1072     return;
1073   }
1074
1075   scoped_ptr<FileTracker> folder_tracker(new FileTracker);
1076   if (!index_->GetFileTracker(trackers.active_tracker(),
1077                               folder_tracker.get())) {
1078     NOTREACHED();
1079     worker_task_runner_->PostTask(
1080         FROM_HERE,
1081         base::Bind(callback, SYNC_STATUS_FAILED));
1082     return;
1083   }
1084
1085   base::hash_set<std::string> children(child_file_ids.begin(),
1086                                        child_file_ids.end());
1087
1088   std::vector<int64> known_children =
1089       index_->GetFileTrackerIDsByParent(folder_tracker->tracker_id());
1090   for (size_t i = 0; i < known_children.size(); ++i) {
1091     FileTracker tracker;
1092     if (!index_->GetFileTracker(known_children[i], &tracker)) {
1093       NOTREACHED();
1094       continue;
1095     }
1096     children.erase(tracker.file_id());
1097   }
1098
1099   for (base::hash_set<std::string>::const_iterator itr = children.begin();
1100        itr != children.end(); ++itr)
1101     CreateTrackerForParentAndFileID(*folder_tracker, *itr);
1102   folder_tracker->set_needs_folder_listing(false);
1103   if (folder_tracker->dirty() && !ShouldKeepDirty(*folder_tracker))
1104     folder_tracker->set_dirty(false);
1105   index_->StoreFileTracker(folder_tracker.Pass());
1106
1107   WriteToDatabase(callback);
1108 }
1109
1110 void MetadataDatabase::UpdateTracker(int64 tracker_id,
1111                                      const FileDetails& updated_details,
1112                                      const SyncStatusCallback& callback) {
1113   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1114
1115   FileTracker tracker;
1116   if (!index_->GetFileTracker(tracker_id, &tracker)) {
1117     worker_task_runner_->PostTask(
1118         FROM_HERE,
1119         base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
1120     return;
1121   }
1122
1123   // Check if the tracker is to be deleted.
1124   if (updated_details.missing()) {
1125     FileMetadata metadata;
1126     if (!index_->GetFileMetadata(tracker.file_id(), &metadata) ||
1127         metadata.details().missing()) {
1128       // Both the tracker and metadata have the missing flag, now it's safe to
1129       // delete the |tracker|.
1130       RemoveFileTracker(tracker_id,
1131                         MARK_SAME_FILE_ID_TRACKERS_DIRTY |
1132                         MARK_SAME_PATH_TRACKERS_DIRTY,
1133                         index_.get());
1134       WriteToDatabase(callback);
1135       return;
1136     }
1137   }
1138
1139   // Sync-root deletion should be handled separately by SyncEngine.
1140   DCHECK(tracker_id != GetSyncRootTrackerID() ||
1141          (tracker.has_synced_details() &&
1142           tracker.synced_details().title() == updated_details.title() &&
1143           !updated_details.missing()));
1144
1145   if (tracker_id != GetSyncRootTrackerID()) {
1146     // Check if the tracker's parent is still in |parent_tracker_ids|.
1147     // If not, there should exist another tracker for the new parent, so delete
1148     // old tracker.
1149     FileTracker parent_tracker;
1150     index_->GetFileTracker(tracker.parent_tracker_id(), &parent_tracker);
1151
1152     if (!HasFileAsParent(updated_details, parent_tracker.file_id())) {
1153       RemoveFileTracker(tracker.tracker_id(),
1154                         MARK_SAME_PATH_TRACKERS_DIRTY,
1155                         index_.get());
1156       WriteToDatabase(callback);
1157       return;
1158     }
1159
1160     if (tracker.has_synced_details()) {
1161       // Check if the tracker was retitled.  If it was, there should exist
1162       // another tracker for the new title, so delete the tracker being updated.
1163       if (tracker.synced_details().title() != updated_details.title()) {
1164         RemoveFileTracker(tracker.tracker_id(),
1165                           MARK_SAME_FILE_ID_TRACKERS_DIRTY,
1166                           index_.get());
1167         WriteToDatabase(callback);
1168         return;
1169       }
1170     } else {
1171       // Check if any other tracker exists has the same parent, title and
1172       // file_id to the updated tracker.  If it exists, delete the tracker being
1173       // updated.
1174       if (FilterFileTrackersByFileID(
1175               index_.get(),
1176               index_->GetFileTrackerIDsByParentAndTitle(
1177                   parent_tracker.tracker_id(),
1178                   updated_details.title()),
1179               tracker.file_id(),
1180               NULL)) {
1181         RemoveFileTracker(tracker.tracker_id(),
1182                           MARK_NOTHING_DIRTY,
1183                           index_.get());
1184         WriteToDatabase(callback);
1185         return;
1186       }
1187     }
1188   }
1189
1190   scoped_ptr<FileTracker> updated_tracker = CloneFileTracker(&tracker);
1191   *updated_tracker->mutable_synced_details() = updated_details;
1192
1193   bool should_promote = false;
1194
1195   // Activate the tracker if:
1196   //   - There is no active tracker that tracks |tracker->file_id()|.
1197   //   - There is no active tracker that has the same |parent| and |title|.
1198   if (!tracker.active() && CanActivateTracker(tracker)) {
1199     updated_tracker->set_active(true);
1200     updated_tracker->set_dirty(true);
1201     updated_tracker->set_needs_folder_listing(
1202         tracker.synced_details().file_kind() == FILE_KIND_FOLDER);
1203     should_promote = true;
1204   } else if (tracker.dirty() && !ShouldKeepDirty(tracker)) {
1205     updated_tracker->set_dirty(false);
1206   }
1207   index_->StoreFileTracker(updated_tracker.Pass());
1208   if (should_promote)
1209     index_->PromoteDemotedDirtyTracker(tracker_id);
1210
1211   WriteToDatabase(callback);
1212 }
1213
1214 MetadataDatabase::ActivationStatus MetadataDatabase::TryActivateTracker(
1215     int64 parent_tracker_id,
1216     const std::string& file_id,
1217     const SyncStatusCallback& callback) {
1218   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1219
1220   FileMetadata metadata;
1221   if (!index_->GetFileMetadata(file_id, &metadata)) {
1222     NOTREACHED();
1223     worker_task_runner_->PostTask(
1224         FROM_HERE,
1225         base::Bind(callback, SYNC_STATUS_FAILED));
1226     return ACTIVATION_PENDING;
1227   }
1228   std::string title = metadata.details().title();
1229   DCHECK(!HasInvalidTitle(title));
1230
1231   TrackerIDSet same_file_id_trackers =
1232       index_->GetFileTrackerIDsByFileID(file_id);
1233   scoped_ptr<FileTracker> tracker_to_be_activated(new FileTracker);
1234   FilterFileTrackersByParentAndTitle(
1235       index_.get(), same_file_id_trackers, parent_tracker_id,
1236       title, tracker_to_be_activated.get());
1237
1238   // Check if there is another active tracker that tracks |file_id|.
1239   // This can happen when the tracked file has multiple parents.
1240   // In this case, report the failure to the caller.
1241   if (!tracker_to_be_activated->active() && same_file_id_trackers.has_active())
1242     return ACTIVATION_FAILED_ANOTHER_ACTIVE_TRACKER;
1243
1244   if (!tracker_to_be_activated->active()) {
1245     // Check if there exists another active tracker that has the same path to
1246     // the tracker.  If there is, deactivate it, assuming the caller already
1247     // overrides local file with newly added file,
1248     TrackerIDSet same_title_trackers =
1249         index_->GetFileTrackerIDsByParentAndTitle(parent_tracker_id, title);
1250     if (same_title_trackers.has_active()) {
1251       RemoveAllDescendantTrackers(same_title_trackers.active_tracker(),
1252                                   index_.get());
1253
1254       scoped_ptr<FileTracker> tracker_to_be_deactivated(new FileTracker);
1255       if (index_->GetFileTracker(same_title_trackers.active_tracker(),
1256                                  tracker_to_be_deactivated.get())) {
1257         const std::string file_id = tracker_to_be_deactivated->file_id();
1258         tracker_to_be_deactivated->set_active(false);
1259         index_->StoreFileTracker(tracker_to_be_deactivated.Pass());
1260
1261         MarkTrackersDirtyByFileID(file_id, index_.get());
1262       } else {
1263         NOTREACHED();
1264       }
1265     }
1266   }
1267
1268   tracker_to_be_activated->set_dirty(false);
1269   tracker_to_be_activated->set_active(true);
1270   *tracker_to_be_activated->mutable_synced_details() = metadata.details();
1271   if (tracker_to_be_activated->synced_details().file_kind() ==
1272       FILE_KIND_FOLDER) {
1273     tracker_to_be_activated->set_needs_folder_listing(true);
1274   }
1275   tracker_to_be_activated->set_dirty(false);
1276
1277   index_->StoreFileTracker(tracker_to_be_activated.Pass());
1278
1279   WriteToDatabase(callback);
1280   return ACTIVATION_PENDING;
1281 }
1282
1283 void MetadataDatabase::LowerTrackerPriority(int64 tracker_id) {
1284   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1285   index_->DemoteDirtyTracker(tracker_id);
1286   WriteToDatabase(base::Bind(&EmptyStatusCallback));
1287 }
1288
1289 bool MetadataDatabase::PromoteLowerPriorityTrackersToNormal() {
1290   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1291   bool promoted = index_->PromoteDemotedDirtyTrackers();
1292   WriteToDatabase(base::Bind(&EmptyStatusCallback));
1293   return promoted;
1294 }
1295
1296 void MetadataDatabase::PromoteDemotedTracker(int64 tracker_id) {
1297   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1298   index_->PromoteDemotedDirtyTracker(tracker_id);
1299   WriteToDatabase(base::Bind(&EmptyStatusCallback));
1300 }
1301
1302 bool MetadataDatabase::GetNormalPriorityDirtyTracker(
1303     FileTracker* tracker_out) const {
1304   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1305
1306   int64 dirty_tracker_id = index_->PickDirtyTracker();
1307   if (!dirty_tracker_id)
1308     return false;
1309
1310   if (tracker_out) {
1311     if (!index_->GetFileTracker(dirty_tracker_id, tracker_out)) {
1312       NOTREACHED();
1313       return false;
1314     }
1315   }
1316   return true;
1317 }
1318
1319 bool MetadataDatabase::HasLowPriorityDirtyTracker() const {
1320   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1321   return index_->HasDemotedDirtyTracker();
1322 }
1323
1324 bool MetadataDatabase::HasDirtyTracker() const {
1325   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1326   return index_->PickDirtyTracker() != kInvalidTrackerID;
1327 }
1328
1329 size_t MetadataDatabase::CountDirtyTracker() const {
1330   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1331   return index_->CountDirtyTracker();
1332 }
1333
1334 bool MetadataDatabase::GetMultiParentFileTrackers(std::string* file_id_out,
1335                                                   TrackerIDSet* trackers_out) {
1336   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1337   DCHECK(file_id_out);
1338   DCHECK(trackers_out);
1339
1340   std::string file_id = index_->PickMultiTrackerFileID();
1341   if (file_id.empty())
1342     return false;
1343
1344   TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(file_id);
1345   if (trackers.size() <= 1) {
1346     NOTREACHED();
1347     return false;
1348   }
1349
1350   *file_id_out = file_id;
1351   std::swap(*trackers_out, trackers);
1352   return true;
1353 }
1354
1355 size_t MetadataDatabase::CountFileMetadata() const {
1356   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1357   return index_->CountFileMetadata();
1358 }
1359
1360 size_t MetadataDatabase::CountFileTracker() const {
1361   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1362   return index_->CountFileTracker();
1363 }
1364
1365 bool MetadataDatabase::GetConflictingTrackers(TrackerIDSet* trackers_out) {
1366   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1367   DCHECK(trackers_out);
1368
1369   ParentIDAndTitle parent_and_title = index_->PickMultiBackingFilePath();
1370   if (parent_and_title.parent_id == kInvalidTrackerID)
1371     return false;
1372
1373   TrackerIDSet trackers = index_->GetFileTrackerIDsByParentAndTitle(
1374       parent_and_title.parent_id, parent_and_title.title);
1375   if (trackers.size() <= 1) {
1376     NOTREACHED();
1377     return false;
1378   }
1379
1380   std::swap(*trackers_out, trackers);
1381   return true;
1382 }
1383
1384 void MetadataDatabase::GetRegisteredAppIDs(std::vector<std::string>* app_ids) {
1385   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1386   DCHECK(app_ids);
1387   *app_ids = index_->GetRegisteredAppIDs();
1388 }
1389
1390 void MetadataDatabase::SweepDirtyTrackers(
1391     const std::vector<std::string>& file_ids,
1392     const SyncStatusCallback& callback) {
1393   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1394
1395   std::set<int64> tracker_ids;
1396   for (size_t i = 0; i < file_ids.size(); ++i) {
1397     TrackerIDSet trackers_for_file_id =
1398         index_->GetFileTrackerIDsByFileID(file_ids[i]);
1399     for (TrackerIDSet::iterator itr = trackers_for_file_id.begin();
1400          itr != trackers_for_file_id.end(); ++itr)
1401       tracker_ids.insert(*itr);
1402   }
1403
1404   for (std::set<int64>::iterator itr = tracker_ids.begin();
1405        itr != tracker_ids.end(); ++itr) {
1406     scoped_ptr<FileTracker> tracker(new FileTracker);
1407     if (!index_->GetFileTracker(*itr, tracker.get()) ||
1408         !CanClearDirty(*tracker))
1409       continue;
1410     tracker->set_dirty(false);
1411     index_->StoreFileTracker(tracker.Pass());
1412   }
1413
1414   WriteToDatabase(callback);
1415 }
1416
1417 MetadataDatabase::MetadataDatabase(
1418     base::SequencedTaskRunner* worker_task_runner,
1419     const base::FilePath& database_path,
1420     leveldb::Env* env_override)
1421     : worker_task_runner_(worker_task_runner),
1422       database_path_(database_path),
1423       env_override_(env_override),
1424       largest_known_change_id_(0),
1425       weak_ptr_factory_(this) {
1426   DCHECK(worker_task_runner);
1427 }
1428
1429 // static
1430 void MetadataDatabase::CreateOnWorkerTaskRunner(
1431     scoped_ptr<CreateParam> create_param,
1432     const CreateCallback& callback) {
1433   DCHECK(create_param->worker_task_runner->RunsTasksOnCurrentThread());
1434
1435   scoped_ptr<MetadataDatabase> metadata_database(
1436       new MetadataDatabase(create_param->worker_task_runner.get(),
1437                            create_param->database_path,
1438                            create_param->env_override));
1439   SyncStatusCode status = metadata_database->Initialize();
1440   if (status != SYNC_STATUS_OK)
1441     metadata_database.reset();
1442
1443   metadata_database->DetachFromSequence();
1444   create_param->worker_task_runner->PostTask(
1445       FROM_HERE,
1446       base::Bind(
1447           callback, status, base::Passed(&metadata_database)));
1448 }
1449
1450 SyncStatusCode MetadataDatabase::Initialize() {
1451   base::ThreadRestrictions::AssertIOAllowed();
1452   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1453
1454   SyncStatusCode status = SYNC_STATUS_UNKNOWN;
1455   bool created = false;
1456   // Open database unless |db_| is overridden for testing.
1457   if (!db_) {
1458     status = OpenDatabase(database_path_, env_override_, &db_, &created);
1459     if (status != SYNC_STATUS_OK)
1460       return status;
1461   }
1462
1463   if (!created) {
1464     status = MigrateDatabaseIfNeeded(db_.get());
1465     if (status != SYNC_STATUS_OK)
1466       return status;
1467   }
1468
1469   if (CommandLine::ForCurrentProcess()->HasSwitch(
1470           kEnableMetadataDatabaseOnDisk)) {
1471     index_ = MetadataDatabaseIndexOnDisk::Create(db_.get());
1472   } else {
1473     index_ = MetadataDatabaseIndex::Create(db_.get());
1474   }
1475
1476   status = LevelDBStatusToSyncStatusCode(db_->Commit());
1477   if (status != SYNC_STATUS_OK)
1478     return status;
1479
1480   UpdateLargestKnownChangeID(index_->GetLargestChangeID());
1481
1482   return status;
1483 }
1484
1485 void MetadataDatabase::CreateTrackerForParentAndFileID(
1486     const FileTracker& parent_tracker,
1487     const std::string& file_id) {
1488   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1489   CreateTrackerInternal(parent_tracker, file_id, NULL,
1490                         UPDATE_TRACKER_FOR_UNSYNCED_FILE);
1491 }
1492
1493 void MetadataDatabase::CreateTrackerForParentAndFileMetadata(
1494     const FileTracker& parent_tracker,
1495     const FileMetadata& file_metadata,
1496     UpdateOption option) {
1497   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1498   DCHECK(file_metadata.has_details());
1499   CreateTrackerInternal(parent_tracker,
1500                         file_metadata.file_id(),
1501                         &file_metadata.details(),
1502                         option);
1503 }
1504
1505 void MetadataDatabase::CreateTrackerInternal(const FileTracker& parent_tracker,
1506                                              const std::string& file_id,
1507                                              const FileDetails* details,
1508                                              UpdateOption option) {
1509   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1510
1511   int64 tracker_id = IncrementTrackerID();
1512   scoped_ptr<FileTracker> tracker(new FileTracker);
1513   tracker->set_tracker_id(tracker_id);
1514   tracker->set_parent_tracker_id(parent_tracker.tracker_id());
1515   tracker->set_file_id(file_id);
1516   tracker->set_app_id(parent_tracker.app_id());
1517   tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
1518   tracker->set_dirty(true);
1519   tracker->set_active(false);
1520   tracker->set_needs_folder_listing(false);
1521   if (details) {
1522     *tracker->mutable_synced_details() = *details;
1523     if (option == UPDATE_TRACKER_FOR_UNSYNCED_FILE) {
1524       tracker->mutable_synced_details()->set_missing(true);
1525       tracker->mutable_synced_details()->clear_md5();
1526     }
1527   }
1528   index_->StoreFileTracker(tracker.Pass());
1529 }
1530
1531 void MetadataDatabase::MaybeAddTrackersForNewFile(
1532     const FileMetadata& metadata,
1533     UpdateOption option) {
1534   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1535
1536   std::set<int64> parents_to_exclude;
1537   TrackerIDSet existing_trackers =
1538       index_->GetFileTrackerIDsByFileID(metadata.file_id());
1539   for (TrackerIDSet::const_iterator itr = existing_trackers.begin();
1540        itr != existing_trackers.end(); ++itr) {
1541     FileTracker tracker;
1542     if (!index_->GetFileTracker(*itr, &tracker)) {
1543       NOTREACHED();
1544       continue;
1545     }
1546
1547     int64 parent_tracker_id = tracker.parent_tracker_id();
1548     if (!parent_tracker_id)
1549       continue;
1550
1551     // Exclude |parent_tracker_id| if it already has a tracker that has
1552     // unknown title or has the same title with |file|.
1553     if (!tracker.has_synced_details() ||
1554         tracker.synced_details().title() == metadata.details().title()) {
1555       parents_to_exclude.insert(parent_tracker_id);
1556     }
1557   }
1558
1559   for (int i = 0; i < metadata.details().parent_folder_ids_size(); ++i) {
1560     std::string parent_folder_id = metadata.details().parent_folder_ids(i);
1561     TrackerIDSet parent_trackers =
1562         index_->GetFileTrackerIDsByFileID(parent_folder_id);
1563     for (TrackerIDSet::const_iterator itr = parent_trackers.begin();
1564          itr != parent_trackers.end(); ++itr) {
1565       FileTracker parent_tracker;
1566       index_->GetFileTracker(*itr, &parent_tracker);
1567       if (!parent_tracker.active())
1568         continue;
1569
1570       if (ContainsKey(parents_to_exclude, parent_tracker.tracker_id()))
1571         continue;
1572
1573       CreateTrackerForParentAndFileMetadata(
1574           parent_tracker, metadata, option);
1575     }
1576   }
1577 }
1578
1579 int64 MetadataDatabase::IncrementTrackerID() {
1580   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1581
1582   int64 tracker_id = index_->GetNextTrackerID();
1583   index_->SetNextTrackerID(tracker_id + 1);
1584   DCHECK_GT(tracker_id, 0);
1585   return tracker_id;
1586 }
1587
1588 bool MetadataDatabase::CanActivateTracker(const FileTracker& tracker) {
1589   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1590   DCHECK(!tracker.active());
1591   DCHECK_NE(index_->GetSyncRootTrackerID(), tracker.tracker_id());
1592
1593   if (HasActiveTrackerForFileID(tracker.file_id()))
1594     return false;
1595
1596   if (tracker.app_id().empty() &&
1597       tracker.tracker_id() != GetSyncRootTrackerID()) {
1598     return false;
1599   }
1600
1601   if (!tracker.has_synced_details())
1602     return false;
1603   if (tracker.synced_details().file_kind() == FILE_KIND_UNSUPPORTED)
1604     return false;
1605   if (HasInvalidTitle(tracker.synced_details().title()))
1606     return false;
1607   DCHECK(tracker.parent_tracker_id());
1608
1609   return !HasActiveTrackerForPath(tracker.parent_tracker_id(),
1610                                   tracker.synced_details().title());
1611 }
1612
1613 bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const {
1614   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1615
1616   if (HasDisabledAppRoot(tracker))
1617     return false;
1618
1619   DCHECK(tracker.dirty());
1620   if (!tracker.has_synced_details())
1621     return true;
1622
1623   FileMetadata metadata;
1624   if (!index_->GetFileMetadata(tracker.file_id(), &metadata))
1625     return true;
1626   DCHECK(metadata.has_details());
1627
1628   const FileDetails& local_details = tracker.synced_details();
1629   const FileDetails& remote_details = metadata.details();
1630
1631   if (tracker.active()) {
1632     if (tracker.needs_folder_listing())
1633       return true;
1634     if (local_details.md5() != remote_details.md5())
1635       return true;
1636     if (local_details.missing() != remote_details.missing())
1637       return true;
1638   }
1639
1640   if (local_details.title() != remote_details.title())
1641     return true;
1642
1643   return false;
1644 }
1645
1646 bool MetadataDatabase::HasDisabledAppRoot(const FileTracker& tracker) const {
1647   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1648
1649   int64 app_root_tracker_id = index_->GetAppRootTracker(tracker.app_id());
1650   if (app_root_tracker_id == kInvalidTrackerID)
1651     return false;
1652
1653   FileTracker app_root_tracker;
1654   if (!index_->GetFileTracker(app_root_tracker_id, &app_root_tracker)) {
1655     NOTREACHED();
1656     return false;
1657   }
1658   return app_root_tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT;
1659 }
1660
1661 bool MetadataDatabase::HasActiveTrackerForFileID(
1662     const std::string& file_id) const {
1663   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1664   return index_->GetFileTrackerIDsByFileID(file_id).has_active();
1665 }
1666
1667 bool MetadataDatabase::HasActiveTrackerForPath(int64 parent_tracker_id,
1668                                                const std::string& title) const {
1669   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1670   return index_->GetFileTrackerIDsByParentAndTitle(parent_tracker_id, title)
1671       .has_active();
1672 }
1673
1674 void MetadataDatabase::RemoveUnneededTrackersForMissingFile(
1675     const std::string& file_id) {
1676   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1677
1678   TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(file_id);
1679   for (TrackerIDSet::const_iterator itr = trackers.begin();
1680        itr != trackers.end(); ++itr) {
1681     FileTracker tracker;
1682     if (!index_->GetFileTracker(*itr, &tracker)) {
1683       NOTREACHED();
1684       continue;
1685     }
1686
1687     if (!tracker.has_synced_details() || tracker.synced_details().missing()) {
1688       RemoveFileTracker(*itr, MARK_NOTHING_DIRTY, index_.get());
1689     }
1690   }
1691 }
1692
1693 void MetadataDatabase::UpdateByFileMetadata(
1694     const tracked_objects::Location& from_where,
1695     scoped_ptr<FileMetadata> metadata,
1696     UpdateOption option) {
1697   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1698   DCHECK(metadata);
1699   DCHECK(metadata->has_details());
1700
1701   DVLOG(1) << from_where.function_name() << ": "
1702            << metadata->file_id() << " ("
1703            << metadata->details().title() << ")"
1704            << (metadata->details().missing() ? " deleted" : "");
1705
1706   std::string file_id = metadata->file_id();
1707   if (metadata->details().missing())
1708     RemoveUnneededTrackersForMissingFile(file_id);
1709   else
1710     MaybeAddTrackersForNewFile(*metadata, option);
1711
1712   TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(file_id);
1713   if (!trackers.empty()) {
1714     index_->StoreFileMetadata(metadata.Pass());
1715
1716     if (option != UPDATE_TRACKER_FOR_SYNCED_FILE)
1717       MarkTrackerSetDirty(trackers, index_.get());
1718   }
1719 }
1720
1721 void MetadataDatabase::WriteToDatabase(const SyncStatusCallback& callback) {
1722   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1723
1724   leveldb::Status status = db_->Commit();
1725   callback.Run(LevelDBStatusToSyncStatusCode(status));
1726 }
1727
1728 scoped_ptr<base::ListValue> MetadataDatabase::DumpFiles(
1729     const std::string& app_id) {
1730   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1731
1732   scoped_ptr<base::ListValue> files(new base::ListValue);
1733
1734   FileTracker app_root_tracker;
1735   if (!FindAppRootTracker(app_id, &app_root_tracker))
1736     return files.Pass();
1737
1738   std::vector<int64> stack;
1739   AppendContents(
1740       index_->GetFileTrackerIDsByParent(app_root_tracker.tracker_id()), &stack);
1741   while (!stack.empty()) {
1742     int64 tracker_id = stack.back();
1743     stack.pop_back();
1744     AppendContents(index_->GetFileTrackerIDsByParent(tracker_id), &stack);
1745
1746     FileTracker tracker;
1747     if (!index_->GetFileTracker(tracker_id, &tracker)) {
1748       NOTREACHED();
1749       continue;
1750     }
1751     base::DictionaryValue* file = new base::DictionaryValue;
1752
1753     base::FilePath path = BuildDisplayPathForTracker(tracker);
1754     file->SetString("path", path.AsUTF8Unsafe());
1755     if (tracker.has_synced_details()) {
1756       file->SetString("title", tracker.synced_details().title());
1757       file->SetString("type",
1758                       FileKindToString(tracker.synced_details().file_kind()));
1759     }
1760
1761     base::DictionaryValue* details = new base::DictionaryValue;
1762     details->SetString("file_id", tracker.file_id());
1763     if (tracker.has_synced_details() &&
1764         tracker.synced_details().file_kind() == FILE_KIND_FILE)
1765       details->SetString("md5", tracker.synced_details().md5());
1766     details->SetString("active", tracker.active() ? "true" : "false");
1767     details->SetString("dirty", tracker.dirty() ? "true" : "false");
1768
1769     file->Set("details", details);
1770
1771     files->Append(file);
1772   }
1773
1774   return files.Pass();
1775 }
1776
1777 scoped_ptr<base::ListValue> MetadataDatabase::DumpDatabase() {
1778   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1779
1780   scoped_ptr<base::ListValue> list(new base::ListValue);
1781   list->Append(DumpTrackers().release());
1782   list->Append(DumpMetadata().release());
1783   return list.Pass();
1784 }
1785
1786 bool MetadataDatabase::HasNewerFileMetadata(const std::string& file_id,
1787                                             int64 change_id) {
1788   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1789
1790   FileMetadata metadata;
1791   if (!index_->GetFileMetadata(file_id, &metadata))
1792     return false;
1793   DCHECK(metadata.has_details());
1794   return metadata.details().change_id() >= change_id;
1795 }
1796
1797 scoped_ptr<base::ListValue> MetadataDatabase::DumpTrackers() {
1798   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1799
1800   scoped_ptr<base::ListValue> trackers(new base::ListValue);
1801
1802   // Append the first element for metadata.
1803   base::DictionaryValue* metadata = new base::DictionaryValue;
1804   const char *trackerKeys[] = {
1805     "tracker_id", "path", "file_id", "tracker_kind", "app_id",
1806     "active", "dirty", "folder_listing",
1807     "title", "kind", "md5", "etag", "missing", "change_id",
1808   };
1809   std::vector<std::string> key_strings(
1810       trackerKeys, trackerKeys + ARRAYSIZE_UNSAFE(trackerKeys));
1811   base::ListValue* keys = new base::ListValue;
1812   keys->AppendStrings(key_strings);
1813   metadata->SetString("title", "Trackers");
1814   metadata->Set("keys", keys);
1815   trackers->Append(metadata);
1816
1817   // Append tracker data.
1818   std::vector<int64> tracker_ids(index_->GetAllTrackerIDs());
1819   for (std::vector<int64>::const_iterator itr = tracker_ids.begin();
1820        itr != tracker_ids.end(); ++itr) {
1821     const int64 tracker_id = *itr;
1822     FileTracker tracker;
1823     if (!index_->GetFileTracker(tracker_id, &tracker)) {
1824       NOTREACHED();
1825       continue;
1826     }
1827
1828     base::DictionaryValue* dict = new base::DictionaryValue;
1829     base::FilePath path = BuildDisplayPathForTracker(tracker);
1830     dict->SetString("tracker_id", base::Int64ToString(tracker_id));
1831     dict->SetString("path", path.AsUTF8Unsafe());
1832     dict->SetString("file_id", tracker.file_id());
1833     TrackerKind tracker_kind = tracker.tracker_kind();
1834     dict->SetString(
1835         "tracker_kind",
1836         tracker_kind == TRACKER_KIND_APP_ROOT ? "AppRoot" :
1837         tracker_kind == TRACKER_KIND_DISABLED_APP_ROOT ? "Disabled App" :
1838         tracker.tracker_id() == GetSyncRootTrackerID() ? "SyncRoot" :
1839         "Regular");
1840     dict->SetString("app_id", tracker.app_id());
1841     dict->SetString("active", tracker.active() ? "true" : "false");
1842     dict->SetString("dirty", tracker.dirty() ? "true" : "false");
1843     dict->SetString("folder_listing",
1844                     tracker.needs_folder_listing() ? "needed" : "no");
1845     if (tracker.has_synced_details()) {
1846       const FileDetails& details = tracker.synced_details();
1847       dict->SetString("title", details.title());
1848       dict->SetString("kind", FileKindToString(details.file_kind()));
1849       dict->SetString("md5", details.md5());
1850       dict->SetString("etag", details.etag());
1851       dict->SetString("missing", details.missing() ? "true" : "false");
1852       dict->SetString("change_id", base::Int64ToString(details.change_id()));
1853     }
1854     trackers->Append(dict);
1855   }
1856   return trackers.Pass();
1857 }
1858
1859 scoped_ptr<base::ListValue> MetadataDatabase::DumpMetadata() {
1860   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1861
1862   scoped_ptr<base::ListValue> files(new base::ListValue);
1863
1864   // Append the first element for metadata.
1865   base::DictionaryValue* metadata = new base::DictionaryValue;
1866   const char *fileKeys[] = {
1867     "file_id", "title", "type", "md5", "etag", "missing",
1868     "change_id", "parents"
1869   };
1870   std::vector<std::string> key_strings(
1871       fileKeys, fileKeys + ARRAYSIZE_UNSAFE(fileKeys));
1872   base::ListValue* keys = new base::ListValue;
1873   keys->AppendStrings(key_strings);
1874   metadata->SetString("title", "Metadata");
1875   metadata->Set("keys", keys);
1876   files->Append(metadata);
1877
1878   // Append metadata data.
1879   std::vector<std::string> metadata_ids(index_->GetAllMetadataIDs());
1880   for (std::vector<std::string>::const_iterator itr = metadata_ids.begin();
1881        itr != metadata_ids.end(); ++itr) {
1882     const std::string& file_id = *itr;
1883     FileMetadata file;
1884     if (!index_->GetFileMetadata(file_id, &file)) {
1885       NOTREACHED();
1886       continue;
1887     }
1888
1889     base::DictionaryValue* dict = new base::DictionaryValue;
1890     dict->SetString("file_id", file_id);
1891     if (file.has_details()) {
1892       const FileDetails& details = file.details();
1893       dict->SetString("title", details.title());
1894       dict->SetString("type", FileKindToString(details.file_kind()));
1895       dict->SetString("md5", details.md5());
1896       dict->SetString("etag", details.etag());
1897       dict->SetString("missing", details.missing() ? "true" : "false");
1898       dict->SetString("change_id", base::Int64ToString(details.change_id()));
1899
1900       std::vector<std::string> parents;
1901       for (int i = 0; i < details.parent_folder_ids_size(); ++i)
1902         parents.push_back(details.parent_folder_ids(i));
1903       dict->SetString("parents", JoinString(parents, ","));
1904     }
1905     files->Append(dict);
1906   }
1907   return files.Pass();
1908 }
1909
1910 void MetadataDatabase::AttachSyncRoot(
1911     const google_apis::FileResource& sync_root_folder) {
1912   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1913
1914   scoped_ptr<FileMetadata> sync_root_metadata =
1915       CreateFileMetadataFromFileResource(
1916           GetLargestKnownChangeID(), sync_root_folder);
1917   scoped_ptr<FileTracker> sync_root_tracker =
1918       CreateSyncRootTracker(IncrementTrackerID(), *sync_root_metadata);
1919
1920   index_->SetSyncRootTrackerID(sync_root_tracker->tracker_id());
1921   index_->StoreFileMetadata(sync_root_metadata.Pass());
1922   index_->StoreFileTracker(sync_root_tracker.Pass());
1923 }
1924
1925 void MetadataDatabase::AttachInitialAppRoot(
1926     const google_apis::FileResource& app_root_folder) {
1927   scoped_ptr<FileMetadata> app_root_metadata =
1928       CreateFileMetadataFromFileResource(
1929           GetLargestKnownChangeID(), app_root_folder);
1930   scoped_ptr<FileTracker> app_root_tracker =
1931       CreateInitialAppRootTracker(IncrementTrackerID(),
1932                                   GetSyncRootTrackerID(),
1933                                   *app_root_metadata);
1934
1935   index_->StoreFileMetadata(app_root_metadata.Pass());
1936   index_->StoreFileTracker(app_root_tracker.Pass());
1937 }
1938
1939 void MetadataDatabase::DetachFromSequence() {
1940   worker_sequence_checker_.DetachFromSequence();
1941 }
1942
1943 bool MetadataDatabase::CanClearDirty(const FileTracker& tracker) {
1944   DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread());
1945
1946   FileMetadata metadata;
1947   if (!index_->GetFileMetadata(tracker.file_id(), &metadata) ||
1948       !tracker.active() || !tracker.dirty() ||
1949       !tracker.has_synced_details() ||
1950       tracker.needs_folder_listing())
1951     return false;
1952
1953   const FileDetails& remote_details = metadata.details();
1954   const FileDetails& synced_details = tracker.synced_details();
1955   if (remote_details.title() != synced_details.title() ||
1956       remote_details.md5() != synced_details.md5())
1957     return false;
1958
1959   std::set<std::string> parents;
1960   for (int i = 0; i < remote_details.parent_folder_ids_size(); ++i)
1961     parents.insert(remote_details.parent_folder_ids(i));
1962
1963   for (int i = 0; i < synced_details.parent_folder_ids_size(); ++i)
1964     if (parents.erase(synced_details.parent_folder_ids(i)) != 1)
1965       return false;
1966
1967   if (!parents.empty())
1968     return false;
1969
1970   return true;
1971 }
1972
1973 }  // namespace drive_backend
1974 }  // namespace sync_file_system