// Copyright 2014 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 "extensions/browser/value_store/leveldb_value_store.h"

#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/value_store/value_store_util.h"
#include "third_party/leveldatabase/src/include/leveldb/iterator.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"

namespace util = value_store_util;
using content::BrowserThread;

namespace {

const char kInvalidJson[] = "Invalid JSON";
const char kCannotSerialize[] = "Cannot serialize value to JSON";

// Scoped leveldb snapshot which releases the snapshot on destruction.
class ScopedSnapshot {
 public:
  explicit ScopedSnapshot(leveldb::DB* db)
      : db_(db), snapshot_(db->GetSnapshot()) {}

  ~ScopedSnapshot() {
    db_->ReleaseSnapshot(snapshot_);
  }

  const leveldb::Snapshot* get() {
    return snapshot_;
  }

 private:
  leveldb::DB* db_;
  const leveldb::Snapshot* snapshot_;

  DISALLOW_COPY_AND_ASSIGN(ScopedSnapshot);
};

}  // namespace

LeveldbValueStore::LeveldbValueStore(const base::FilePath& db_path)
    : db_path_(db_path) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  scoped_ptr<Error> open_error = EnsureDbIsOpen();
  if (open_error)
    LOG(WARNING) << open_error->message;
}

LeveldbValueStore::~LeveldbValueStore() {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  // Delete the database from disk if it's empty (but only if we managed to
  // open it!). This is safe on destruction, assuming that we have exclusive
  // access to the database.
  if (db_ && IsEmpty())
    DeleteDbFile();
}

size_t LeveldbValueStore::GetBytesInUse(const std::string& key) {
  // Let SettingsStorageQuotaEnforcer implement this.
  NOTREACHED() << "Not implemented";
  return 0;
}

size_t LeveldbValueStore::GetBytesInUse(
    const std::vector<std::string>& keys) {
  // Let SettingsStorageQuotaEnforcer implement this.
  NOTREACHED() << "Not implemented";
  return 0;
}

size_t LeveldbValueStore::GetBytesInUse() {
  // Let SettingsStorageQuotaEnforcer implement this.
  NOTREACHED() << "Not implemented";
  return 0;
}

ValueStore::ReadResult LeveldbValueStore::Get(const std::string& key) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  scoped_ptr<Error> open_error = EnsureDbIsOpen();
  if (open_error)
    return MakeReadResult(open_error.Pass());

  scoped_ptr<base::Value> setting;
  scoped_ptr<Error> error = ReadFromDb(leveldb::ReadOptions(), key, &setting);
  if (error)
    return MakeReadResult(error.Pass());

  base::DictionaryValue* settings = new base::DictionaryValue();
  if (setting)
    settings->SetWithoutPathExpansion(key, setting.release());
  return MakeReadResult(make_scoped_ptr(settings));
}

ValueStore::ReadResult LeveldbValueStore::Get(
    const std::vector<std::string>& keys) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  scoped_ptr<Error> open_error = EnsureDbIsOpen();
  if (open_error)
    return MakeReadResult(open_error.Pass());

  leveldb::ReadOptions options;
  scoped_ptr<base::DictionaryValue> settings(new base::DictionaryValue());

  // All interaction with the db is done on the same thread, so snapshotting
  // isn't strictly necessary.  This is just defensive.
  ScopedSnapshot snapshot(db_.get());
  options.snapshot = snapshot.get();
  for (std::vector<std::string>::const_iterator it = keys.begin();
      it != keys.end(); ++it) {
    scoped_ptr<base::Value> setting;
    scoped_ptr<Error> error = ReadFromDb(options, *it, &setting);
    if (error)
      return MakeReadResult(error.Pass());
    if (setting)
      settings->SetWithoutPathExpansion(*it, setting.release());
  }

  return MakeReadResult(settings.Pass());
}

ValueStore::ReadResult LeveldbValueStore::Get() {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  scoped_ptr<Error> open_error = EnsureDbIsOpen();
  if (open_error)
    return MakeReadResult(open_error.Pass());

  base::JSONReader json_reader;
  leveldb::ReadOptions options = leveldb::ReadOptions();
  // All interaction with the db is done on the same thread, so snapshotting
  // isn't strictly necessary.  This is just defensive.
  scoped_ptr<base::DictionaryValue> settings(new base::DictionaryValue());

  ScopedSnapshot snapshot(db_.get());
  options.snapshot = snapshot.get();
  scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    std::string key = it->key().ToString();
    base::Value* value = json_reader.ReadToValue(it->value().ToString());
    if (!value) {
      return MakeReadResult(
          Error::Create(CORRUPTION, kInvalidJson, util::NewKey(key)));
    }
    settings->SetWithoutPathExpansion(key, value);
  }

  if (it->status().IsNotFound()) {
    NOTREACHED() << "IsNotFound() but iterating over all keys?!";
    return MakeReadResult(settings.Pass());
  }

  if (!it->status().ok())
    return MakeReadResult(ToValueStoreError(it->status(), util::NoKey()));

  return MakeReadResult(settings.Pass());
}

ValueStore::WriteResult LeveldbValueStore::Set(
    WriteOptions options, const std::string& key, const base::Value& value) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  scoped_ptr<Error> open_error = EnsureDbIsOpen();
  if (open_error)
    return MakeWriteResult(open_error.Pass());

  leveldb::WriteBatch batch;
  scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());
  scoped_ptr<Error> batch_error =
      AddToBatch(options, key, value, &batch, changes.get());
  if (batch_error)
    return MakeWriteResult(batch_error.Pass());

  scoped_ptr<Error> write_error = WriteToDb(&batch);
  return write_error ? MakeWriteResult(write_error.Pass())
                     : MakeWriteResult(changes.Pass());
}

ValueStore::WriteResult LeveldbValueStore::Set(
    WriteOptions options, const base::DictionaryValue& settings) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  scoped_ptr<Error> open_error = EnsureDbIsOpen();
  if (open_error)
    return MakeWriteResult(open_error.Pass());

  leveldb::WriteBatch batch;
  scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());

  for (base::DictionaryValue::Iterator it(settings);
       !it.IsAtEnd(); it.Advance()) {
    scoped_ptr<Error> batch_error =
        AddToBatch(options, it.key(), it.value(), &batch, changes.get());
    if (batch_error)
      return MakeWriteResult(batch_error.Pass());
  }

  scoped_ptr<Error> write_error = WriteToDb(&batch);
  return write_error ? MakeWriteResult(write_error.Pass())
                     : MakeWriteResult(changes.Pass());
}

ValueStore::WriteResult LeveldbValueStore::Remove(const std::string& key) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  return Remove(std::vector<std::string>(1, key));
}

ValueStore::WriteResult LeveldbValueStore::Remove(
    const std::vector<std::string>& keys) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  scoped_ptr<Error> open_error = EnsureDbIsOpen();
  if (open_error)
    return MakeWriteResult(open_error.Pass());

  leveldb::WriteBatch batch;
  scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());

  for (std::vector<std::string>::const_iterator it = keys.begin();
      it != keys.end(); ++it) {
    scoped_ptr<base::Value> old_value;
    scoped_ptr<Error> read_error =
        ReadFromDb(leveldb::ReadOptions(), *it, &old_value);
    if (read_error)
      return MakeWriteResult(read_error.Pass());

    if (old_value) {
      changes->push_back(ValueStoreChange(*it, old_value.release(), NULL));
      batch.Delete(*it);
    }
  }

  leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch);
  if (!status.ok() && !status.IsNotFound())
    return MakeWriteResult(ToValueStoreError(status, util::NoKey()));
  return MakeWriteResult(changes.Pass());
}

ValueStore::WriteResult LeveldbValueStore::Clear() {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());

  ReadResult read_result = Get();
  if (read_result->HasError())
    return MakeWriteResult(read_result->PassError());

  base::DictionaryValue& whole_db = read_result->settings();
  while (!whole_db.empty()) {
    std::string next_key = base::DictionaryValue::Iterator(whole_db).key();
    scoped_ptr<base::Value> next_value;
    whole_db.RemoveWithoutPathExpansion(next_key, &next_value);
    changes->push_back(
        ValueStoreChange(next_key, next_value.release(), NULL));
  }

  DeleteDbFile();
  return MakeWriteResult(changes.Pass());
}

bool LeveldbValueStore::Restore() {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  ReadResult result = Get();
  std::string previous_key;
  while (result->IsCorrupted()) {
    // If we don't have a specific corrupted key, or we've tried and failed to
    // clear this specific key, or we fail to restore the key, then wipe the
    // whole database.
    if (!result->error().key.get() || *result->error().key == previous_key ||
        !RestoreKey(*result->error().key)) {
      DeleteDbFile();
      result = Get();
      break;
    }

    // Otherwise, re-Get() the database to check if there is still any
    // corruption.
    previous_key = *result->error().key;
    result = Get();
  }

  // If we still have an error, it means we've tried deleting the database file,
  // and failed. There's nothing more we can do.
  return !result->IsCorrupted();
}

bool LeveldbValueStore::RestoreKey(const std::string& key) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  ReadResult result = Get(key);
  if (result->IsCorrupted()) {
    leveldb::WriteBatch batch;
    batch.Delete(key);
    scoped_ptr<ValueStore::Error> error = WriteToDb(&batch);
    // If we can't delete the key, the restore failed.
    if (error.get())
      return false;
    result = Get(key);
  }

  // The restore succeeded if there is no corruption error.
  return !result->IsCorrupted();
}

bool LeveldbValueStore::WriteToDbForTest(leveldb::WriteBatch* batch) {
  return !WriteToDb(batch).get();
}

scoped_ptr<ValueStore::Error> LeveldbValueStore::EnsureDbIsOpen() {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);

  if (db_)
    return util::NoError();

  leveldb::Options options;
  options.max_open_files = 0;  // Use minimum.
  options.create_if_missing = true;

  leveldb::DB* db = NULL;
  leveldb::Status status =
      leveldb::DB::Open(options, db_path_.AsUTF8Unsafe(), &db);
  if (!status.ok())
    return ToValueStoreError(status, util::NoKey());

  CHECK(db);
  db_.reset(db);
  return util::NoError();
}

scoped_ptr<ValueStore::Error> LeveldbValueStore::ReadFromDb(
    leveldb::ReadOptions options,
    const std::string& key,
    scoped_ptr<base::Value>* setting) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  DCHECK(setting);

  std::string value_as_json;
  leveldb::Status s = db_->Get(options, key, &value_as_json);

  if (s.IsNotFound()) {
    // Despite there being no value, it was still a success. Check this first
    // because ok() is false on IsNotFound.
    return util::NoError();
  }

  if (!s.ok())
    return ToValueStoreError(s, util::NewKey(key));

  base::Value* value = base::JSONReader().ReadToValue(value_as_json);
  if (!value)
    return Error::Create(CORRUPTION, kInvalidJson, util::NewKey(key));

  setting->reset(value);
  return util::NoError();
}

scoped_ptr<ValueStore::Error> LeveldbValueStore::AddToBatch(
    ValueStore::WriteOptions options,
    const std::string& key,
    const base::Value& value,
    leveldb::WriteBatch* batch,
    ValueStoreChangeList* changes) {
  bool write_new_value = true;

  if (!(options & NO_GENERATE_CHANGES)) {
    scoped_ptr<base::Value> old_value;
    scoped_ptr<Error> read_error =
        ReadFromDb(leveldb::ReadOptions(), key, &old_value);
    if (read_error)
      return read_error.Pass();
    if (!old_value || !old_value->Equals(&value)) {
      changes->push_back(
          ValueStoreChange(key, old_value.release(), value.DeepCopy()));
    } else {
      write_new_value = false;
    }
  }

  if (write_new_value) {
    std::string value_as_json;
    if (!base::JSONWriter::Write(&value, &value_as_json))
      return Error::Create(OTHER_ERROR, kCannotSerialize, util::NewKey(key));
    batch->Put(key, value_as_json);
  }

  return util::NoError();
}

scoped_ptr<ValueStore::Error> LeveldbValueStore::WriteToDb(
    leveldb::WriteBatch* batch) {
  leveldb::Status status = db_->Write(leveldb::WriteOptions(), batch);
  return status.ok() ? util::NoError()
                     : ToValueStoreError(status, util::NoKey());
}

bool LeveldbValueStore::IsEmpty() {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions()));

  it->SeekToFirst();
  bool is_empty = !it->Valid();
  if (!it->status().ok()) {
    LOG(ERROR) << "Checking DB emptiness failed: " << it->status().ToString();
    return false;
  }
  return is_empty;
}

void LeveldbValueStore::DeleteDbFile() {
  db_.reset();  // release any lock on the directory
  if (!base::DeleteFile(db_path_, true /* recursive */)) {
    LOG(WARNING) << "Failed to delete LeveldbValueStore database at " <<
        db_path_.value();
  }
}

scoped_ptr<ValueStore::Error> LeveldbValueStore::ToValueStoreError(
    const leveldb::Status& status,
    scoped_ptr<std::string> key) {
  CHECK(!status.ok());
  CHECK(!status.IsNotFound());  // not an error

  std::string message = status.ToString();
  // The message may contain |db_path_|, which may be considered sensitive
  // data, and those strings are passed to the extension, so strip it out.
  ReplaceSubstringsAfterOffset(&message, 0u, db_path_.AsUTF8Unsafe(), "...");

  return Error::Create(CORRUPTION, message, key.Pass());
}
