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