metadata_database.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
1cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// Copyright 2013 The Chromium Authors. All rights reserved.
2cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// Use of this source code is governed by a BSD-style license that can be
3cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// found in the LICENSE file.
4cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com
5cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
6cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com
7cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include <algorithm>
8cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include <stack>
9cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com
108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/bind.h"
118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/callback.h"
128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/files/file_path.h"
138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/location.h"
148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/memory/scoped_vector.h"
158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/message_loop/message_loop_proxy.h"
168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/sequenced_task_runner.h"
178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/stl_util.h"
188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/strings/string_number_conversions.h"
198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/strings/string_util.h"
208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/strings/stringprintf.h"
218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/task_runner_util.h"
228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/threading/thread_restrictions.h"
238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/drive/drive_api_util.h"
248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/google_apis/drive_api_parser.h"
258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/google_apis/drive_entry_kinds.h"
268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h"
288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/sync_file_system/logger.h"
298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "third_party/leveldatabase/src/include/leveldb/db.h"
318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "webkit/common/fileapi/file_system_util.h"
338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace sync_file_system {
358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace drive_backend {
368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char kDatabaseVersionKey[] = "VERSION";
388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst int64 kCurrentDatabaseVersion = 3;
398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char kServiceMetadataKey[] = "SERVICE";
408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char kFileMetadataKeyPrefix[] = "FILE: ";
418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char kFileTrackerKeyPrefix[] = "TRACKER: ";
428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstruct DatabaseContents {
448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  scoped_ptr<ServiceMetadata> service_metadata;
458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  ScopedVector<FileMetadata> file_metadata;
468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  ScopedVector<FileTracker> file_trackers;
478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com};
488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace {
508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypedef MetadataDatabase::FileByID FileByID;
528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypedef MetadataDatabase::TrackerByID TrackerByID;
538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypedef MetadataDatabase::TrackersByParentAndTitle TrackersByParentAndTitle;
548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypedef MetadataDatabase::TrackersByTitle TrackersByTitle;
558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool IsAppRoot(const FileTracker& tracker) {
578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return tracker.tracker_kind() == TRACKER_KIND_APP_ROOT ||
588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT;
598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstd::string RemovePrefix(const std::string& str, const std::string& prefix) {
628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (StartsWithASCII(str, prefix, true))
638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return str.substr(prefix.size());
648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return str;
658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combase::FilePath ReverseConcatPathComponents(
688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const std::vector<base::FilePath>& components) {
698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (components.empty())
708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return base::FilePath(FILE_PATH_LITERAL("/")).NormalizePathSeparators();
718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  size_t total_size = 0;
738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  typedef std::vector<base::FilePath> PathComponents;
748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (PathComponents::const_iterator itr = components.begin();
758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       itr != components.end(); ++itr)
768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    total_size += itr->value().size() + 1;
778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  base::FilePath::StringType result;
798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  result.reserve(total_size);
808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (PathComponents::const_reverse_iterator itr = components.rbegin();
818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       itr != components.rend(); ++itr) {
828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    result.append(1, base::FilePath::kSeparators[0]);
838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    result.append(itr->value());
848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return base::FilePath(result).NormalizePathSeparators();
878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PopulateFileDetailsByFileResource(
908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const google_apis::FileResource& file_resource,
918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    FileDetails* details) {
928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  details->clear_parent_folder_ids();
938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (ScopedVector<google_apis::ParentReference>::const_iterator itr =
948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com           file_resource.parents().begin();
958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       itr != file_resource.parents().end();
968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       ++itr) {
978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    details->add_parent_folder_ids((*itr)->file_id());
988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  details->set_title(file_resource.title());
1008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  google_apis::DriveEntryKind kind = drive::util::GetKind(file_resource);
1028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (kind == google_apis::ENTRY_KIND_FILE)
1038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    details->set_file_kind(FILE_KIND_FILE);
1048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  else if (kind == google_apis::ENTRY_KIND_FOLDER)
1058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    details->set_file_kind(FILE_KIND_FOLDER);
1068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  else
1078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    details->set_file_kind(FILE_KIND_UNSUPPORTED);
1088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  details->set_md5(file_resource.md5_checksum());
1108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  details->set_etag(file_resource.etag());
1118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  details->set_creation_time(file_resource.created_date().ToInternalValue());
1128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  details->set_modification_time(
1138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      file_resource.modified_date().ToInternalValue());
1148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  details->set_deleted(false);
1158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comscoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource(
1188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const google_apis::ChangeResource& change) {
1198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  scoped_ptr<FileMetadata> file(new FileMetadata);
1208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  file->set_file_id(change.file_id());
1218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  FileDetails* details = file->mutable_details();
1238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  details->set_change_id(change.change_id());
1248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (change.is_deleted()) {
1268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    details->set_deleted(true);
1278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return file.Pass();
1288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
1298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  PopulateFileDetailsByFileResource(*change.file(), details);
1318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return file.Pass();
1328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid CreateInitialSyncRootTracker(
1358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    int64 tracker_id,
1368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const google_apis::FileResource& file_resource,
1378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    scoped_ptr<FileMetadata>* file_out,
1388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    scoped_ptr<FileTracker>* tracker_out) {
1398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  FileDetails details;
1408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  PopulateFileDetailsByFileResource(file_resource, &details);
1418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  scoped_ptr<FileMetadata> file(new FileMetadata);
1438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  file->set_file_id(file_resource.file_id());
1448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *file->mutable_details() = details;
1458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  scoped_ptr<FileTracker> tracker(new FileTracker);
1478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_tracker_id(tracker_id);
1488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_file_id(file_resource.file_id());
1498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_parent_tracker_id(0);
1508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
1518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_dirty(false);
1528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_active(true);
1538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_needs_folder_listing(false);
1548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *tracker->mutable_synced_details() = details;
1558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *file_out = file.Pass();
1578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *tracker_out = tracker.Pass();
1588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid CreateInitialAppRootTracker(
1618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    int64 tracker_id,
1628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const FileTracker& parent_tracker,
1638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const google_apis::FileResource& file_resource,
1648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    scoped_ptr<FileMetadata>* file_out,
1658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    scoped_ptr<FileTracker>* tracker_out) {
1668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  FileDetails details;
1678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  PopulateFileDetailsByFileResource(file_resource, &details);
1688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  scoped_ptr<FileMetadata> file(new FileMetadata);
1708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  file->set_file_id(file_resource.file_id());
1718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *file->mutable_details() = details;
1728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  scoped_ptr<FileTracker> tracker(new FileTracker);
1748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_tracker_id(tracker_id);
1758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_parent_tracker_id(parent_tracker.tracker_id());
1768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_file_id(file_resource.file_id());
1778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
1788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_dirty(false);
1798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_active(false);
1808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  tracker->set_needs_folder_listing(false);
1818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *tracker->mutable_synced_details() = details;
1828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *file_out = file.Pass();
1848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *tracker_out = tracker.Pass();
1858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid AdaptLevelDBStatusToSyncStatusCode(const SyncStatusCallback& callback,
1888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                                        const leveldb::Status& status) {
1898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  callback.Run(LevelDBStatusToSyncStatusCode(status));
1908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutServiceMetadataToBatch(const ServiceMetadata& service_metadata,
1938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                               leveldb::WriteBatch* batch) {
1948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string value;
1958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  bool success = service_metadata.SerializeToString(&value);
1968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(success);
1978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  batch->Put(kServiceMetadataKey, value);
1988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutFileToBatch(const FileMetadata& file, leveldb::WriteBatch* batch) {
2018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string value;
2028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  bool success = file.SerializeToString(&value);
2038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(success);
2048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  batch->Put(kFileMetadataKeyPrefix + file.file_id(), value);
2058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutTrackerToBatch(const FileTracker& tracker, leveldb::WriteBatch* batch) {
2088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string value;
2098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  bool success = tracker.SerializeToString(&value);
2108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(success);
2118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()),
2128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com             value);
2138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutFileDeletionToBatch(const std::string& file_id,
2168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                            leveldb::WriteBatch* batch) {
2178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  batch->Delete(kFileMetadataKeyPrefix + file_id);
2188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutTrackerDeletionToBatch(int64 tracker_id, leveldb::WriteBatch* batch) {
2218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  batch->Delete(kFileTrackerKeyPrefix + base::Int64ToString(tracker_id));
2228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtemplate <typename OutputIterator>
2258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comOutputIterator PushChildTrackersToContainer(
2268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const TrackersByParentAndTitle& trackers_by_parent,
2278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    int64 parent_tracker_id,
2288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    OutputIterator target_itr) {
2298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  TrackersByParentAndTitle::const_iterator found =
2308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      trackers_by_parent.find(parent_tracker_id);
2318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (found == trackers_by_parent.end())
2328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return target_itr;
2338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (TrackersByTitle::const_iterator title_itr = found->second.begin();
2358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       title_itr != found->second.end(); ++title_itr) {
2368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const TrackerSet& trackers = title_itr->second;
2378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    for (TrackerSet::const_iterator tracker_itr = trackers.begin();
2388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com         tracker_itr != trackers.end(); ++tracker_itr) {
2398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      *target_itr = (*tracker_itr)->tracker_id();
2408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      ++target_itr;
2418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
2428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
2438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return target_itr;
2448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstd::string GetTrackerTitle(const FileTracker& tracker) {
2478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (tracker.has_synced_details())
2488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return tracker.synced_details().title();
2498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return std::string();
2508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// Returns true if |db| has no content.
2538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool IsDatabaseEmpty(leveldb::DB* db) {
2548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(db);
2558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
2568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  itr->SeekToFirst();
2578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return !itr->Valid();
2588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode OpenDatabase(const base::FilePath& path,
2618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                            scoped_ptr<leveldb::DB>* db_out,
2628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                            bool* created) {
2638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  base::ThreadRestrictions::AssertIOAllowed();
2648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(db_out);
2658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(created);
2668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  leveldb::Options options;
2688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  options.max_open_files = 0;  // Use minimum.
2698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  options.create_if_missing = true;
2708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  leveldb::DB* db = NULL;
2718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  leveldb::Status db_status =
2728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db);
2738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  SyncStatusCode status = LevelDBStatusToSyncStatusCode(db_status);
2748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (status != SYNC_STATUS_OK) {
2758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    delete db;
2768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return status;
2778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
2788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  *created = IsDatabaseEmpty(db);
2808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  db_out->reset(db);
2818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return status;
2828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode MigrateDatabaseIfNeeded(leveldb::DB* db) {
2858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  base::ThreadRestrictions::AssertIOAllowed();
2868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(db);
2878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string value;
2888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  leveldb::Status status =
2898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      db->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value);
2908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  int64 version = 0;
2918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (status.ok()) {
2928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (!base::StringToInt64(value, &version))
2938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return SYNC_DATABASE_ERROR_FAILED;
2948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  } else {
2958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (!status.IsNotFound())
2968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return SYNC_DATABASE_ERROR_FAILED;
2978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
2988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  switch (version) {
3008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    case 0:
3018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      drive_backend::MigrateDatabaseFromV0ToV1(db);
3028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // fall-through
3038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    case 1:
3048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      drive_backend::MigrateDatabaseFromV1ToV2(db);
3058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // fall-through
3068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    case 2:
3078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // TODO(tzik): Migrate database from version 2 to 3.
3088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //   * Add sync-root folder as active, dirty and needs_folder_listing
3098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //     folder.
3108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //   * Add app-root folders for each origins.  Each app-root folder for
3118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //     an enabled origin should be a active, dirty and
3128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //     needs_folder_listing folder.  And Each app-root folder for a
3138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //     disabled origin should be an inactive, dirty and
3148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //     non-needs_folder_listing folder.
3158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //   * Add a file metadata for each file in previous version.
3168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NOTIMPLEMENTED();
3178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return SYNC_DATABASE_ERROR_FAILED;
3188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // fall-through
3198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    case 3:
3208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      DCHECK_EQ(3, kCurrentDatabaseVersion);
3218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return SYNC_STATUS_OK;
3228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    default:
3238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return SYNC_DATABASE_ERROR_FAILED;
3248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
3258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode WriteVersionInfo(leveldb::DB* db) {
3288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  base::ThreadRestrictions::AssertIOAllowed();
3298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(db);
3308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return LevelDBStatusToSyncStatusCode(
3318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      db->Put(leveldb::WriteOptions(),
3328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com              kDatabaseVersionKey,
3338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com              base::Int64ToString(kCurrentDatabaseVersion)));
3348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode ReadDatabaseContents(leveldb::DB* db,
3378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                                    DatabaseContents* contents) {
3388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  base::ThreadRestrictions::AssertIOAllowed();
3398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(db);
3408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DCHECK(contents);
3418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
3438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (itr->SeekToFirst(); itr->Valid(); itr->Next()) {
3448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    std::string key = itr->key().ToString();
3458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    std::string value = itr->value().ToString();
3468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (key == kServiceMetadataKey) {
3478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      scoped_ptr<ServiceMetadata> service_metadata(new ServiceMetadata);
3488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (!service_metadata->ParseFromString(value)) {
3498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        util::Log(logging::LOG_WARNING, FROM_HERE,
3508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                  "Failed to parse SyncServiceMetadata");
3518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        continue;
3528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      }
3538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      contents->service_metadata = service_metadata.Pass();
3558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      continue;
3568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
3578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (StartsWithASCII(key, kFileMetadataKeyPrefix, true)) {
3598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      std::string file_id = RemovePrefix(key, kFileMetadataKeyPrefix);
3608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      scoped_ptr<FileMetadata> file(new FileMetadata);
3628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (!file->ParseFromString(itr->value().ToString())) {
3638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        util::Log(logging::LOG_WARNING, FROM_HERE,
3648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                  "Failed to parse a FileMetadata");
3658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        continue;
3668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      }
3678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      contents->file_metadata.push_back(file.release());
3698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      continue;
3708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
3718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (StartsWithASCII(key, kFileTrackerKeyPrefix, true)) {
3738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      int64 tracker_id = 0;
3748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (!base::StringToInt64(RemovePrefix(key, kFileTrackerKeyPrefix),
3758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                               &tracker_id)) {
3768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        util::Log(logging::LOG_WARNING, FROM_HERE,
3778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                  "Failed to parse TrackerID");
3788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        continue;
3798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      }
3808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      scoped_ptr<FileTracker> tracker(new FileTracker);
3828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (!tracker->ParseFromString(itr->value().ToString())) {
3838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        util::Log(logging::LOG_WARNING, FROM_HERE,
3848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                  "Failed to parse a Tracker");
3858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        continue;
3868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      }
3878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      contents->file_trackers.push_back(tracker.release());
3888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      continue;
3898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
3908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
3918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return SYNC_STATUS_OK;
3938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode InitializeServiceMetadata(DatabaseContents* contents,
3968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                                         leveldb::WriteBatch* batch) {
3978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (!contents->service_metadata) {
3988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    contents->service_metadata.reset(new ServiceMetadata);
3998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    contents->service_metadata->set_next_tracker_id(1);
4008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    std::string value;
4028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    contents->service_metadata->SerializeToString(&value);
4038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    batch->Put(kServiceMetadataKey, value);
4048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return SYNC_STATUS_OK;
4068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
4078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode RemoveUnreachableItems(DatabaseContents* contents,
4098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                                      leveldb::WriteBatch* batch) {
4108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  TrackerByID unvisited_trackers;
4118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  typedef std::map<int64, std::set<FileTracker*> > TrackersByParent;
4128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  TrackersByParent trackers_by_parent;
4138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (ScopedVector<FileTracker>::iterator itr =
4158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com           contents->file_trackers.begin();
4168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       itr != contents->file_trackers.end();
4178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       ++itr) {
4188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    FileTracker* tracker = *itr;
4198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    DCHECK(!ContainsKey(unvisited_trackers, tracker->tracker_id()));
4208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    unvisited_trackers[tracker->tracker_id()] = tracker;
4218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (tracker->parent_tracker_id())
4228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      trackers_by_parent[tracker->parent_tracker_id()].insert(tracker);
4238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Traverse synced tracker tree. Take only active items, app-root and their
4268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // children. Drop unreachable items.
4278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  ScopedVector<FileTracker> reachable_trackers;
4288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::stack<int64> pending;
4298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (contents->service_metadata->sync_root_tracker_id())
4308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    pending.push(contents->service_metadata->sync_root_tracker_id());
4318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  while (!pending.empty()) {
4338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    int64 tracker_id = pending.top();
4348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    pending.pop();
4358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    {
4378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      TrackerByID::iterator found = unvisited_trackers.find(tracker_id);
4388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (found == unvisited_trackers.end())
4398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        continue;
4408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      FileTracker* tracker = found->second;
4428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      unvisited_trackers.erase(found);
4438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      reachable_trackers.push_back(tracker);
4448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (!tracker->active())
4468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        continue;
4478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
4488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    TrackersByParent::iterator found = trackers_by_parent.find(tracker_id);
4508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (found == trackers_by_parent.end())
4518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      continue;
4528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    for (std::set<FileTracker*>::const_iterator itr =
4548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com             found->second.begin();
4558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com         itr != found->second.end();
4568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com         ++itr)
4578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      pending.push((*itr)->tracker_id());
4588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Delete all unreachable trackers.
4618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (TrackerByID::iterator itr = unvisited_trackers.begin();
4628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       itr != unvisited_trackers.end(); ++itr) {
4638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    FileTracker* tracker = itr->second;
4648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    PutTrackerDeletionToBatch(tracker->tracker_id(), batch);
4658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    delete tracker;
4668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  unvisited_trackers.clear();
4688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // |reachable_trackers| contains all files/folders reachable from sync-root
4708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // folder via active folders and app-root folders.
4718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Update the tracker set in database contents with the reachable tracker set.
4728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  contents->file_trackers.weak_clear();
4738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  contents->file_trackers.swap(reachable_trackers);
4748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Do the similar traverse for FileMetadata and remove FileMetadata that don't
4768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // have reachable trackers.
4778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  FileByID unreferred_files;
4788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (ScopedVector<FileMetadata>::const_iterator itr =
4798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com           contents->file_metadata.begin();
4808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       itr != contents->file_metadata.end();
4818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       ++itr) {
4828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    unreferred_files.insert(std::make_pair((*itr)->file_id(), *itr));
4838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  ScopedVector<FileMetadata> referred_files;
4868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (ScopedVector<FileTracker>::const_iterator itr =
4878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com           contents->file_trackers.begin();
4888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       itr != contents->file_trackers.end();
4898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       ++itr) {
4908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    FileByID::iterator found = unreferred_files.find((*itr)->file_id());
4918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (found != unreferred_files.end()) {
4928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      referred_files.push_back(found->second);
4938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      unreferred_files.erase(found);
4948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
4958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  for (FileByID::iterator itr = unreferred_files.begin();
4988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       itr != unreferred_files.end(); ++itr) {
4998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    FileMetadata* file = itr->second;
5008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    PutFileDeletionToBatch(file->file_id(), batch);
5018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    delete file;
5028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
5038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  unreferred_files.clear();
5048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
5058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  contents->file_metadata.weak_clear();
5068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  contents->file_metadata.swap(referred_files);
5078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
5088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return SYNC_STATUS_OK;
5098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
5108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
5118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtemplate <typename Container, typename Key, typename Value>
5128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool FindItem(const Container& container, const Key& key, Value* value) {
5138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  typename Container::const_iterator found = container.find(key);
5148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (found == container.end())
5158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return false;
5168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (value)
5178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    *value = *found->second;
5188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return true;
5198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
5208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
5218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtemplate <typename Container, typename Key>
5228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypename Container::mapped_type FindAndEraseItem(Container* container,
523cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com                                                 const Key& key) {
5248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  typedef typename Container::mapped_type Value;
5258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  typename Container::iterator found = container->find(key);
526cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com  if (found == container->end())
5278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return Value();
5288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
529cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com  Value result = found->second;
5308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  container->erase(found);
5318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return result;
5328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
5338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
5348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid RunSoon(const tracked_objects::Location& from_here,
535cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com             const base::Closure& closure) {
536  base::MessageLoopProxy::current()->PostTask(from_here, closure);
537}
538
539}  // namespace
540
541bool MetadataDatabase::DirtyTrackerComparator::operator()(
542    const FileTracker* left,
543    const FileTracker* right) const {
544  return left->tracker_id() < right->tracker_id();
545}
546
547// static
548void MetadataDatabase::Create(base::SequencedTaskRunner* task_runner,
549                              const base::FilePath& database_path,
550                              const CreateCallback& callback) {
551  task_runner->PostTask(FROM_HERE, base::Bind(
552      &CreateOnTaskRunner,
553      base::MessageLoopProxy::current(),
554      make_scoped_refptr(task_runner),
555      database_path, callback));
556}
557
558MetadataDatabase::~MetadataDatabase() {
559  task_runner_->DeleteSoon(FROM_HERE, db_.release());
560  STLDeleteContainerPairSecondPointers(
561      file_by_id_.begin(), file_by_id_.end());
562  STLDeleteContainerPairSecondPointers(
563      tracker_by_id_.begin(), tracker_by_id_.end());
564}
565
566int64 MetadataDatabase::GetLargestChangeID() const {
567  return service_metadata_->largest_change_id();
568}
569
570int64 MetadataDatabase::GetSyncRootTrackerID() const {
571  return service_metadata_->sync_root_tracker_id();
572}
573
574bool MetadataDatabase::HasSyncRoot() const {
575  return service_metadata_->has_sync_root_tracker_id() &&
576      !!service_metadata_->sync_root_tracker_id();
577}
578
579void MetadataDatabase::PopulateInitialData(
580    int64 largest_change_id,
581    const google_apis::FileResource& sync_root_folder,
582    const ScopedVector<google_apis::FileResource>& app_root_folders,
583    const SyncStatusCallback& callback) {
584  DCHECK(tracker_by_id_.empty());
585  DCHECK(file_by_id_.empty());
586
587  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
588  service_metadata_->set_largest_change_id(largest_change_id);
589
590  FileTracker* sync_root_tracker = NULL;
591  int64 sync_root_tracker_id = 0;
592  {
593    scoped_ptr<FileMetadata> folder;
594    scoped_ptr<FileTracker> tracker;
595    CreateInitialSyncRootTracker(GetNextTrackerID(batch.get()),
596                                 sync_root_folder,
597                                 &folder,
598                                 &tracker);
599    std::string sync_root_folder_id = folder->file_id();
600    sync_root_tracker = tracker.get();
601    sync_root_tracker_id = tracker->tracker_id();
602
603    PutFileToBatch(*folder, batch.get());
604    PutTrackerToBatch(*tracker, batch.get());
605
606    service_metadata_->set_sync_root_tracker_id(tracker->tracker_id());
607    PutServiceMetadataToBatch(*service_metadata_, batch.get());
608
609    trackers_by_file_id_[folder->file_id()].Insert(tracker.get());
610
611    file_by_id_[sync_root_folder_id] = folder.release();
612    tracker_by_id_[sync_root_tracker_id] = tracker.release();
613  }
614
615  for (ScopedVector<google_apis::FileResource>::const_iterator itr =
616           app_root_folders.begin();
617       itr != app_root_folders.end();
618       ++itr) {
619    const google_apis::FileResource& folder_resource = **itr;
620    scoped_ptr<FileMetadata> folder;
621    scoped_ptr<FileTracker> tracker;
622    CreateInitialAppRootTracker(GetNextTrackerID(batch.get()),
623                                *sync_root_tracker,
624                                folder_resource,
625                                &folder,
626                                &tracker);
627    std::string title = folder->details().title();
628    std::string folder_id = folder->file_id();
629    int64 tracker_id = tracker->tracker_id();
630
631    PutFileToBatch(*folder, batch.get());
632    PutTrackerToBatch(*tracker, batch.get());
633
634    trackers_by_file_id_[folder_id].Insert(tracker.get());
635    trackers_by_parent_and_title_[sync_root_tracker_id][title]
636        .Insert(tracker.get());
637
638    file_by_id_[folder_id] = folder.release();
639    tracker_by_id_[tracker_id] = tracker.release();
640  }
641
642  WriteToDatabase(batch.Pass(), callback);
643}
644
645
646void MetadataDatabase::RegisterApp(const std::string& app_id,
647                                   const std::string& folder_id,
648                                   const SyncStatusCallback& callback) {
649  if (FindAppRootTracker(app_id, NULL)) {
650    // The app-root is already registered.
651    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
652    return;
653  }
654
655  TrackerSet trackers;
656  if (!FindTrackersByFileID(folder_id, &trackers) || trackers.has_active()) {
657    // The folder is tracked by another tracker.
658    util::Log(logging::LOG_WARNING, FROM_HERE,
659              "Failed to register App for %s", app_id.c_str());
660    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_HAS_CONFLICT));
661    return;
662  }
663
664  int64 sync_root_tracker_id = service_metadata_->sync_root_tracker_id();
665  if (!sync_root_tracker_id) {
666    util::Log(logging::LOG_WARNING, FROM_HERE,
667              "Sync-root needs to be set up before registering app-root");
668    RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
669    return;
670  }
671
672  // Make this tracker an app-root tracker.
673  FileTracker* app_root_tracker = NULL;
674  for (TrackerSet::iterator itr = trackers.begin();
675       itr != trackers.end(); ++itr) {
676    FileTracker* tracker = *itr;
677    if (tracker->parent_tracker_id() == sync_root_tracker_id)
678      app_root_tracker = tracker;
679  }
680
681  if (!app_root_tracker) {
682    RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
683    return;
684  }
685
686  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
687  RegisterTrackerAsAppRoot(app_id, app_root_tracker->tracker_id(), batch.get());
688  WriteToDatabase(batch.Pass(), callback);
689}
690
691void MetadataDatabase::DisableApp(const std::string& app_id,
692                                  const SyncStatusCallback& callback) {
693  FileTracker tracker;
694  if (!FindAppRootTracker(app_id, &tracker)) {
695    RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
696    return;
697  }
698
699  if (tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT) {
700    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
701    return;
702  }
703
704  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
705  MakeAppRootDisabled(tracker.tracker_id(), batch.get());
706  WriteToDatabase(batch.Pass(), callback);
707}
708
709void MetadataDatabase::EnableApp(const std::string& app_id,
710                                 const SyncStatusCallback& callback) {
711  FileTracker tracker;
712  if (!FindAppRootTracker(app_id, &tracker) ||
713      tracker.tracker_kind() == TRACKER_KIND_REGULAR) {
714    RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
715    return;
716  }
717
718  if (tracker.tracker_kind() == TRACKER_KIND_APP_ROOT) {
719    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
720    return;
721  }
722
723  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
724  MakeAppRootEnabled(tracker.tracker_id(), batch.get());
725  WriteToDatabase(batch.Pass(), callback);
726}
727
728void MetadataDatabase::UnregisterApp(const std::string& app_id,
729                                     const SyncStatusCallback& callback) {
730  FileTracker tracker;
731  if (!FindAppRootTracker(app_id, &tracker) ||
732      tracker.tracker_kind() == TRACKER_KIND_REGULAR) {
733    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
734    return;
735  }
736
737  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
738  UnregisterTrackerAsAppRoot(app_id, batch.get());
739  WriteToDatabase(batch.Pass(), callback);
740}
741
742bool MetadataDatabase::FindAppRootTracker(const std::string& app_id,
743                                          FileTracker* tracker) const {
744  return FindItem(app_root_by_app_id_, app_id, tracker);
745}
746
747bool MetadataDatabase::FindFileByFileID(const std::string& file_id,
748                                        FileMetadata* file) const {
749  return FindItem(file_by_id_, file_id, file);
750}
751
752bool MetadataDatabase::FindTrackersByFileID(const std::string& file_id,
753                                            TrackerSet* trackers) const {
754  TrackersByFileID::const_iterator found = trackers_by_file_id_.find(file_id);
755  if (found == trackers_by_file_id_.end())
756    return false;
757  if (trackers)
758    *trackers = found->second;
759  return true;
760}
761
762bool MetadataDatabase::FindTrackerByTrackerID(int64 tracker_id,
763                                              FileTracker* tracker) const {
764  return FindItem(tracker_by_id_, tracker_id, tracker);
765}
766
767bool MetadataDatabase::BuildPathForTracker(int64 tracker_id,
768                                           base::FilePath* path) const {
769  FileTracker current;
770  if (!FindTrackerByTrackerID(tracker_id, &current) || !current.active())
771    return false;
772
773  std::vector<base::FilePath> components;
774  while (!IsAppRoot(current)) {
775    std::string title = GetTrackerTitle(current);
776    if (title.empty())
777      return false;
778    components.push_back(base::FilePath::FromUTF8Unsafe(title));
779    if (!FindTrackerByTrackerID(current.parent_tracker_id(), &current) ||
780        !current.active())
781      return false;
782  }
783
784  if (path)
785    *path = ReverseConcatPathComponents(components);
786
787  return true;
788}
789
790void MetadataDatabase::UpdateByChangeList(
791    ScopedVector<google_apis::ChangeResource> changes,
792    const SyncStatusCallback& callback) {
793  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
794
795  for (ScopedVector<google_apis::ChangeResource>::const_iterator itr =
796           changes.begin();
797       itr != changes.end();
798       ++itr) {
799    const google_apis::ChangeResource& change = **itr;
800    scoped_ptr<FileMetadata> file(
801        CreateFileMetadataFromChangeResource(change));
802    std::string file_id = file->file_id();
803
804    MarkTrackersDirtyByFileID(file_id, batch.get());
805    if (!file->details().deleted())
806      MaybeAddTrackersForNewFile(*file, batch.get());
807
808    if (FindTrackersByFileID(file_id, NULL)) {
809      PutFileToBatch(*file, batch.get());
810
811      FileMetadata* file_ptr = file.release();
812      std::swap(file_ptr, file_by_id_[file_id]);
813      delete file_ptr;
814    }
815  }
816
817  WriteToDatabase(batch.Pass(), callback);
818}
819
820void MetadataDatabase::PopulateFolderByChildList(
821    const std::string& folder_id,
822    const FileIDList& child_file_ids,
823    const SyncStatusCallback& callback) {
824  TrackerSet trackers;
825  if (!FindTrackersByFileID(folder_id, &trackers) ||
826      !trackers.has_active()) {
827    // It's OK that there is no folder to populate its children.
828    // Inactive folders should ignore their contents updates.
829    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
830    return;
831  }
832
833  FileTracker* folder_tracker =
834      tracker_by_id_[trackers.active_tracker()->tracker_id()];
835  DCHECK(folder_tracker);
836  std::set<std::string> children(child_file_ids.begin(), child_file_ids.end());
837
838  std::vector<int64> known_children;
839  PushChildTrackersToContainer(trackers_by_parent_and_title_,
840                               folder_tracker->tracker_id(),
841                               std::back_inserter(known_children));
842  for (std::vector<int64>::iterator itr = known_children.begin();
843       itr != known_children.end(); ++itr)
844    children.erase(tracker_by_id_[*itr]->file_id());
845
846  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
847  for (FileIDList::const_iterator itr = child_file_ids.begin();
848       itr != child_file_ids.end(); ++itr)
849    CreateTrackerForParentAndFileID(*folder_tracker, *itr, batch.get());
850  folder_tracker->set_needs_folder_listing(false);
851  if (folder_tracker->dirty() && !ShouldKeepDirty(*folder_tracker)) {
852    folder_tracker->set_dirty(false);
853    dirty_trackers_.erase(folder_tracker);
854  }
855  PutTrackerToBatch(*folder_tracker, batch.get());
856
857  WriteToDatabase(batch.Pass(), callback);
858}
859
860void MetadataDatabase::UpdateTracker(int64 tracker_id,
861                                     const FileDetails& updated_details,
862                                     const SyncStatusCallback& callback) {
863  TrackerByID::iterator found = tracker_by_id_.find(tracker_id);
864  if (found == tracker_by_id_.end()) {
865    RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
866    return;
867  }
868
869  FileTracker* tracker = found->second;
870  DCHECK(tracker);
871
872  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
873
874  if (updated_details.deleted()) {
875    // The update deletes the local file.
876    FileByID::iterator found = file_by_id_.find(tracker->file_id());
877    if (found == file_by_id_.end() || found->second->details().deleted()) {
878      // Both the tracker and metadata have the deleted flag, now it's safe to
879      // delete the |tracker|.
880      RemoveTracker(tracker->tracker_id(), batch.get());
881    } else {
882      // The local file is deleted, but corresponding remote file isn't.
883      // Put the tracker back to the initial state.
884      tracker->clear_synced_details();
885      tracker->set_dirty(true);
886      tracker->set_active(false);
887      PutTrackerToBatch(*tracker, batch.get());
888    }
889
890    WriteToDatabase(batch.Pass(), callback);
891    return;
892  }
893
894  // Check if the tracker was retitled.  If it was, update the title and its
895  // index in advance.
896  if (!tracker->has_synced_details() ||
897      tracker->synced_details().title() != updated_details.title()) {
898    UpdateTrackerTitle(tracker, updated_details.title(), batch.get());
899  }
900
901  *tracker->mutable_synced_details() = updated_details;
902
903  // Activate the tracker if:
904  //   - There is no active tracker that tracks |tracker->file_id()|.
905  //   - There is no active tracker that has the same |parent| and |title|.
906  if (!tracker->active() && CanActivateTracker(*tracker))
907    MakeTrackerActive(tracker->tracker_id(), batch.get());
908  if (tracker->dirty() && !ShouldKeepDirty(*tracker)) {
909    tracker->set_dirty(false);
910    dirty_trackers_.erase(tracker);
911  }
912  PutTrackerToBatch(*tracker, batch.get());
913
914  WriteToDatabase(batch.Pass(), callback);
915}
916
917MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner)
918    : task_runner_(task_runner), weak_ptr_factory_(this) {
919  DCHECK(task_runner);
920}
921
922// static
923void MetadataDatabase::CreateOnTaskRunner(
924    base::SingleThreadTaskRunner* callback_runner,
925    base::SequencedTaskRunner* task_runner,
926    const base::FilePath& database_path,
927    const CreateCallback& callback) {
928  scoped_ptr<MetadataDatabase> metadata_database(
929      new MetadataDatabase(task_runner));
930  SyncStatusCode status =
931      metadata_database->InitializeOnTaskRunner(database_path);
932  if (status != SYNC_STATUS_OK)
933    metadata_database.reset();
934
935  callback_runner->PostTask(FROM_HERE, base::Bind(
936      callback, status, base::Passed(&metadata_database)));
937}
938
939// static
940SyncStatusCode MetadataDatabase::CreateForTesting(
941    scoped_ptr<leveldb::DB> db,
942    scoped_ptr<MetadataDatabase>* metadata_database_out) {
943  scoped_ptr<MetadataDatabase> metadata_database(
944      new MetadataDatabase(base::MessageLoopProxy::current()));
945  metadata_database->db_ = db.Pass();
946  SyncStatusCode status =
947      metadata_database->InitializeOnTaskRunner(base::FilePath());
948  if (status == SYNC_STATUS_OK)
949    *metadata_database_out = metadata_database.Pass();
950  return status;
951}
952
953SyncStatusCode MetadataDatabase::InitializeOnTaskRunner(
954    const base::FilePath& database_path) {
955  base::ThreadRestrictions::AssertIOAllowed();
956  DCHECK(task_runner_->RunsTasksOnCurrentThread());
957
958  SyncStatusCode status = SYNC_STATUS_UNKNOWN;
959  bool created = false;
960  // Open database unless |db_| is overridden for testing.
961  if (!db_) {
962    status = OpenDatabase(database_path, &db_, &created);
963    if (status != SYNC_STATUS_OK)
964      return status;
965  }
966
967  if (created) {
968    status = WriteVersionInfo(db_.get());
969    if (status != SYNC_STATUS_OK)
970      return status;
971  } else {
972    status = MigrateDatabaseIfNeeded(db_.get());
973    if (status != SYNC_STATUS_OK)
974      return status;
975  }
976
977  DatabaseContents contents;
978  status = ReadDatabaseContents(db_.get(), &contents);
979  if (status != SYNC_STATUS_OK)
980    return status;
981
982  leveldb::WriteBatch batch;
983  status = InitializeServiceMetadata(&contents, &batch);
984  if (status != SYNC_STATUS_OK)
985    return status;
986
987  status = RemoveUnreachableItems(&contents, &batch);
988  if (status != SYNC_STATUS_OK)
989    return status;
990
991  status = LevelDBStatusToSyncStatusCode(
992      db_->Write(leveldb::WriteOptions(), &batch));
993  if (status != SYNC_STATUS_OK)
994    return status;
995
996  BuildIndexes(&contents);
997  return status;
998}
999
1000void MetadataDatabase::BuildIndexes(DatabaseContents* contents) {
1001  service_metadata_ = contents->service_metadata.Pass();
1002
1003  for (ScopedVector<FileMetadata>::const_iterator itr =
1004           contents->file_metadata.begin();
1005       itr != contents->file_metadata.end();
1006       ++itr) {
1007    file_by_id_[(*itr)->file_id()] = *itr;
1008  }
1009  contents->file_metadata.weak_clear();
1010
1011  for (ScopedVector<FileTracker>::const_iterator itr =
1012           contents->file_trackers.begin();
1013       itr != contents->file_trackers.end();
1014       ++itr) {
1015    FileTracker* tracker = *itr;
1016    tracker_by_id_[tracker->tracker_id()] = tracker;
1017    trackers_by_file_id_[tracker->file_id()].Insert(tracker);
1018
1019    if (IsAppRoot(*tracker))
1020      app_root_by_app_id_[tracker->app_id()] = tracker;
1021
1022    if (tracker->parent_tracker_id()) {
1023      std::string title = GetTrackerTitle(*tracker);
1024      TrackerSet* trackers =
1025          &trackers_by_parent_and_title_[tracker->parent_tracker_id()][title];
1026      trackers->Insert(tracker);
1027    }
1028
1029    if (tracker->dirty())
1030      dirty_trackers_.insert(tracker);
1031  }
1032  contents->file_trackers.weak_clear();
1033}
1034
1035void MetadataDatabase::RegisterTrackerAsAppRoot(
1036    const std::string& app_id,
1037    int64 tracker_id,
1038    leveldb::WriteBatch* batch) {
1039  FileTracker* tracker = tracker_by_id_[tracker_id];
1040  DCHECK(tracker);
1041  tracker->set_app_id(app_id);
1042  tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT);
1043  app_root_by_app_id_[app_id] = tracker;
1044
1045  MakeTrackerActive(tracker->tracker_id(), batch);
1046}
1047
1048void MetadataDatabase::UnregisterTrackerAsAppRoot(
1049    const std::string& app_id,
1050    leveldb::WriteBatch* batch) {
1051  FileTracker* tracker = FindAndEraseItem(&app_root_by_app_id_, app_id);
1052  tracker->set_app_id(std::string());
1053  tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
1054
1055  // Inactivate the tracker to drop all descendant.
1056  // (Note that we set tracker_kind to TRACKER_KIND_REGULAR before calling
1057  // this.)
1058  MakeTrackerInactive(tracker->tracker_id(), batch);
1059}
1060
1061void MetadataDatabase::MakeTrackerActive(int64 tracker_id,
1062                                         leveldb::WriteBatch* batch) {
1063  FileTracker* tracker = tracker_by_id_[tracker_id];
1064  DCHECK(tracker);
1065  DCHECK(!tracker->active());
1066
1067  int64 parent_tracker_id = tracker->parent_tracker_id();
1068  DCHECK(tracker->has_synced_details());
1069  trackers_by_file_id_[tracker->file_id()].Activate(tracker);
1070  if (parent_tracker_id) {
1071    trackers_by_parent_and_title_[parent_tracker_id][
1072        tracker->synced_details().title()].Activate(tracker);
1073  }
1074  tracker->set_active(true);
1075  tracker->set_needs_folder_listing(
1076      tracker->synced_details().file_kind() == FILE_KIND_FOLDER);
1077  tracker->set_dirty(true);
1078  dirty_trackers_.insert(tracker);
1079
1080  PutTrackerToBatch(*tracker, batch);
1081}
1082
1083void MetadataDatabase::MakeTrackerInactive(int64 tracker_id,
1084                                           leveldb::WriteBatch* batch) {
1085  FileTracker* tracker = tracker_by_id_[tracker_id];
1086  DCHECK(tracker);
1087  DCHECK(tracker->active());
1088  DCHECK_EQ(TRACKER_KIND_REGULAR, tracker->tracker_kind());
1089  trackers_by_file_id_[tracker->file_id()].Inactivate(tracker);
1090
1091  std::string title = GetTrackerTitle(*tracker);
1092  int64 parent_tracker_id = tracker->parent_tracker_id();
1093  if (parent_tracker_id)
1094    trackers_by_parent_and_title_[parent_tracker_id][title].Inactivate(tracker);
1095  tracker->set_active(false);
1096
1097  RemoveAllDescendantTrackers(tracker_id, batch);
1098  MarkTrackersDirtyByFileID(tracker->file_id(), batch);
1099  if (parent_tracker_id)
1100    MarkTrackersDirtyByPath(parent_tracker_id, title, batch);
1101  PutTrackerToBatch(*tracker, batch);
1102}
1103
1104void MetadataDatabase::MakeAppRootDisabled(int64 tracker_id,
1105                                           leveldb::WriteBatch* batch) {
1106  FileTracker* tracker = tracker_by_id_[tracker_id];
1107  DCHECK(tracker);
1108  DCHECK_EQ(TRACKER_KIND_APP_ROOT, tracker->tracker_kind());
1109  DCHECK(tracker->active());
1110
1111  // Keep the app-root tracker active (but change the tracker_kind) so that
1112  // other conflicting trackers won't become active.
1113  tracker->set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT);
1114  PutTrackerToBatch(*tracker, batch);
1115}
1116
1117void MetadataDatabase::MakeAppRootEnabled(int64 tracker_id,
1118                                          leveldb::WriteBatch* batch) {
1119  FileTracker* tracker = tracker_by_id_[tracker_id];
1120  DCHECK(tracker);
1121  DCHECK_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker->tracker_kind());
1122  DCHECK(tracker->active());
1123
1124  tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT);
1125  // Mark descendant trackers as dirty to handle changes in disable period.
1126  RecursiveMarkTrackerAsDirty(tracker_id, batch);
1127  PutTrackerToBatch(*tracker, batch);
1128}
1129
1130void MetadataDatabase::CreateTrackerForParentAndFileID(
1131    const FileTracker& parent_tracker,
1132    const std::string& file_id,
1133    leveldb::WriteBatch* batch) {
1134  int64 tracker_id = GetNextTrackerID(batch);
1135  scoped_ptr<FileTracker> tracker(new FileTracker);
1136  tracker->set_tracker_id(tracker_id);
1137  tracker->set_parent_tracker_id(parent_tracker.tracker_id());
1138  tracker->set_file_id(file_id);
1139  tracker->set_app_id(parent_tracker.app_id());
1140  tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
1141  tracker->set_dirty(true);
1142  tracker->set_active(false);
1143  tracker->set_needs_folder_listing(false);
1144  PutTrackerToBatch(*tracker, batch);
1145
1146  trackers_by_file_id_[file_id].Insert(tracker.get());
1147  // Note: |trackers_by_parent_and_title_| does not map from
1148  // FileMetadata::details but from FileTracker::synced_details, which is filled
1149  // on tracker updated phase.  Use empty string as the title since
1150  // FileTracker::synced_details is empty here.
1151  trackers_by_parent_and_title_[parent_tracker.tracker_id()][std::string()]
1152      .Insert(tracker.get());
1153  dirty_trackers_.insert(tracker.get());
1154  DCHECK(!ContainsKey(tracker_by_id_, tracker_id));
1155  tracker_by_id_[tracker_id] = tracker.release();
1156}
1157
1158void MetadataDatabase::RemoveTracker(int64 tracker_id,
1159                                     leveldb::WriteBatch* batch) {
1160  RemoveTrackerInternal(tracker_id, batch, false);
1161}
1162
1163void MetadataDatabase::RemoveTrackerIgnoringSiblings(
1164    int64 tracker_id,
1165    leveldb::WriteBatch* batch) {
1166  RemoveTrackerInternal(tracker_id, batch, true);
1167}
1168
1169void MetadataDatabase::RemoveTrackerInternal(
1170    int64 tracker_id,
1171    leveldb::WriteBatch* batch,
1172    bool ignoring_siblings) {
1173  scoped_ptr<FileTracker> tracker(
1174      FindAndEraseItem(&tracker_by_id_, tracker_id));
1175  if (!tracker)
1176    return;
1177
1178  EraseTrackerFromFileIDIndex(tracker.get(), batch);
1179  if (IsAppRoot(*tracker))
1180    app_root_by_app_id_.erase(tracker->app_id());
1181  EraseTrackerFromPathIndex(tracker.get());
1182
1183  MarkTrackersDirtyByFileID(tracker->file_id(), batch);
1184  if (!ignoring_siblings) {
1185    MarkTrackersDirtyByPath(tracker->parent_tracker_id(),
1186                            GetTrackerTitle(*tracker),
1187                            batch);
1188  }
1189  PutTrackerDeletionToBatch(tracker_id, batch);
1190}
1191
1192void MetadataDatabase::MaybeAddTrackersForNewFile(
1193    const FileMetadata& file,
1194    leveldb::WriteBatch* batch) {
1195  std::set<int64> known_parents;
1196  TrackersByFileID::iterator found = trackers_by_file_id_.find(file.file_id());
1197  if (found != trackers_by_file_id_.end()) {
1198    for (TrackerSet::const_iterator itr = found->second.begin();
1199         itr != found->second.end(); ++itr) {
1200      int64 parent_tracker_id = (*itr)->parent_tracker_id();
1201      if (parent_tracker_id)
1202        known_parents.insert(parent_tracker_id);
1203    }
1204  }
1205
1206  for (int i = 0; i < file.details().parent_folder_ids_size(); ++i) {
1207    std::string parent_folder_id = file.details().parent_folder_ids(i);
1208    TrackersByFileID::iterator found =
1209        trackers_by_file_id_.find(parent_folder_id);
1210    if (found == trackers_by_file_id_.end())
1211      continue;
1212
1213    for (TrackerSet::const_iterator itr = found->second.begin();
1214         itr != found->second.end(); ++itr) {
1215      FileTracker* parent_tracker = *itr;
1216      int64 parent_tracker_id = parent_tracker->tracker_id();
1217      if (!parent_tracker->active())
1218        continue;
1219
1220      if (ContainsKey(known_parents, parent_tracker_id))
1221        continue;
1222
1223      CreateTrackerForParentAndFileID(*parent_tracker, file.file_id(), batch);
1224    }
1225  }
1226}
1227
1228void MetadataDatabase::RemoveAllDescendantTrackers(int64 root_tracker_id,
1229                                                   leveldb::WriteBatch* batch) {
1230  std::vector<int64> pending_trackers;
1231  PushChildTrackersToContainer(trackers_by_parent_and_title_,
1232                               root_tracker_id,
1233                               std::back_inserter(pending_trackers));
1234
1235  while (!pending_trackers.empty()) {
1236    int64 tracker_id = pending_trackers.back();
1237    pending_trackers.pop_back();
1238    PushChildTrackersToContainer(trackers_by_parent_and_title_,
1239                                 tracker_id,
1240                                 std::back_inserter(pending_trackers));
1241    RemoveTrackerIgnoringSiblings(tracker_id, batch);
1242  }
1243}
1244
1245void MetadataDatabase::EraseTrackerFromFileIDIndex(FileTracker* tracker,
1246                                                   leveldb::WriteBatch* batch) {
1247  TrackersByFileID::iterator found =
1248      trackers_by_file_id_.find(tracker->file_id());
1249  if (found == trackers_by_file_id_.end())
1250    return;
1251
1252  TrackerSet* trackers = &found->second;
1253  trackers->Erase(tracker);
1254  if (!trackers->tracker_set().empty())
1255    return;
1256  trackers_by_file_id_.erase(found);
1257  EraseFileFromDatabase(tracker->file_id(), batch);
1258}
1259
1260void MetadataDatabase::EraseFileFromDatabase(const std::string& file_id,
1261                                             leveldb::WriteBatch* batch) {
1262  scoped_ptr<FileMetadata> file(FindAndEraseItem(&file_by_id_, file_id));
1263  if (file)
1264    PutFileDeletionToBatch(file_id, batch);
1265}
1266
1267void MetadataDatabase::EraseTrackerFromPathIndex(FileTracker* tracker) {
1268  TrackersByParentAndTitle::iterator found =
1269      trackers_by_parent_and_title_.find(tracker->parent_tracker_id());
1270  if (found == trackers_by_parent_and_title_.end())
1271    return;
1272
1273  std::string title = GetTrackerTitle(*tracker);
1274  TrackersByTitle* trackers_by_title = &found->second;
1275  TrackersByTitle::iterator found_by_title = trackers_by_title->find(title);
1276  TrackerSet* conflicting_trackers = &found_by_title->second;
1277  conflicting_trackers->Erase(tracker);
1278
1279  if (conflicting_trackers->tracker_set().empty()) {
1280    trackers_by_title->erase(found_by_title);
1281    if (trackers_by_title->empty())
1282      trackers_by_parent_and_title_.erase(found);
1283  }
1284}
1285
1286void MetadataDatabase::MarkTrackerSetDirty(
1287    TrackerSet* trackers,
1288    leveldb::WriteBatch* batch) {
1289  for (TrackerSet::iterator itr = trackers->begin();
1290       itr != trackers->end(); ++itr) {
1291    FileTracker* tracker = *itr;
1292    if (tracker->dirty())
1293      continue;
1294    tracker->set_dirty(true);
1295    PutTrackerToBatch(*tracker, batch);
1296    dirty_trackers_.insert(tracker);
1297  }
1298}
1299
1300void MetadataDatabase::MarkTrackersDirtyByFileID(
1301    const std::string& file_id,
1302    leveldb::WriteBatch* batch) {
1303  TrackersByFileID::iterator found = trackers_by_file_id_.find(file_id);
1304  if (found != trackers_by_file_id_.end())
1305    MarkTrackerSetDirty(&found->second, batch);
1306}
1307
1308void MetadataDatabase::MarkTrackersDirtyByPath(int64 parent_tracker_id,
1309                                               const std::string& title,
1310                                               leveldb::WriteBatch* batch) {
1311  TrackersByParentAndTitle::iterator found =
1312      trackers_by_parent_and_title_.find(parent_tracker_id);
1313  if (found == trackers_by_parent_and_title_.end()) {
1314    NOTREACHED() << "parent: " << parent_tracker_id
1315                 << ", title: " << title;
1316    return;
1317  }
1318
1319  TrackersByTitle::iterator itr = found->second.find(title);
1320  if (itr != found->second.end())
1321    MarkTrackerSetDirty(&itr->second, batch);
1322}
1323
1324int64 MetadataDatabase::GetNextTrackerID(leveldb::WriteBatch* batch) {
1325  int64 tracker_id = service_metadata_->next_tracker_id();
1326  service_metadata_->set_next_tracker_id(tracker_id + 1);
1327  PutServiceMetadataToBatch(*service_metadata_, batch);
1328  DCHECK_GT(tracker_id, 0);
1329  return tracker_id;
1330}
1331
1332void MetadataDatabase::RecursiveMarkTrackerAsDirty(int64 root_tracker_id,
1333                                                   leveldb::WriteBatch* batch) {
1334  std::vector<int64> stack;
1335  stack.push_back(root_tracker_id);
1336  while (!stack.empty()) {
1337    int64 tracker_id = stack.back();
1338    stack.pop_back();
1339    PushChildTrackersToContainer(
1340        trackers_by_parent_and_title_, tracker_id, std::back_inserter(stack));
1341
1342    FileTracker* tracker = tracker_by_id_[tracker_id];
1343    if (!tracker->dirty()) {
1344      tracker->set_dirty(true);
1345      PutTrackerToBatch(*tracker, batch);
1346      dirty_trackers_.insert(tracker);
1347    }
1348  }
1349}
1350
1351bool MetadataDatabase::CanActivateTracker(const FileTracker& tracker) {
1352  DCHECK(!tracker.active());
1353  DCHECK_NE(service_metadata_->sync_root_tracker_id(), tracker.tracker_id());
1354
1355  if (HasActiveTrackerForFileID(tracker.file_id()))
1356    return false;
1357
1358  if (tracker.app_id().empty())
1359    return false;
1360  if (!tracker.has_synced_details())
1361    return false;
1362  DCHECK(tracker.parent_tracker_id());
1363
1364  return !HasActiveTrackerForPath(tracker.parent_tracker_id(),
1365                                  tracker.synced_details().title());
1366}
1367
1368bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const {
1369  if (HasDisabledAppRoot(tracker))
1370    return false;
1371
1372  DCHECK(tracker.dirty());
1373  if (!tracker.has_synced_details())
1374    return true;
1375
1376  FileByID::const_iterator found = file_by_id_.find(tracker.file_id());
1377  if (found == file_by_id_.end())
1378    return true;
1379  const FileMetadata* file = found->second;
1380  DCHECK(file);
1381
1382  if (tracker.active()) {
1383    if (tracker.needs_folder_listing())
1384      return true;
1385    if (tracker.synced_details().md5() != file->details().md5())
1386      return true;
1387  }
1388
1389  const FileDetails& local_details = tracker.synced_details();
1390  const FileDetails& remote_details = file->details();
1391
1392  if (local_details.title() != remote_details.title())
1393    return true;
1394  if (local_details.deleted() != remote_details.deleted())
1395    return true;
1396
1397  return false;
1398}
1399
1400bool MetadataDatabase::HasDisabledAppRoot(const FileTracker& tracker) const {
1401  TrackerByAppID::const_iterator found =
1402      app_root_by_app_id_.find(tracker.app_id());
1403  if (found == app_root_by_app_id_.end())
1404    return false;
1405
1406  const FileTracker* app_root_tracker = found->second;
1407  DCHECK(app_root_tracker);
1408  return app_root_tracker->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT;
1409}
1410
1411bool MetadataDatabase::HasActiveTrackerForFileID(
1412    const std::string& file_id) const {
1413  TrackersByFileID::const_iterator found = trackers_by_file_id_.find(file_id);
1414  return found != trackers_by_file_id_.end() && found->second.has_active();
1415}
1416
1417bool MetadataDatabase::HasActiveTrackerForPath(int64 parent_tracker_id,
1418                                               const std::string& title) const {
1419  TrackersByParentAndTitle::const_iterator found_by_parent =
1420      trackers_by_parent_and_title_.find(parent_tracker_id);
1421  if (found_by_parent == trackers_by_parent_and_title_.end())
1422    return false;
1423
1424  const TrackersByTitle& trackers_by_title = found_by_parent->second;
1425  TrackersByTitle::const_iterator found = trackers_by_title.find(title);
1426  return found != trackers_by_title.end() && found->second.has_active();
1427}
1428
1429void MetadataDatabase::UpdateTrackerTitle(FileTracker* tracker,
1430                                          const std::string& new_title,
1431                                          leveldb::WriteBatch* batch) {
1432  int64 parent_id = tracker->parent_tracker_id();
1433  std::string old_title = GetTrackerTitle(*tracker);
1434  DCHECK_NE(old_title, new_title);
1435  DCHECK(!new_title.empty());
1436
1437  TrackersByTitle* trackers_by_title =
1438      &trackers_by_parent_and_title_[parent_id];
1439  TrackerSet* old_siblings = &(*trackers_by_title)[old_title];
1440  TrackerSet* new_siblings = &(*trackers_by_title)[new_title];
1441
1442  old_siblings->Erase(tracker);
1443  if (old_siblings->empty())
1444    trackers_by_title->erase(old_title);
1445  else
1446    MarkTrackerSetDirty(old_siblings, batch);
1447
1448  if (tracker->active() && new_siblings->has_active()) {
1449    // Inactivate existing active tracker.
1450    FileTracker* obstacle = new_siblings->active_tracker();
1451    new_siblings->Inactivate(obstacle);
1452    DCHECK_EQ(TRACKER_KIND_REGULAR, obstacle->tracker_kind());
1453
1454    TrackerSet* same_file_id_trackers_to_obstacle =
1455        &trackers_by_file_id_[obstacle->file_id()];
1456    same_file_id_trackers_to_obstacle->Inactivate(obstacle);
1457    MarkTrackerSetDirty(same_file_id_trackers_to_obstacle, batch);
1458
1459    obstacle->set_active(false);
1460    PutTrackerToBatch(*obstacle, batch);
1461
1462    RemoveAllDescendantTrackers(obstacle->tracker_id(), batch);
1463  }
1464
1465  tracker->mutable_synced_details()->set_title(new_title);
1466  new_siblings->Insert(tracker);
1467  PutTrackerToBatch(*tracker, batch);
1468}
1469
1470void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch,
1471                                       const SyncStatusCallback& callback) {
1472  base::PostTaskAndReplyWithResult(
1473      task_runner_.get(),
1474      FROM_HERE,
1475      base::Bind(&leveldb::DB::Write,
1476                 base::Unretained(db_.get()),
1477                 leveldb::WriteOptions(),
1478                 base::Owned(batch.release())),
1479      base::Bind(&AdaptLevelDBStatusToSyncStatusCode, callback));
1480}
1481
1482}  // namespace drive_backend
1483}  // namespace sync_file_system
1484