Home | History | Annotate | Download | only in drive_backend_v1
      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_v1/drive_metadata_store.h"
      6 
      7 #include <utility>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/callback.h"
     12 #include "base/files/file_path.h"
     13 #include "base/location.h"
     14 #include "base/message_loop/message_loop_proxy.h"
     15 #include "base/sequenced_task_runner.h"
     16 #include "base/stl_util.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "base/strings/string_util.h"
     19 #include "base/strings/stringprintf.h"
     20 #include "base/task_runner_util.h"
     21 #include "base/values.h"
     22 #include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h"
     23 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h"
     24 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_util.h"
     25 #include "chrome/browser/sync_file_system/logger.h"
     26 #include "chrome/browser/sync_file_system/sync_file_system.pb.h"
     27 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     28 #include "third_party/leveldatabase/src/include/leveldb/db.h"
     29 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
     30 #include "url/gurl.h"
     31 #include "webkit/browser/fileapi/file_system_url.h"
     32 #include "webkit/common/fileapi/file_system_util.h"
     33 
     34 using fileapi::FileSystemURL;
     35 
     36 namespace sync_file_system {
     37 
     38 typedef DriveMetadataStore::MetadataMap MetadataMap;
     39 typedef DriveMetadataStore::OriginByResourceId OriginByResourceId;
     40 typedef DriveMetadataStore::PathToMetadata PathToMetadata;
     41 typedef DriveMetadataStore::ResourceIdByOrigin ResourceIdByOrigin;
     42 
     43 const base::FilePath::CharType DriveMetadataStore::kDatabaseName[] =
     44     FILE_PATH_LITERAL("DriveMetadata");
     45 
     46 struct DBContents {
     47   SyncStatusCode status;
     48   scoped_ptr<leveldb::DB> db;
     49   bool created;
     50 
     51   int64 largest_changestamp;
     52   DriveMetadataStore::MetadataMap metadata_map;
     53   std::string sync_root_directory_resource_id;
     54   ResourceIdByOrigin incremental_sync_origins;
     55   ResourceIdByOrigin disabled_origins;
     56 
     57   DBContents()
     58       : status(SYNC_STATUS_UNKNOWN),
     59         created(false),
     60         largest_changestamp(0) {
     61   }
     62 };
     63 
     64 namespace {
     65 
     66 const char kDatabaseVersionKey[] = "VERSION";
     67 const int64 kCurrentDatabaseVersion = 2;
     68 const char kChangeStampKey[] = "CHANGE_STAMP";
     69 const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR";
     70 const char kDriveMetadataKeyPrefix[] = "METADATA: ";
     71 const char kMetadataKeySeparator = ' ';
     72 const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: ";
     73 const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: ";
     74 
     75 enum OriginSyncType {
     76   INCREMENTAL_SYNC_ORIGIN,
     77   DISABLED_ORIGIN
     78 };
     79 
     80 std::string RemovePrefix(const std::string& str, const std::string& prefix) {
     81   if (StartsWithASCII(str, prefix, true))
     82     return str.substr(prefix.size());
     83   return str;
     84 }
     85 
     86 std::string OriginAndPathToMetadataKey(const GURL& origin,
     87                                        const base::FilePath& path) {
     88   return kDriveMetadataKeyPrefix + origin.spec() +
     89       kMetadataKeySeparator + path.AsUTF8Unsafe();
     90 }
     91 
     92 std::string FileSystemURLToMetadataKey(const FileSystemURL& url) {
     93   return OriginAndPathToMetadataKey(url.origin(), url.path());
     94 }
     95 
     96 void MetadataKeyToOriginAndPath(const std::string& metadata_key,
     97                                 GURL* origin,
     98                                 base::FilePath* path) {
     99   std::string key_body(RemovePrefix(metadata_key, kDriveMetadataKeyPrefix));
    100   size_t separator_position = key_body.find(kMetadataKeySeparator);
    101   *origin = GURL(key_body.substr(0, separator_position));
    102   *path = base::FilePath::FromUTF8Unsafe(
    103       key_body.substr(separator_position + 1));
    104 }
    105 
    106 bool UpdateResourceIdMap(ResourceIdByOrigin* map,
    107                          OriginByResourceId* reverse_map,
    108                          const GURL& origin,
    109                          const std::string& resource_id) {
    110   ResourceIdByOrigin::iterator found = map->find(origin);
    111   if (found == map->end())
    112     return false;
    113   reverse_map->erase(found->second);
    114   reverse_map->insert(std::make_pair(resource_id, origin));
    115 
    116   found->second = resource_id;
    117   return true;
    118 }
    119 
    120 ////////////////////////////////////////////////////////////////////////////////
    121 
    122 bool IsDBEmpty(leveldb::DB* db) {
    123   DCHECK(db);
    124   scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
    125   itr->SeekToFirst();
    126   return !itr->Valid();
    127 }
    128 
    129 scoped_ptr<leveldb::DB> OpenDatabase(const base::FilePath& path,
    130                                      SyncStatusCode* status,
    131                                      bool* created) {
    132   DCHECK(status);
    133   DCHECK(created);
    134 
    135   leveldb::Options options;
    136   options.max_open_files = 0;  // Use minimum.
    137   options.create_if_missing = true;
    138   leveldb::DB* db = NULL;
    139   leveldb::Status db_status = leveldb::DB::Open(
    140       options, path.AsUTF8Unsafe(), &db);
    141   if (db_status.ok()) {
    142     *created = IsDBEmpty(db);
    143   } else {
    144     delete db;
    145     db = NULL;
    146   }
    147   *status = LevelDBStatusToSyncStatusCode(db_status);
    148 
    149   return make_scoped_ptr(db);
    150 }
    151 
    152 SyncStatusCode WriteInitialData(leveldb::DB* db) {
    153   DCHECK(db);
    154   return LevelDBStatusToSyncStatusCode(db->Put(
    155       leveldb::WriteOptions(),
    156       kDatabaseVersionKey,
    157       base::Int64ToString(kCurrentDatabaseVersion)));
    158 }
    159 
    160 SyncStatusCode MigrateDatabaseIfNeeded(leveldb::DB* db) {
    161   DCHECK(db);
    162   std::string value;
    163   leveldb::Status status = db->Get(leveldb::ReadOptions(),
    164                                    kDatabaseVersionKey, &value);
    165   int64 version = 0;
    166   if (status.ok()) {
    167     if (!base::StringToInt64(value, &version))
    168       return SYNC_DATABASE_ERROR_FAILED;
    169   } else {
    170     if (!status.IsNotFound())
    171       return SYNC_DATABASE_ERROR_FAILED;
    172   }
    173 
    174   switch (version) {
    175     case 0:
    176       drive_backend::MigrateDatabaseFromV0ToV1(db);
    177       // fall-through
    178     case 1:
    179       drive_backend::MigrateDatabaseFromV1ToV2(db);
    180       // fall-through
    181     case 2:
    182       DCHECK_EQ(2, kCurrentDatabaseVersion);
    183       return SYNC_STATUS_OK;
    184     default:
    185       return SYNC_DATABASE_ERROR_FAILED;
    186   }
    187 }
    188 
    189 SyncStatusCode ReadContents(DBContents* contents) {
    190   DCHECK(contents);
    191   DCHECK(contents->db);
    192 
    193   contents->largest_changestamp = 0;
    194   contents->metadata_map.clear();
    195   contents->incremental_sync_origins.clear();
    196 
    197   scoped_ptr<leveldb::Iterator> itr(
    198       contents->db->NewIterator(leveldb::ReadOptions()));
    199   for (itr->SeekToFirst(); itr->Valid(); itr->Next()) {
    200     std::string key = itr->key().ToString();
    201     if (key == kChangeStampKey) {
    202       bool success = base::StringToInt64(itr->value().ToString(),
    203                                          &contents->largest_changestamp);
    204       DCHECK(success);
    205       continue;
    206     }
    207 
    208     if (key == kSyncRootDirectoryKey) {
    209       std::string resource_id = itr->value().ToString();
    210       if (IsDriveAPIDisabled())
    211         resource_id = drive_backend::AddWapiFolderPrefix(resource_id);
    212       contents->sync_root_directory_resource_id = resource_id;
    213       continue;
    214     }
    215 
    216     if (StartsWithASCII(key, kDriveMetadataKeyPrefix, true)) {
    217       GURL origin;
    218       base::FilePath path;
    219       MetadataKeyToOriginAndPath(key, &origin, &path);
    220 
    221       DriveMetadata metadata;
    222       bool success = metadata.ParseFromString(itr->value().ToString());
    223       DCHECK(success);
    224 
    225       if (IsDriveAPIDisabled()) {
    226         metadata.set_resource_id(drive_backend::AddWapiIdPrefix(
    227             metadata.resource_id(), metadata.type()));
    228       }
    229 
    230       success = contents->metadata_map[origin].insert(
    231           std::make_pair(path, metadata)).second;
    232       DCHECK(success);
    233       continue;
    234     }
    235 
    236     if (StartsWithASCII(key, kDriveIncrementalSyncOriginKeyPrefix, true)) {
    237       GURL origin(RemovePrefix(key, kDriveIncrementalSyncOriginKeyPrefix));
    238       DCHECK(origin.is_valid());
    239 
    240       std::string origin_resource_id = IsDriveAPIDisabled()
    241           ? drive_backend::AddWapiFolderPrefix(itr->value().ToString())
    242           : itr->value().ToString();
    243 
    244       DCHECK(!ContainsKey(contents->incremental_sync_origins, origin));
    245       contents->incremental_sync_origins[origin] = origin_resource_id;
    246       continue;
    247     }
    248 
    249     if (StartsWithASCII(key, kDriveDisabledOriginKeyPrefix, true)) {
    250       GURL origin(RemovePrefix(key, kDriveDisabledOriginKeyPrefix));
    251       DCHECK(origin.is_valid());
    252 
    253       std::string origin_resource_id = IsDriveAPIDisabled()
    254           ? drive_backend::AddWapiFolderPrefix(itr->value().ToString())
    255           : itr->value().ToString();
    256 
    257       DCHECK(!ContainsKey(contents->disabled_origins, origin));
    258       contents->disabled_origins[origin] = origin_resource_id;
    259       continue;
    260     }
    261   }
    262 
    263   return SYNC_STATUS_OK;
    264 }
    265 
    266 scoped_ptr<DBContents> LoadDBContents(const base::FilePath& db_path) {
    267   scoped_ptr<DBContents> contents(new DBContents);
    268   contents->db = OpenDatabase(db_path,
    269                               &contents->status,
    270                               &contents->created);
    271   if (contents->status != SYNC_STATUS_OK)
    272     return contents.Pass();
    273 
    274   if (contents->created) {
    275     contents->status = WriteInitialData(contents->db.get());
    276     if (contents->status != SYNC_STATUS_OK)
    277       return contents.Pass();
    278   } else {
    279     contents->status = MigrateDatabaseIfNeeded(contents->db.get());
    280     if (contents->status != SYNC_STATUS_OK)
    281       return contents.Pass();
    282   }
    283 
    284   contents->status = ReadContents(contents.get());
    285   return contents.Pass();
    286 }
    287 
    288 ////////////////////////////////////////////////////////////////////////////////
    289 
    290 // Returns a key string for the given origin.
    291 // For example, when |origin| is "http://www.example.com" and |sync_type| is
    292 // BATCH_SYNC_ORIGIN, returns "BSYNC_ORIGIN: http://www.example.com".
    293 std::string CreateKeyForOriginRoot(const GURL& origin,
    294                                    OriginSyncType sync_type) {
    295   DCHECK(origin.is_valid());
    296   switch (sync_type) {
    297     case INCREMENTAL_SYNC_ORIGIN:
    298       return kDriveIncrementalSyncOriginKeyPrefix + origin.spec();
    299     case DISABLED_ORIGIN:
    300       return kDriveDisabledOriginKeyPrefix + origin.spec();
    301   }
    302   NOTREACHED();
    303   return std::string();
    304 }
    305 
    306 void AddOriginsToVector(std::vector<GURL>* all_origins,
    307                         const ResourceIdByOrigin& resource_map) {
    308   for (ResourceIdByOrigin::const_iterator itr = resource_map.begin();
    309        itr != resource_map.end();
    310        ++itr) {
    311     all_origins->push_back(itr->first);
    312   }
    313 }
    314 
    315 void InsertReverseMap(const ResourceIdByOrigin& forward_map,
    316                       OriginByResourceId* backward_map) {
    317   for (ResourceIdByOrigin::const_iterator itr = forward_map.begin();
    318        itr != forward_map.end(); ++itr)
    319     backward_map->insert(std::make_pair(itr->second, itr->first));
    320 }
    321 
    322 bool EraseIfExists(ResourceIdByOrigin* map,
    323                    const GURL& origin,
    324                    std::string* resource_id) {
    325   ResourceIdByOrigin::iterator found = map->find(origin);
    326   if (found == map->end())
    327     return false;
    328   *resource_id = found->second;
    329   map->erase(found);
    330   return true;
    331 }
    332 
    333 void AppendMetadataDeletionToBatch(const MetadataMap& metadata_map,
    334                                    const GURL& origin,
    335                                    leveldb::WriteBatch* batch) {
    336   MetadataMap::const_iterator found = metadata_map.find(origin);
    337   if (found == metadata_map.end())
    338     return;
    339 
    340   for (PathToMetadata::const_iterator itr = found->second.begin();
    341        itr != found->second.end(); ++itr)
    342     batch->Delete(OriginAndPathToMetadataKey(origin, itr->first));
    343 }
    344 
    345 std::string DriveTypeToString(DriveMetadata_ResourceType drive_type) {
    346   switch (drive_type) {
    347     case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE:
    348       return "file";
    349     case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER:
    350       return "folder";
    351   }
    352 
    353   NOTREACHED();
    354   return "unknown";
    355 }
    356 
    357 }  // namespace
    358 
    359 DriveMetadataStore::DriveMetadataStore(
    360     const base::FilePath& base_dir,
    361     base::SequencedTaskRunner* file_task_runner)
    362     : file_task_runner_(file_task_runner),
    363       base_dir_(base_dir),
    364       db_status_(SYNC_STATUS_UNKNOWN),
    365       largest_changestamp_(0) {
    366   DCHECK(file_task_runner);
    367 }
    368 
    369 DriveMetadataStore::~DriveMetadataStore() {
    370   DCHECK(CalledOnValidThread());
    371   file_task_runner_->DeleteSoon(FROM_HERE, db_.release());
    372 }
    373 
    374 void DriveMetadataStore::Initialize(const InitializationCallback& callback) {
    375   DCHECK(CalledOnValidThread());
    376   base::PostTaskAndReplyWithResult(
    377       file_task_runner_.get(), FROM_HERE,
    378       base::Bind(&LoadDBContents, base_dir_.Append(kDatabaseName)),
    379       base::Bind(&DriveMetadataStore::DidInitialize, AsWeakPtr(), callback));
    380 }
    381 
    382 void DriveMetadataStore::DidInitialize(const InitializationCallback& callback,
    383                                        scoped_ptr<DBContents> contents) {
    384   DCHECK(CalledOnValidThread());
    385   DCHECK(contents);
    386 
    387   db_status_ = contents->status;
    388   if (db_status_ != SYNC_STATUS_OK) {
    389     callback.Run(db_status_, false);
    390     file_task_runner_->DeleteSoon(FROM_HERE, contents.release());
    391     return;
    392   }
    393 
    394   db_ = contents->db.Pass();
    395   largest_changestamp_ = contents->largest_changestamp;
    396   metadata_map_.swap(contents->metadata_map);
    397   sync_root_directory_resource_id_ = contents->sync_root_directory_resource_id;
    398   incremental_sync_origins_.swap(contents->incremental_sync_origins);
    399   disabled_origins_.swap(contents->disabled_origins);
    400 
    401   origin_by_resource_id_.clear();
    402   InsertReverseMap(incremental_sync_origins_, &origin_by_resource_id_);
    403   InsertReverseMap(disabled_origins_, &origin_by_resource_id_);
    404 
    405   callback.Run(db_status_, contents->created);
    406 }
    407 
    408 void DriveMetadataStore::SetLargestChangeStamp(
    409     int64 largest_changestamp,
    410     const SyncStatusCallback& callback) {
    411   DCHECK(CalledOnValidThread());
    412   DCHECK_EQ(SYNC_STATUS_OK, db_status_);
    413   largest_changestamp_ = largest_changestamp;
    414 
    415   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    416   batch->Put(kChangeStampKey, base::Int64ToString(largest_changestamp));
    417   return WriteToDB(batch.Pass(), callback);
    418 }
    419 
    420 int64 DriveMetadataStore::GetLargestChangeStamp() const {
    421   DCHECK(CalledOnValidThread());
    422   DCHECK_EQ(SYNC_STATUS_OK, db_status_);
    423   return largest_changestamp_;
    424 }
    425 
    426 void DriveMetadataStore::UpdateEntry(
    427     const FileSystemURL& url,
    428     const DriveMetadata& metadata,
    429     const SyncStatusCallback& callback) {
    430   DCHECK(CalledOnValidThread());
    431   DCHECK_EQ(SYNC_STATUS_OK, db_status_);
    432   DCHECK(!metadata.conflicted() || !metadata.to_be_fetched());
    433 
    434   std::pair<PathToMetadata::iterator, bool> result =
    435       metadata_map_[url.origin()].insert(std::make_pair(url.path(), metadata));
    436   if (!result.second)
    437     result.first->second = metadata;
    438 
    439   std::string value;
    440   if (IsDriveAPIDisabled()) {
    441     DriveMetadata metadata_in_db(metadata);
    442     metadata_in_db.set_resource_id(
    443         drive_backend::RemoveWapiIdPrefix(metadata.resource_id()));
    444     bool success = metadata_in_db.SerializeToString(&value);
    445     DCHECK(success);
    446   } else {
    447     bool success = metadata.SerializeToString(&value);
    448     DCHECK(success);
    449   }
    450 
    451   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    452   batch->Put(FileSystemURLToMetadataKey(url), value);
    453   WriteToDB(batch.Pass(), callback);
    454 }
    455 
    456 void DriveMetadataStore::DeleteEntry(
    457     const FileSystemURL& url,
    458     const SyncStatusCallback& callback) {
    459   DCHECK(CalledOnValidThread());
    460   MetadataMap::iterator found = metadata_map_.find(url.origin());
    461   if (found == metadata_map_.end()) {
    462     RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
    463     return;
    464   }
    465 
    466   if (found->second.erase(url.path()) == 1) {
    467     scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    468     batch->Delete(FileSystemURLToMetadataKey(url));
    469     WriteToDB(batch.Pass(), callback);
    470     return;
    471   }
    472 
    473   RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
    474 }
    475 
    476 SyncStatusCode DriveMetadataStore::ReadEntry(const FileSystemURL& url,
    477                                              DriveMetadata* metadata) const {
    478   DCHECK(CalledOnValidThread());
    479   DCHECK(metadata);
    480 
    481   MetadataMap::const_iterator found_origin = metadata_map_.find(url.origin());
    482   if (found_origin == metadata_map_.end())
    483     return SYNC_DATABASE_ERROR_NOT_FOUND;
    484 
    485   PathToMetadata::const_iterator found = found_origin->second.find(url.path());
    486   if (found == found_origin->second.end())
    487     return SYNC_DATABASE_ERROR_NOT_FOUND;
    488 
    489   *metadata = found->second;
    490   return SYNC_STATUS_OK;
    491 }
    492 
    493 void DriveMetadataStore::AddIncrementalSyncOrigin(
    494     const GURL& origin,
    495     const std::string& resource_id) {
    496   DCHECK(CalledOnValidThread());
    497   DCHECK(!IsIncrementalSyncOrigin(origin));
    498   DCHECK(!IsOriginDisabled(origin));
    499   DCHECK_EQ(SYNC_STATUS_OK, db_status_);
    500 
    501   incremental_sync_origins_.insert(std::make_pair(origin, resource_id));
    502   origin_by_resource_id_.insert(std::make_pair(resource_id, origin));
    503 
    504   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    505   batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN));
    506   batch->Put(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN),
    507              drive_backend::RemoveWapiIdPrefix(resource_id));
    508   WriteToDB(batch.Pass(),
    509             base::Bind(&DriveMetadataStore::UpdateDBStatus, AsWeakPtr()));
    510 }
    511 
    512 void DriveMetadataStore::SetSyncRootDirectory(const std::string& resource_id) {
    513   DCHECK(CalledOnValidThread());
    514 
    515   sync_root_directory_resource_id_ = resource_id;
    516 
    517   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    518   batch->Put(kSyncRootDirectoryKey,
    519              drive_backend::RemoveWapiIdPrefix(resource_id));
    520   return WriteToDB(batch.Pass(),
    521                    base::Bind(&DriveMetadataStore::UpdateDBStatus,
    522                               AsWeakPtr()));
    523 }
    524 
    525 void DriveMetadataStore::SetOriginRootDirectory(
    526     const GURL& origin,
    527     const std::string& resource_id) {
    528   DCHECK(CalledOnValidThread());
    529   DCHECK(IsKnownOrigin(origin));
    530 
    531   OriginSyncType sync_type;
    532   if (UpdateResourceIdMap(
    533       &incremental_sync_origins_, &origin_by_resource_id_,
    534       origin, resource_id)) {
    535     sync_type = INCREMENTAL_SYNC_ORIGIN;
    536   } else if (UpdateResourceIdMap(&disabled_origins_, &origin_by_resource_id_,
    537                                  origin, resource_id)) {
    538     sync_type = DISABLED_ORIGIN;
    539   } else {
    540     return;
    541   }
    542 
    543   std::string key = CreateKeyForOriginRoot(origin, sync_type);
    544   DCHECK(!key.empty());
    545 
    546   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    547   batch->Put(key, drive_backend::RemoveWapiIdPrefix(resource_id));
    548   WriteToDB(batch.Pass(),
    549             base::Bind(&DriveMetadataStore::UpdateDBStatus, AsWeakPtr()));
    550 }
    551 
    552 bool DriveMetadataStore::IsKnownOrigin(const GURL& origin) const {
    553   DCHECK(CalledOnValidThread());
    554   return IsIncrementalSyncOrigin(origin) || IsOriginDisabled(origin);
    555 }
    556 
    557 bool DriveMetadataStore::IsIncrementalSyncOrigin(const GURL& origin) const {
    558   DCHECK(CalledOnValidThread());
    559   return ContainsKey(incremental_sync_origins_, origin);
    560 }
    561 
    562 bool DriveMetadataStore::IsOriginDisabled(const GURL& origin) const {
    563   DCHECK(CalledOnValidThread());
    564   return ContainsKey(disabled_origins_, origin);
    565 }
    566 
    567 void DriveMetadataStore::EnableOrigin(
    568     const GURL& origin,
    569     const SyncStatusCallback& callback) {
    570   DCHECK(CalledOnValidThread());
    571 
    572   std::map<GURL, std::string>::iterator found = disabled_origins_.find(origin);
    573   if (found == disabled_origins_.end()) {
    574     RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
    575     // |origin| has not been registered yet.
    576     return;
    577   }
    578   disabled_origins_.erase(found);
    579 
    580   // |origin| goes back to DriveFileSyncService::pending_batch_sync_origins_
    581   // only and is not stored in drive_metadata_store.
    582   found = incremental_sync_origins_.find(origin);
    583   if (found != incremental_sync_origins_.end())
    584     incremental_sync_origins_.erase(found);
    585 
    586   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    587   batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN));
    588   batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN));
    589   WriteToDB(batch.Pass(), callback);
    590 }
    591 
    592 void DriveMetadataStore::DisableOrigin(
    593     const GURL& origin,
    594     const SyncStatusCallback& callback) {
    595   DCHECK(CalledOnValidThread());
    596 
    597   std::string resource_id;
    598   if (!EraseIfExists(&incremental_sync_origins_, origin, &resource_id)) {
    599     RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
    600     return;
    601   }
    602   disabled_origins_[origin] = resource_id;
    603 
    604   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    605   batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN));
    606   batch->Put(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN),
    607              drive_backend::RemoveWapiIdPrefix(resource_id));
    608   AppendMetadataDeletionToBatch(metadata_map_, origin, batch.get());
    609   metadata_map_.erase(origin);
    610 
    611   WriteToDB(batch.Pass(), callback);
    612 }
    613 
    614 void DriveMetadataStore::RemoveOrigin(
    615     const GURL& origin,
    616     const SyncStatusCallback& callback) {
    617   DCHECK(CalledOnValidThread());
    618 
    619   std::string resource_id;
    620   if (!EraseIfExists(&incremental_sync_origins_, origin, &resource_id) &&
    621       !EraseIfExists(&disabled_origins_, origin, &resource_id)) {
    622     RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
    623     return;
    624   }
    625   origin_by_resource_id_.erase(resource_id);
    626 
    627   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
    628   batch->Delete(CreateKeyForOriginRoot(origin, INCREMENTAL_SYNC_ORIGIN));
    629   batch->Delete(CreateKeyForOriginRoot(origin, DISABLED_ORIGIN));
    630   AppendMetadataDeletionToBatch(metadata_map_, origin, batch.get());
    631   metadata_map_.erase(origin);
    632 
    633   WriteToDB(batch.Pass(), callback);
    634 }
    635 
    636 void DriveMetadataStore::WriteToDB(scoped_ptr<leveldb::WriteBatch> batch,
    637                                    const SyncStatusCallback& callback) {
    638   DCHECK(CalledOnValidThread());
    639   if (db_status_ != SYNC_STATUS_OK &&
    640       db_status_ != SYNC_DATABASE_ERROR_NOT_FOUND) {
    641     RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_FAILED));
    642     return;
    643   }
    644 
    645   DCHECK(db_);
    646   base::PostTaskAndReplyWithResult(
    647       file_task_runner_.get(),
    648       FROM_HERE,
    649       base::Bind(&leveldb::DB::Write,
    650                  base::Unretained(db_.get()),
    651                  leveldb::WriteOptions(),
    652                  base::Owned(batch.release())),
    653       base::Bind(&DriveMetadataStore::UpdateDBStatusAndInvokeCallback,
    654                  AsWeakPtr(),
    655                  callback));
    656 }
    657 
    658 void DriveMetadataStore::UpdateDBStatus(SyncStatusCode status) {
    659   DCHECK(CalledOnValidThread());
    660   if (db_status_ != SYNC_STATUS_OK &&
    661       db_status_ != SYNC_DATABASE_ERROR_NOT_FOUND) {
    662     // TODO(tzik): Handle database corruption. http://crbug.com/153709
    663     db_status_ = status;
    664     util::Log(logging::LOG_WARNING,
    665               FROM_HERE,
    666               "DriveMetadataStore turned to wrong state: %s",
    667               SyncStatusCodeToString(status));
    668     return;
    669   }
    670   db_status_ = SYNC_STATUS_OK;
    671 }
    672 
    673 void DriveMetadataStore::UpdateDBStatusAndInvokeCallback(
    674     const SyncStatusCallback& callback,
    675     const leveldb::Status& leveldb_status) {
    676   SyncStatusCode status = LevelDBStatusToSyncStatusCode(leveldb_status);
    677   UpdateDBStatus(status);
    678   callback.Run(status);
    679 }
    680 
    681 SyncStatusCode DriveMetadataStore::GetConflictURLs(
    682     fileapi::FileSystemURLSet* urls) const {
    683   DCHECK(CalledOnValidThread());
    684   DCHECK_EQ(SYNC_STATUS_OK, db_status_);
    685 
    686   urls->clear();
    687   for (MetadataMap::const_iterator origin_itr = metadata_map_.begin();
    688        origin_itr != metadata_map_.end();
    689        ++origin_itr) {
    690     for (PathToMetadata::const_iterator itr = origin_itr->second.begin();
    691          itr != origin_itr->second.end();
    692          ++itr) {
    693       if (itr->second.conflicted()) {
    694         urls->insert(CreateSyncableFileSystemURL(
    695             origin_itr->first, itr->first));
    696       }
    697     }
    698   }
    699   return SYNC_STATUS_OK;
    700 }
    701 
    702 SyncStatusCode DriveMetadataStore::GetToBeFetchedFiles(
    703     URLAndDriveMetadataList* list) const {
    704   DCHECK(CalledOnValidThread());
    705   DCHECK_EQ(SYNC_STATUS_OK, db_status_);
    706 
    707   list->clear();
    708   for (MetadataMap::const_iterator origin_itr = metadata_map_.begin();
    709        origin_itr != metadata_map_.end();
    710        ++origin_itr) {
    711     for (PathToMetadata::const_iterator itr = origin_itr->second.begin();
    712          itr != origin_itr->second.end();
    713          ++itr) {
    714       if (itr->second.to_be_fetched()) {
    715         FileSystemURL url = CreateSyncableFileSystemURL(
    716             origin_itr->first, itr->first);
    717         list->push_back(std::make_pair(url, itr->second));
    718       }
    719     }
    720   }
    721   return SYNC_STATUS_OK;
    722 }
    723 
    724 std::string DriveMetadataStore::GetResourceIdForOrigin(
    725     const GURL& origin) const {
    726   DCHECK(CalledOnValidThread());
    727 
    728   // If we don't have valid root directory (this could be reset even after
    729   // initialized) just return empty string, as the origin directories
    730   // in the root directory must have become invalid now too.
    731   if (sync_root_directory().empty())
    732     return std::string();
    733 
    734   ResourceIdByOrigin::const_iterator found =
    735       incremental_sync_origins_.find(origin);
    736   if (found != incremental_sync_origins_.end())
    737     return found->second;
    738 
    739   found = disabled_origins_.find(origin);
    740   if (found != disabled_origins_.end())
    741     return found->second;
    742 
    743   return std::string();
    744 }
    745 
    746 void DriveMetadataStore::GetAllOrigins(std::vector<GURL>* origins) {
    747   DCHECK(CalledOnValidThread());
    748   DCHECK(origins);
    749   origins->clear();
    750   origins->reserve(incremental_sync_origins_.size() +
    751                    disabled_origins_.size());
    752   AddOriginsToVector(origins, incremental_sync_origins_);
    753   AddOriginsToVector(origins, disabled_origins_);
    754 }
    755 
    756 bool DriveMetadataStore::GetOriginByOriginRootDirectoryId(
    757     const std::string& resource_id,
    758     GURL* origin) {
    759   DCHECK(CalledOnValidThread());
    760   DCHECK(origin);
    761 
    762   OriginByResourceId::iterator found = origin_by_resource_id_.find(resource_id);
    763   if (found == origin_by_resource_id_.end())
    764     return false;
    765   *origin = found->second;
    766   return true;
    767 }
    768 
    769 scoped_ptr<base::ListValue> DriveMetadataStore::DumpFiles(const GURL& origin) {
    770   DCHECK(CalledOnValidThread());
    771 
    772   scoped_ptr<base::ListValue> files(new base::ListValue);
    773 
    774   MetadataMap::const_iterator found = metadata_map_.find(origin);
    775   if (found == metadata_map_.end())
    776     return make_scoped_ptr(new base::ListValue);
    777 
    778   for (PathToMetadata::const_iterator itr = found->second.begin();
    779        itr != found->second.end();
    780        ++itr) {
    781     // Convert Drive specific metadata to Common File metadata object.
    782     const DriveMetadata& metadata = itr->second;
    783 
    784     base::DictionaryValue* file = new DictionaryValue;
    785     file->SetString("path", itr->first.AsUTF8Unsafe());
    786     file->SetString("title", itr->first.BaseName().AsUTF8Unsafe());
    787     file->SetString("type", DriveTypeToString(metadata.type()));
    788 
    789     base::DictionaryValue* details = new DictionaryValue;
    790     details->SetString("resource_id", metadata.resource_id());
    791     details->SetString("md5", metadata.md5_checksum());
    792     details->SetString("dirty", metadata.to_be_fetched() ? "true" : "false");
    793 
    794     file->Set("details", details);
    795     files->Append(file);
    796   }
    797 
    798   return files.Pass();
    799 }
    800 
    801 }  // namespace sync_file_system
    802