// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/drive/resource_metadata_storage.h"

#include <stddef.h>

#include <map>
#include <set>
#include <unordered_map>
#include <utility>

#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/sequenced_task_runner.h"
#include "base/stl_util.h"
#include "base/threading/scoped_blocking_call.h"
#include "components/drive/drive.pb.h"
#include "components/drive/drive_api_util.h"
#include "components/drive/file_system_core_util.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/leveldb_chrome.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"

namespace drive {
namespace internal {

namespace {

// Enum to describe DB initialization status.
enum DBInitStatus {
  DB_INIT_SUCCESS,
  DB_INIT_NOT_FOUND,
  DB_INIT_CORRUPTION,
  DB_INIT_IO_ERROR,
  DB_INIT_FAILED,
  DB_INIT_INCOMPATIBLE,
  DB_INIT_BROKEN,
  DB_INIT_OPENED_EXISTING_DB,
  DB_INIT_CREATED_NEW_DB,
  DB_INIT_REPLACED_EXISTING_DB_WITH_NEW_DB,
  DB_INIT_MAX_VALUE,
};

// Enum to describe DB validity check failure reason.
enum CheckValidityFailureReason {
  CHECK_VALIDITY_FAILURE_INVALID_HEADER,
  CHECK_VALIDITY_FAILURE_BROKEN_ID_ENTRY,
  CHECK_VALIDITY_FAILURE_BROKEN_ENTRY,
  CHECK_VALIDITY_FAILURE_INVALID_LOCAL_ID,
  CHECK_VALIDITY_FAILURE_INVALID_PARENT_ID,
  CHECK_VALIDITY_FAILURE_BROKEN_CHILD_MAP,
  CHECK_VALIDITY_FAILURE_CHILD_ENTRY_COUNT_MISMATCH,
  CHECK_VALIDITY_FAILURE_ITERATOR_ERROR,
  CHECK_VALIDITY_FAILURE_MAX_VALUE,
};

// The name of the DB which stores the metadata.
const base::FilePath::CharType kResourceMapDBName[] =
    FILE_PATH_LITERAL("resource_metadata_resource_map.db");

// The name of the DB which couldn't be opened, but is preserved just in case.
const base::FilePath::CharType kPreservedResourceMapDBName[] =
    FILE_PATH_LITERAL("resource_metadata_preserved_resource_map.db");

// The name of the DB which couldn't be opened, and was replaced with a new one.
const base::FilePath::CharType kTrashedResourceMapDBName[] =
    FILE_PATH_LITERAL("resource_metadata_trashed_resource_map.db");

// Meant to be a character which never happen to be in real IDs.
const char kDBKeyDelimeter = '\0';

// String used as a suffix of a key for a cache entry.
const char kCacheEntryKeySuffix[] = "CACHE";

// String used as a prefix of a key for a resource-ID-to-local-ID entry.
const char kIdEntryKeyPrefix[] = "ID";

// Returns a string to be used as the key for the header.
std::string GetHeaderDBKey() {
  std::string key;
  key.push_back(kDBKeyDelimeter);
  key.append("HEADER");
  return key;
}

// Returns true if |key| is a key for a child entry.
bool IsChildEntryKey(const leveldb::Slice& key) {
  return !key.empty() && key[key.size() - 1] == kDBKeyDelimeter;
}

// Returns true if |key| is a key for a cache entry.
bool IsCacheEntryKey(const leveldb::Slice& key) {
  // A cache entry key should end with |kDBKeyDelimeter + kCacheEntryKeySuffix|.
  const leveldb::Slice expected_suffix(kCacheEntryKeySuffix,
                                       base::size(kCacheEntryKeySuffix) - 1);
  if (key.size() < 1 + expected_suffix.size() ||
      key[key.size() - expected_suffix.size() - 1] != kDBKeyDelimeter)
    return false;

  const leveldb::Slice key_substring(
      key.data() + key.size() - expected_suffix.size(), expected_suffix.size());
  return key_substring.compare(expected_suffix) == 0;
}

// Returns ID extracted from a cache entry key.
std::string GetIdFromCacheEntryKey(const leveldb::Slice& key) {
  DCHECK(IsCacheEntryKey(key));
  // Drop the suffix |kDBKeyDelimeter + kCacheEntryKeySuffix| from the key.
  const size_t kSuffixLength = base::size(kCacheEntryKeySuffix) - 1;
  const int id_length = key.size() - 1 - kSuffixLength;
  return std::string(key.data(), id_length);
}

// Returns a string to be used as a key for a resource-ID-to-local-ID entry.
std::string GetIdEntryKey(const std::string& resource_id) {
  std::string key;
  key.push_back(kDBKeyDelimeter);
  key.append(kIdEntryKeyPrefix);
  key.push_back(kDBKeyDelimeter);
  key.append(resource_id);
  return key;
}

// Returns true if |key| is a key for a resource-ID-to-local-ID entry.
bool IsIdEntryKey(const leveldb::Slice& key) {
  // A resource-ID-to-local-ID entry key should start with
  // |kDBKeyDelimeter + kIdEntryKeyPrefix + kDBKeyDelimeter|.
  const leveldb::Slice expected_prefix(kIdEntryKeyPrefix,
                                       base::size(kIdEntryKeyPrefix) - 1);
  if (key.size() < 2 + expected_prefix.size())
    return false;
  const leveldb::Slice key_substring(key.data() + 1, expected_prefix.size());
  return key[0] == kDBKeyDelimeter &&
      key_substring.compare(expected_prefix) == 0 &&
      key[expected_prefix.size() + 1] == kDBKeyDelimeter;
}

// Returns the resource ID extracted from a resource-ID-to-local-ID entry key.
std::string GetResourceIdFromIdEntryKey(const leveldb::Slice& key) {
  DCHECK(IsIdEntryKey(key));
  // Drop the prefix |kDBKeyDelimeter + kIdEntryKeyPrefix + kDBKeyDelimeter|
  // from the key.
  const size_t kPrefixLength = base::size(kIdEntryKeyPrefix) - 1;
  const int offset = kPrefixLength + 2;
  return std::string(key.data() + offset, key.size() - offset);
}

// Converts leveldb::Status to DBInitStatus.
DBInitStatus LevelDBStatusToDBInitStatus(const leveldb::Status& status) {
  if (status.ok())
    return DB_INIT_SUCCESS;
  if (status.IsNotFound())
    return DB_INIT_NOT_FOUND;
  if (status.IsCorruption())
    return DB_INIT_CORRUPTION;
  if (status.IsIOError())
    return DB_INIT_IO_ERROR;
  return DB_INIT_FAILED;
}

// Converts leveldb::Status to FileError.
FileError LevelDBStatusToFileError(const leveldb::Status& status) {
  if (status.ok())
    return FILE_ERROR_OK;
  if (status.IsNotFound())
    return FILE_ERROR_NOT_FOUND;
  if (leveldb_env::IndicatesDiskFull(status))
    return FILE_ERROR_NO_LOCAL_SPACE;
  return FILE_ERROR_FAILED;
}

ResourceMetadataHeader GetDefaultHeaderEntry() {
  ResourceMetadataHeader header;
  header.set_version(ResourceMetadataStorage::kDBVersion);
  return header;
}

bool MoveIfPossible(const base::FilePath& from, const base::FilePath& to) {
  return !base::PathExists(from) || base::Move(from, to);
}

void RecordCheckValidityFailure(CheckValidityFailureReason reason) {
  UMA_HISTOGRAM_ENUMERATION("Drive.MetadataDBValidityCheckFailureReason",
                            reason,
                            CHECK_VALIDITY_FAILURE_MAX_VALUE);
}

bool UpgradeOldDBVersions6To10(leveldb::DB* resource_map) {
  // Cache entries can be reused.
  leveldb::ReadOptions options;
  options.verify_checksums = true;
  std::unique_ptr<leveldb::Iterator> it(resource_map->NewIterator(options));

  leveldb::WriteBatch batch;
  // First, remove all entries.
  for (it->SeekToFirst(); it->Valid(); it->Next())
    batch.Delete(it->key());

  // Put ID entries and cache entries.
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    if (!IsCacheEntryKey(it->key()))
      continue;

    FileCacheEntry cache_entry;
    if (!cache_entry.ParseFromArray(it->value().data(), it->value().size()))
      return false;

    // The resource ID might be in old WAPI format. We need to canonicalize
    // to the format of API service currently in use.
    const std::string& id = GetIdFromCacheEntryKey(it->key());
    const std::string& id_new = util::CanonicalizeResourceId(id);

    // Before v11, resource ID was directly used as local ID. Such entries
    // can be migrated by adding an identity ID mapping.
    batch.Put(GetIdEntryKey(id_new), id_new);

    // Put cache state into a ResourceEntry.
    ResourceEntry entry;
    entry.set_local_id(id_new);
    entry.set_resource_id(id_new);
    *entry.mutable_file_specific_info()->mutable_cache_state() = cache_entry;

    std::string serialized_entry;
    if (!entry.SerializeToString(&serialized_entry)) {
      DLOG(ERROR) << "Failed to serialize the entry: " << id;
      return false;
    }
    batch.Put(id_new, serialized_entry);
  }
  if (!it->status().ok())
    return false;

  // Put header with the latest version number. This also clears
  // largest_changestamp and triggers refresh of metadata.
  std::string serialized_header;
  if (!GetDefaultHeaderEntry().SerializeToString(&serialized_header))
    return false;

  batch.Put(GetHeaderDBKey(), serialized_header);
  return resource_map->Write(leveldb::WriteOptions(), &batch).ok();
}

bool UpgradeOldDBVersion11(leveldb::DB* resource_map) {
  // Cache and ID map entries are reusable.
  leveldb::ReadOptions options;
  options.verify_checksums = true;
  std::unique_ptr<leveldb::Iterator> it(resource_map->NewIterator(options));

  // First, get the set of local IDs associated with cache entries.
  std::set<std::string> cached_entry_ids;
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    if (IsCacheEntryKey(it->key()))
      cached_entry_ids.insert(GetIdFromCacheEntryKey(it->key()));
  }
  if (!it->status().ok())
    return false;

  // Remove all entries except used ID entries.
  leveldb::WriteBatch batch;
  std::map<std::string, std::string> local_id_to_resource_id;
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    const bool is_used_id = IsIdEntryKey(it->key()) &&
                            cached_entry_ids.count(it->value().ToString());
    if (is_used_id) {
      local_id_to_resource_id[it->value().ToString()] =
          GetResourceIdFromIdEntryKey(it->key());
    } else {
      batch.Delete(it->key());
    }
  }
  if (!it->status().ok())
    return false;

  // Put cache entries.
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    if (!IsCacheEntryKey(it->key()))
      continue;

    const std::string& id = GetIdFromCacheEntryKey(it->key());
    const auto iter_resource_id = local_id_to_resource_id.find(id);
    if (iter_resource_id == local_id_to_resource_id.end())
      continue;

    FileCacheEntry cache_entry;
    if (!cache_entry.ParseFromArray(it->value().data(), it->value().size()))
      return false;

    // Put cache state into a ResourceEntry.
    ResourceEntry entry;
    entry.set_local_id(id);
    entry.set_resource_id(iter_resource_id->second);
    *entry.mutable_file_specific_info()->mutable_cache_state() = cache_entry;

    std::string serialized_entry;
    if (!entry.SerializeToString(&serialized_entry)) {
      DLOG(ERROR) << "Failed to serialize the entry: " << id;
      return false;
    }
    batch.Put(id, serialized_entry);
  }
  if (!it->status().ok())
    return false;

  // Put header with the latest version number. This also clears
  // largest_changestamp and triggers refresh of metadata.
  std::string serialized_header;
  if (!GetDefaultHeaderEntry().SerializeToString(&serialized_header))
    return false;

  batch.Put(GetHeaderDBKey(), serialized_header);
  return resource_map->Write(leveldb::WriteOptions(), &batch).ok();
}

bool UpgradeOldDBVersion12(leveldb::DB* resource_map) {
  // Reuse all entries.
  leveldb::ReadOptions options;
  options.verify_checksums = true;
  std::unique_ptr<leveldb::Iterator> it(resource_map->NewIterator(options));

  // First, get local ID to resource ID map.
  std::map<std::string, std::string> local_id_to_resource_id;
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    if (IsIdEntryKey(it->key())) {
      local_id_to_resource_id[it->value().ToString()] =
          GetResourceIdFromIdEntryKey(it->key());
    }
  }
  if (!it->status().ok())
    return false;

  leveldb::WriteBatch batch;
  // Merge cache entries to ResourceEntry.
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    if (!IsCacheEntryKey(it->key()))
      continue;

    const std::string& id = GetIdFromCacheEntryKey(it->key());

    FileCacheEntry cache_entry;
    if (!cache_entry.ParseFromArray(it->value().data(), it->value().size()))
      return false;

    std::string serialized_entry;
    leveldb::Status status =
        resource_map->Get(options, leveldb::Slice(id), &serialized_entry);

    const auto iter_resource_id = local_id_to_resource_id.find(id);

    // No need to keep cache-only entries without resource ID.
    if (status.IsNotFound() &&
        iter_resource_id == local_id_to_resource_id.end())
      continue;

    ResourceEntry entry;
    if (status.ok()) {
      if (!entry.ParseFromString(serialized_entry))
        return false;
    } else if (status.IsNotFound()) {
      entry.set_local_id(id);
      entry.set_resource_id(iter_resource_id->second);
    } else {
      DLOG(ERROR) << "Failed to get the entry: " << id;
      return false;
    }
    *entry.mutable_file_specific_info()->mutable_cache_state() = cache_entry;

    if (!entry.SerializeToString(&serialized_entry)) {
      DLOG(ERROR) << "Failed to serialize the entry: " << id;
      return false;
    }
    batch.Delete(it->key());
    batch.Put(id, serialized_entry);
  }
  if (!it->status().ok())
    return false;

  // Put header with the latest version number. This also clears
  // largest_changestamp and triggers refresh of metadata.
  std::string serialized_header;
  if (!GetDefaultHeaderEntry().SerializeToString(&serialized_header))
    return false;

  batch.Put(GetHeaderDBKey(), serialized_header);
  return resource_map->Write(leveldb::WriteOptions(), &batch).ok();
}

bool UpgradeOldDBVersion13(leveldb::DB* resource_map) {
  // Before r272134, UpgradeOldDB() was not deleting unused ID entries.
  // Delete unused ID entries to fix crbug.com/374648.
  std::set<std::string> used_ids;

  std::unique_ptr<leveldb::Iterator> it(
      resource_map->NewIterator(leveldb::ReadOptions()));
  it->Seek(leveldb::Slice(GetHeaderDBKey()));
  it->Next();
  for (; it->Valid(); it->Next()) {
    if (IsCacheEntryKey(it->key()))
      used_ids.insert(GetIdFromCacheEntryKey(it->key()));
    else if (!IsChildEntryKey(it->key()) && !IsIdEntryKey(it->key()))
      used_ids.insert(it->key().ToString());
  }
  if (!it->status().ok())
    return false;

  leveldb::WriteBatch batch;
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    if (IsIdEntryKey(it->key()) && !used_ids.count(it->value().ToString()))
      batch.Delete(it->key());
  }
  if (!it->status().ok())
    return false;

  // Put header with the latest version number. This also clears
  // largest_changestamp and triggers refresh of metadata.
  std::string serialized_header;
  if (!GetDefaultHeaderEntry().SerializeToString(&serialized_header))
    return false;

  batch.Put(GetHeaderDBKey(), serialized_header);
  return resource_map->Write(leveldb::WriteOptions(), &batch).ok();
}

bool UpgradeOldDBVersion14(leveldb::DB* resource_map) {
  // Just need to clear largest_changestamp.
  // Put header with the latest version number.
  std::string serialized_header;
  if (!GetDefaultHeaderEntry().SerializeToString(&serialized_header))
    return false;

  leveldb::WriteBatch batch;
  batch.Put(GetHeaderDBKey(), serialized_header);
  return resource_map->Write(leveldb::WriteOptions(), &batch).ok();
}

bool UpgradeOldDBVersion15(leveldb::DB* resource_map) {
  leveldb::ReadOptions read_options;
  read_options.verify_checksums = true;
  leveldb::WriteBatch batch;

  std::unique_ptr<leveldb::Iterator> it(
      resource_map->NewIterator(read_options));

  it->SeekToFirst();
  ResourceMetadataHeader header;

  if (!it->Valid() || it->key() != GetHeaderDBKey()) {
    DLOG(ERROR) << "Header not detected.";
    return false;
  }

  if (!header.ParseFromArray(it->value().data(), it->value().size())) {
    DLOG(ERROR) << "Could not parse header.";
    return false;
  }

  header.set_version(ResourceMetadataStorage::kDBVersion);
  header.set_start_page_token(drive::util::ConvertChangestampToStartPageToken(
      header.largest_changestamp()));
  std::string serialized_header;
  header.SerializeToString(&serialized_header);
  batch.Put(GetHeaderDBKey(), serialized_header);

  for (it->Next(); it->Valid(); it->Next()) {
    if (IsIdEntryKey(it->key()))
      continue;

    ResourceEntry entry;
    if (!entry.ParseFromArray(it->value().data(), it->value().size()))
      return false;

    if (entry.has_directory_specific_info()) {
      int64_t changestamp = entry.directory_specific_info().changestamp();
      entry.mutable_directory_specific_info()->set_start_page_token(
          drive::util::ConvertChangestampToStartPageToken(changestamp));

      std::string serialized_entry;
      if (!entry.SerializeToString(&serialized_entry)) {
        DLOG(ERROR) << "Failed to serialize the entry";
        return false;
      }

      batch.Put(entry.local_id(), serialized_entry);
    }
  }

  return resource_map->Write(leveldb::WriteOptions(), &batch).ok();
}

bool UpgradeOldDBVersions16To18(leveldb::DB* resource_map) {
  // From 15->16, the field |alternate_url| was moved from FileSpecificData
  // to ResourceEntry. Since it isn't saved for directories, we need to do a
  // full fetch to get the |alternate_url| fetched for each directory.
  // Put a new header with the latest version number, and clear the start page
  // token.
  std::string serialized_header;
  if (!GetDefaultHeaderEntry().SerializeToString(&serialized_header))
    return false;

  leveldb::WriteBatch batch;
  batch.Put(GetHeaderDBKey(), serialized_header);
  return resource_map->Write(leveldb::WriteOptions(), &batch).ok();
}

}  // namespace

ResourceMetadataStorage::Iterator::Iterator(
    std::unique_ptr<leveldb::Iterator> it)
    : it_(std::move(it)) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  DCHECK(it_);

  // Skip the header entry.
  // Note: The header entry comes before all other entries because its key
  // starts with kDBKeyDelimeter. (i.e. '\0')
  it_->Seek(leveldb::Slice(GetHeaderDBKey()));

  Advance();
}

ResourceMetadataStorage::Iterator::~Iterator() {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
}

bool ResourceMetadataStorage::Iterator::IsAtEnd() const {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  return !it_->Valid();
}

std::string ResourceMetadataStorage::Iterator::GetID() const {
  return it_->key().ToString();
}

const ResourceEntry& ResourceMetadataStorage::Iterator::GetValue() const {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  DCHECK(!IsAtEnd());
  return entry_;
}

void ResourceMetadataStorage::Iterator::Advance() {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  DCHECK(!IsAtEnd());

  for (it_->Next() ; it_->Valid(); it_->Next()) {
    if (!IsChildEntryKey(it_->key()) &&
        !IsIdEntryKey(it_->key()) &&
        entry_.ParseFromArray(it_->value().data(), it_->value().size())) {
      break;
    }
  }
}

bool ResourceMetadataStorage::Iterator::HasError() const {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  return !it_->status().ok();
}

// static
bool ResourceMetadataStorage::UpgradeOldDB(
    const base::FilePath& directory_path) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  const base::FilePath resource_map_path =
      directory_path.Append(kResourceMapDBName);
  const base::FilePath preserved_resource_map_path =
      directory_path.Append(kPreservedResourceMapDBName);

  leveldb_env::Options options;
  options.max_open_files = 0;  // Use minimum.
  options.create_if_missing = false;

  if (base::PathExists(preserved_resource_map_path)) {
    // Preserved DB is found. The previous attempt to create a new DB should not
    // be successful. Discard the imperfect new DB and restore the old DB.
    leveldb::Status status =
        leveldb_chrome::DeleteDB(resource_map_path, options);
    if (!status.ok()) {
      LOG(ERROR) << "ERROR deleting " << resource_map_path
                 << ", err:" << status.ToString();
      return false;
    }
    if (!base::Move(preserved_resource_map_path, resource_map_path))
      return false;
  }

  if (!base::PathExists(resource_map_path))
    return false;

  // Open DB.
  std::unique_ptr<leveldb::DB> resource_map;
  leveldb::Status status = leveldb_env::OpenDB(
      options, resource_map_path.AsUTF8Unsafe(), &resource_map);
  if (!status.ok())
    return false;

  // Check DB version.
  std::string serialized_header;
  ResourceMetadataHeader header;
  if (!resource_map->Get(leveldb::ReadOptions(),
                         leveldb::Slice(GetHeaderDBKey()),
                         &serialized_header).ok() ||
      !header.ParseFromString(serialized_header))
    return false;
  base::UmaHistogramSparse("Drive.MetadataDBVersionBeforeUpgradeCheck",
                           header.version());

  switch (header.version()) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
      return false;  // Too old, nothing can be done.
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
      return UpgradeOldDBVersions6To10(resource_map.get());
    case 11:
      return UpgradeOldDBVersion11(resource_map.get());
    case 12:
      return UpgradeOldDBVersion12(resource_map.get());
    case 13:
      return UpgradeOldDBVersion13(resource_map.get());
    case 14:
      return UpgradeOldDBVersion14(resource_map.get());
    case 15:
      return UpgradeOldDBVersion15(resource_map.get());
    case 16:
    case 17:
    case 18:
      return UpgradeOldDBVersions16To18(resource_map.get());
    case kDBVersion:
      static_assert(
          kDBVersion == 19,
          "database version and this function must be updated together");
      return true;
    default:
      LOG(WARNING) << "Unexpected DB version: " << header.version();
      return false;
  }
}

ResourceMetadataStorage::ResourceMetadataStorage(
    const base::FilePath& directory_path,
    base::SequencedTaskRunner* blocking_task_runner)
    : directory_path_(directory_path),
      cache_file_scan_is_needed_(true),
      blocking_task_runner_(blocking_task_runner) {
}

bool ResourceMetadataStorage::Initialize() {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  resource_map_.reset();

  const base::FilePath resource_map_path =
      directory_path_.Append(kResourceMapDBName);
  const base::FilePath preserved_resource_map_path =
      directory_path_.Append(kPreservedResourceMapDBName);
  const base::FilePath trashed_resource_map_path =
      directory_path_.Append(kTrashedResourceMapDBName);

  leveldb_env::Options options;
  options.max_open_files = 0;  // Use minimum.
  options.create_if_missing = false;

  // Discard unneeded DBs.
  if (!leveldb_chrome::DeleteDB(preserved_resource_map_path, options).ok() ||
      !leveldb_chrome::DeleteDB(trashed_resource_map_path, options).ok()) {
    LOG(ERROR) << "Failed to remove unneeded DBs.";
    return false;
  }

  // Try to open the existing DB.
  DBInitStatus open_existing_result = DB_INIT_NOT_FOUND;
  leveldb::Status status;
  if (base::PathExists(resource_map_path)) {
    status = leveldb_env::OpenDB(options, resource_map_path.AsUTF8Unsafe(),
                                 &resource_map_);
    open_existing_result = LevelDBStatusToDBInitStatus(status);
  }

  if (open_existing_result == DB_INIT_SUCCESS) {
    // Check the validity of existing DB.
    int db_version = -1;
    ResourceMetadataHeader header;
    if (GetHeader(&header) == FILE_ERROR_OK)
      db_version = header.version();

    bool should_discard_db = true;
    if (db_version != kDBVersion) {
      open_existing_result = DB_INIT_INCOMPATIBLE;
      DVLOG(1) << "Reject incompatible DB.";
    } else if (!CheckValidity()) {
      open_existing_result = DB_INIT_BROKEN;
      LOG(ERROR) << "Reject invalid DB.";
    } else {
      should_discard_db = false;
    }

    if (should_discard_db)
      resource_map_.reset();
    else
      cache_file_scan_is_needed_ = false;
  }

  UMA_HISTOGRAM_ENUMERATION("Drive.MetadataDBOpenExistingResult",
                            open_existing_result,
                            DB_INIT_MAX_VALUE);

  DBInitStatus init_result = DB_INIT_OPENED_EXISTING_DB;

  // Failed to open the existing DB, create new DB.
  if (!resource_map_) {
    // Move the existing DB to the preservation path. The moved old DB is
    // deleted once the new DB creation succeeds, or is restored later in
    // UpgradeOldDB() when the creation fails.
    MoveIfPossible(resource_map_path, preserved_resource_map_path);

    // Create DB.
    options = leveldb_env::Options();
    options.max_open_files = 0;  // Use minimum.
    options.create_if_missing = true;
    options.error_if_exists = true;

    status = leveldb_env::OpenDB(options, resource_map_path.AsUTF8Unsafe(),
                                 &resource_map_);
    if (status.ok()) {
      // Set up header and trash the old DB.
      if (PutHeader(GetDefaultHeaderEntry()) == FILE_ERROR_OK &&
          MoveIfPossible(preserved_resource_map_path,
                         trashed_resource_map_path)) {
        init_result = open_existing_result == DB_INIT_NOT_FOUND ?
            DB_INIT_CREATED_NEW_DB : DB_INIT_REPLACED_EXISTING_DB_WITH_NEW_DB;
      } else {
        init_result = DB_INIT_FAILED;
        resource_map_.reset();
      }
    } else {
      LOG(ERROR) << "Failed to create resource map DB: " << status.ToString();
      init_result = LevelDBStatusToDBInitStatus(status);
    }
  }

  UMA_HISTOGRAM_ENUMERATION("Drive.MetadataDBInitResult",
                            init_result,
                            DB_INIT_MAX_VALUE);
  return !!resource_map_;
}

void ResourceMetadataStorage::Destroy() {
  blocking_task_runner_->PostTask(
      FROM_HERE, base::BindOnce(&ResourceMetadataStorage::DestroyOnBlockingPool,
                                base::Unretained(this)));
}

void ResourceMetadataStorage::RecoverCacheInfoFromTrashedResourceMap(
    RecoveredCacheInfoMap* out_info) {
  const base::FilePath trashed_resource_map_path =
      directory_path_.Append(kTrashedResourceMapDBName);

  if (!base::PathExists(trashed_resource_map_path))
    return;

  leveldb_env::Options options;
  options.max_open_files = 0;  // Use minimum.
  options.create_if_missing = false;
  options.reuse_logs = false;

  // Trashed DB may be broken, repair it first.
  leveldb::Status status;
  status = leveldb::RepairDB(trashed_resource_map_path.AsUTF8Unsafe(), options);
  if (!status.ok()) {
    LOG(ERROR) << "Failed to repair trashed DB: " << status.ToString();
    return;
  }

  // Open it.
  std::unique_ptr<leveldb::DB> resource_map;
  status = leveldb_env::OpenDB(
      options, trashed_resource_map_path.AsUTF8Unsafe(), &resource_map);
  if (!status.ok()) {
    LOG(ERROR) << "Failed to open trashed DB: " << status.ToString();
    return;
  }

  // Check DB version.
  std::string serialized_header;
  ResourceMetadataHeader header;
  if (!resource_map->Get(leveldb::ReadOptions(),
                         leveldb::Slice(GetHeaderDBKey()),
                         &serialized_header).ok() ||
      !header.ParseFromString(serialized_header) ||
      header.version() != kDBVersion) {
    LOG(ERROR) << "Incompatible DB version: " << header.version();
    return;
  }

  // Collect cache entries.
  std::unique_ptr<leveldb::Iterator> it(
      resource_map->NewIterator(leveldb::ReadOptions()));
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    if (!IsChildEntryKey(it->key()) &&
        !IsIdEntryKey(it->key())) {
      const std::string id = it->key().ToString();
      ResourceEntry entry;
      if (entry.ParseFromArray(it->value().data(), it->value().size()) &&
          entry.file_specific_info().has_cache_state()) {
        RecoveredCacheInfo* info = &(*out_info)[id];
        info->is_dirty = entry.file_specific_info().cache_state().is_dirty();
        info->md5 = entry.file_specific_info().cache_state().md5();
        info->title = entry.title();
      }
    }
  }
}

FileError ResourceMetadataStorage::SetLargestChangestamp(
    int64_t largest_changestamp) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  ResourceMetadataHeader header;
  FileError error = GetHeader(&header);
  if (error != FILE_ERROR_OK) {
    DLOG(ERROR) << "Failed to get the header.";
    return error;
  }
  header.set_largest_changestamp(largest_changestamp);
  return PutHeader(header);
}

FileError ResourceMetadataStorage::GetLargestChangestamp(
    int64_t* largest_changestamp) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  ResourceMetadataHeader header;
  FileError error = GetHeader(&header);
  if (error != FILE_ERROR_OK) {
    DLOG(ERROR) << "Failed to get the header.";
    return error;
  }
  *largest_changestamp = header.largest_changestamp();
  return FILE_ERROR_OK;
}

FileError ResourceMetadataStorage::GetStartPageToken(
    std::string* start_page_token) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  ResourceMetadataHeader header;
  FileError error = GetHeader(&header);
  if (error != FILE_ERROR_OK) {
    DLOG(ERROR) << "Failed to get the header.";
    return error;
  }
  *start_page_token = header.start_page_token();
  return FILE_ERROR_OK;
}

FileError ResourceMetadataStorage::SetStartPageToken(
    const std::string& start_page_token) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  ResourceMetadataHeader header;
  FileError error = GetHeader(&header);
  if (error != FILE_ERROR_OK) {
    DLOG(ERROR) << "Failed to get the header.";
    return error;
  }
  header.set_start_page_token(start_page_token);
  return PutHeader(header);
}

FileError ResourceMetadataStorage::PutEntry(const ResourceEntry& entry) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  const std::string& id = entry.local_id();
  DCHECK(!id.empty());

  // Try to get existing entry.
  std::string serialized_entry;
  leveldb::Status status = resource_map_->Get(leveldb::ReadOptions(),
                                              leveldb::Slice(id),
                                              &serialized_entry);
  if (!status.ok() && !status.IsNotFound())  // Unexpected errors.
    return LevelDBStatusToFileError(status);

  ResourceEntry old_entry;
  if (status.ok() && !old_entry.ParseFromString(serialized_entry))
    return FILE_ERROR_FAILED;

  // Construct write batch.
  leveldb::WriteBatch batch;

  // Remove from the old parent.
  if (!old_entry.parent_local_id().empty()) {
    batch.Delete(GetChildEntryKey(old_entry.parent_local_id(),
                                  old_entry.base_name()));
  }
  // Add to the new parent.
  if (!entry.parent_local_id().empty())
    batch.Put(GetChildEntryKey(entry.parent_local_id(), entry.base_name()), id);

  // Refresh resource-ID-to-local-ID mapping entry.
  if (old_entry.resource_id() != entry.resource_id()) {
    // Resource ID should not change.
    DCHECK(old_entry.resource_id().empty() || entry.resource_id().empty());

    if (!old_entry.resource_id().empty())
      batch.Delete(GetIdEntryKey(old_entry.resource_id()));
    if (!entry.resource_id().empty())
      batch.Put(GetIdEntryKey(entry.resource_id()), id);
  }

  // Put the entry itself.
  if (!entry.SerializeToString(&serialized_entry)) {
    DLOG(ERROR) << "Failed to serialize the entry: " << id;
    return FILE_ERROR_FAILED;
  }
  batch.Put(id, serialized_entry);

  status = resource_map_->Write(leveldb::WriteOptions(), &batch);
  return LevelDBStatusToFileError(status);
}

FileError ResourceMetadataStorage::GetEntry(const std::string& id,
                                            ResourceEntry* out_entry) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  DCHECK(!id.empty());

  std::string serialized_entry;
  const leveldb::Status status = resource_map_->Get(leveldb::ReadOptions(),
                                                    leveldb::Slice(id),
                                                    &serialized_entry);
  if (!status.ok())
    return LevelDBStatusToFileError(status);
  if (!out_entry->ParseFromString(serialized_entry))
    return FILE_ERROR_FAILED;
  return FILE_ERROR_OK;
}

FileError ResourceMetadataStorage::RemoveEntry(const std::string& id) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  DCHECK(!id.empty());

  ResourceEntry entry;
  FileError error = GetEntry(id, &entry);
  if (error != FILE_ERROR_OK)
    return error;

  leveldb::WriteBatch batch;

  // Remove from the parent.
  if (!entry.parent_local_id().empty())
    batch.Delete(GetChildEntryKey(entry.parent_local_id(), entry.base_name()));

  // Remove resource ID-local ID mapping entry.
  if (!entry.resource_id().empty())
    batch.Delete(GetIdEntryKey(entry.resource_id()));

  // Remove the entry itself.
  batch.Delete(id);

  const leveldb::Status status = resource_map_->Write(leveldb::WriteOptions(),
                                                      &batch);
  return LevelDBStatusToFileError(status);
}

std::unique_ptr<ResourceMetadataStorage::Iterator>
ResourceMetadataStorage::GetIterator() {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  std::unique_ptr<leveldb::Iterator> it(
      resource_map_->NewIterator(leveldb::ReadOptions()));
  return std::make_unique<Iterator>(std::move(it));
}

FileError ResourceMetadataStorage::GetChild(const std::string& parent_id,
                                            const std::string& child_name,
                                            std::string* child_id) const {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  DCHECK(!parent_id.empty());
  DCHECK(!child_name.empty());

  const leveldb::Status status =
      resource_map_->Get(
          leveldb::ReadOptions(),
          leveldb::Slice(GetChildEntryKey(parent_id, child_name)),
          child_id);
  return LevelDBStatusToFileError(status);
}

FileError ResourceMetadataStorage::GetChildren(
    const std::string& parent_id,
    std::vector<std::string>* children) const {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  DCHECK(!parent_id.empty());

  // Iterate over all entries with keys starting with |parent_id|.
  std::unique_ptr<leveldb::Iterator> it(
      resource_map_->NewIterator(leveldb::ReadOptions()));
  for (it->Seek(parent_id);
       it->Valid() && it->key().starts_with(leveldb::Slice(parent_id));
       it->Next()) {
    if (IsChildEntryKey(it->key()))
      children->push_back(it->value().ToString());
  }
  return LevelDBStatusToFileError(it->status());
}

FileError ResourceMetadataStorage::GetIdByResourceId(
    const std::string& resource_id,
    std::string* out_id) const {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  DCHECK(!resource_id.empty());

  const leveldb::Status status = resource_map_->Get(
      leveldb::ReadOptions(),
      leveldb::Slice(GetIdEntryKey(resource_id)),
      out_id);
  return LevelDBStatusToFileError(status);
}

ResourceMetadataStorage::RecoveredCacheInfo::RecoveredCacheInfo()
    : is_dirty(false) {}

ResourceMetadataStorage::RecoveredCacheInfo::~RecoveredCacheInfo() = default;

ResourceMetadataStorage::~ResourceMetadataStorage() {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
}

void ResourceMetadataStorage::DestroyOnBlockingPool() {
  delete this;
}

// static
std::string ResourceMetadataStorage::GetChildEntryKey(
    const std::string& parent_id,
    const std::string& child_name) {
  DCHECK(!parent_id.empty());
  DCHECK(!child_name.empty());

  std::string key = parent_id;
  key.push_back(kDBKeyDelimeter);
  key.append(child_name);
  key.push_back(kDBKeyDelimeter);
  return key;
}

FileError ResourceMetadataStorage::PutHeader(
    const ResourceMetadataHeader& header) {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  std::string serialized_header;
  if (!header.SerializeToString(&serialized_header)) {
    DLOG(ERROR) << "Failed to serialize the header";
    return FILE_ERROR_FAILED;
  }

  const leveldb::Status status = resource_map_->Put(
      leveldb::WriteOptions(),
      leveldb::Slice(GetHeaderDBKey()),
      leveldb::Slice(serialized_header));
  return LevelDBStatusToFileError(status);
}

FileError ResourceMetadataStorage::GetHeader(
    ResourceMetadataHeader* header) const {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  std::string serialized_header;
  const leveldb::Status status = resource_map_->Get(
      leveldb::ReadOptions(),
      leveldb::Slice(GetHeaderDBKey()),
      &serialized_header);
  if (!status.ok())
    return LevelDBStatusToFileError(status);
  return header->ParseFromString(serialized_header) ?
      FILE_ERROR_OK : FILE_ERROR_FAILED;
}

bool ResourceMetadataStorage::CheckValidity() {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);

  // Perform read with checksums verification enabled.
  leveldb::ReadOptions options;
  options.verify_checksums = true;

  std::unique_ptr<leveldb::Iterator> it(resource_map_->NewIterator(options));
  it->SeekToFirst();

  // DB is organized like this:
  //
  // <key>                          : <value>
  // "\0HEADER"                     : ResourceMetadataHeader
  // "\0ID\0|resource ID 1|"        : Local ID associated to resource ID 1.
  // "\0ID\0|resource ID 2|"        : Local ID associated to resource ID 2.
  // ...
  // "|ID of A|"                    : ResourceEntry for entry A.
  // "|ID of A|\0|child name 1|\0"  : ID of the 1st child entry of entry A.
  // "|ID of A|\0|child name 2|\0"  : ID of the 2nd child entry of entry A.
  // ...
  // "|ID of A|\0|child name n|\0"  : ID of the nth child entry of entry A.
  // "|ID of B|"                    : ResourceEntry for entry B.
  // ...

  // Check the header.
  ResourceMetadataHeader header;
  if (!it->Valid() ||
      it->key() != GetHeaderDBKey() ||  // Header entry must come first.
      !header.ParseFromArray(it->value().data(), it->value().size()) ||
      header.version() != kDBVersion) {
    DLOG(ERROR) << "Invalid header detected. version = " << header.version();
    RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_INVALID_HEADER);
    return false;
  }

  // First scan. Remember relationships between IDs.
  typedef std::unordered_map<std::string, std::string> KeyToIdMapping;
  KeyToIdMapping local_id_to_resource_id_map;
  KeyToIdMapping child_key_to_local_id_map;
  std::set<std::string> resource_entries;
  std::string first_resource_entry_key;
  for (it->Next(); it->Valid(); it->Next()) {
    if (IsChildEntryKey(it->key())) {
      child_key_to_local_id_map[it->key().ToString()] = it->value().ToString();
      continue;
    }

    if (IsIdEntryKey(it->key())) {
      const auto result = local_id_to_resource_id_map.insert(std::make_pair(
          it->value().ToString(),
          GetResourceIdFromIdEntryKey(it->key().ToString())));
      // Check that no local ID is associated with more than one resource ID.
      if (!result.second) {
        DLOG(ERROR) << "Broken ID entry.";
        RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_BROKEN_ID_ENTRY);
        return false;
      }
      continue;
    }

    // Remember the key of the first resource entry record, so the second scan
    // can start from this point.
    if (first_resource_entry_key.empty())
      first_resource_entry_key = it->key().ToString();

    resource_entries.insert(it->key().ToString());
  }

  // Second scan. Verify relationships and resource entry correctness.
  size_t num_entries_with_parent = 0;
  ResourceEntry entry;
  for (it->Seek(first_resource_entry_key); it->Valid(); it->Next()) {
    if (IsChildEntryKey(it->key()))
      continue;

    if (!entry.ParseFromArray(it->value().data(), it->value().size())) {
      DLOG(ERROR) << "Broken entry detected.";
      RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_BROKEN_ENTRY);
      return false;
    }

    // Resource-ID-to-local-ID mapping without entry for the local ID is OK,
    // but if it exists, then the resource ID must be consistent.
    const auto mapping_it =
        local_id_to_resource_id_map.find(it->key().ToString());
    if (mapping_it != local_id_to_resource_id_map.end() &&
        entry.resource_id() != mapping_it->second) {
      DLOG(ERROR) << "Broken ID entry.";
      RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_BROKEN_ID_ENTRY);
      return false;
    }

    // If the parent is referenced, then confirm that it exists and check the
    // parent-child relationships.
    if (!entry.parent_local_id().empty()) {
      const auto mapping_it = resource_entries.find(entry.parent_local_id());
      if (mapping_it == resource_entries.end()) {
        DLOG(ERROR) << "Parent entry not found.";
        RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_INVALID_PARENT_ID);
        return false;
      }

      // Check if parent-child relationship is stored correctly.
      const auto child_mapping_it = child_key_to_local_id_map.find(
          GetChildEntryKey(entry.parent_local_id(), entry.base_name()));
      if (child_mapping_it == child_key_to_local_id_map.end() ||
          leveldb::Slice(child_mapping_it->second) != it->key()) {
        DLOG(ERROR) << "Child map is broken.";
        RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_BROKEN_CHILD_MAP);
        return false;
      }
      ++num_entries_with_parent;
    }
  }

  if (!it->status().ok()) {
    DLOG(ERROR) << "Error during checking resource map. status = "
                << it->status().ToString();
    RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_ITERATOR_ERROR);
    return false;
  }

  if (child_key_to_local_id_map.size() != num_entries_with_parent) {
    DLOG(ERROR) << "Child entry count mismatch.";
    RecordCheckValidityFailure(
        CHECK_VALIDITY_FAILURE_CHILD_ENTRY_COUNT_MISMATCH);
    return false;
  }

  return true;
}

}  // namespace internal
}  // namespace drive
