blob: b30379943e86a7581de3a88db4b1d8b53d8f6efd [file] [log] [blame]
// Copyright 2015 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.
#ifndef SYNC_INTERNAL_API_PUBLIC_MODEL_TYPE_STORE_BACKEND_H_
#define SYNC_INTERNAL_API_PUBLIC_MODEL_TYPE_STORE_BACKEND_H_
#include <memory>
#include <string>
#include <unordered_map>
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/threading/thread_collision_warner.h"
#include "sync/api/model_type_store.h"
#include "sync/base/sync_export.h"
namespace leveldb {
class DB;
class Env;
class WriteBatch;
} // namespace leveldb
namespace syncer_v2 {
// ModelTypeStoreBackend handles operations with leveldb. It is oblivious of the
// fact that it is called from separate thread (with the exception of ctor),
// meaning it shouldn't deal with callbacks and task_runners.
class SYNC_EXPORT ModelTypeStoreBackend
: public base::RefCountedThreadSafe<ModelTypeStoreBackend> {
public:
typedef std::unordered_map<std::string, ModelTypeStoreBackend*> BackendMap;
// Helper function to create in memory environment for leveldb.
static std::unique_ptr<leveldb::Env> CreateInMemoryEnv();
// GetOrCreateBackend will check if |backend_map_| has a backend with same
// |path|. If |backend_map_| has one, wrap that backend to scoped_refptr and
// return. If |backend_map_| does not have, create a backend and store it into
// |backend_map_|.
static scoped_refptr<ModelTypeStoreBackend> GetOrCreateBackend(
const std::string& path,
std::unique_ptr<leveldb::Env> env,
ModelTypeStore::Result* result);
// Reads records with keys formed by prepending ids from |id_list| with
// |prefix|. If the record is found its id (without prefix) and value is
// appended to record_list. If record is not found its id is appended to
// |missing_id_list|. It is not an error that records for ids are not found so
// function will still return success in this case.
ModelTypeStore::Result ReadRecordsWithPrefix(
const std::string& prefix,
const ModelTypeStore::IdList& id_list,
ModelTypeStore::RecordList* record_list,
ModelTypeStore::IdList* missing_id_list);
// Reads all records with keys starting with |prefix|. Prefix is removed from
// key before it is added to |record_list|.
ModelTypeStore::Result ReadAllRecordsWithPrefix(
const std::string& prefix,
ModelTypeStore::RecordList* record_list);
// Writes modifications accumulated in |write_batch| to database.
ModelTypeStore::Result WriteModifications(
std::unique_ptr<leveldb::WriteBatch> write_batch);
private:
friend class base::RefCountedThreadSafe<ModelTypeStoreBackend>;
friend class ModelTypeStoreBackendTest;
ModelTypeStoreBackend(const std::string& path);
~ModelTypeStoreBackend();
// In some scenarios ModelTypeStoreBackend holds ownership of env. Typical
// example is when test creates in memory environment with CreateInMemoryEnv
// and wants it to be destroyed along with backend. This is achieved by
// passing ownership of env to TakeEnvOwnership function.
//
// env_ declaration should appear before declaration of db_ because
// environment object should still be valid when db_'s destructor is called.
std::unique_ptr<leveldb::Env> env_;
std::unique_ptr<leveldb::DB> db_;
std::string path_;
// backend_map_ holds raw pointer of backend, and when stores ask for backend,
// GetOrCreateBackend will return scoped_refptr of backend. backend_map_
// doesn't take reference to backend, therefore doesn't block backend
// destruction.
static base::LazyInstance<BackendMap> backend_map_;
// Init opens database at |path|. If database doesn't exist it creates one.
// Normally |env| should be nullptr, this causes leveldb to use default disk
// based environment from leveldb::Env::Default().
// Providing |env| allows to override environment used by leveldb for tests
// with in-memory or faulty environment.
ModelTypeStore::Result Init(const std::string& path,
std::unique_ptr<leveldb::Env> env);
// Macro wrapped mutex to guard against concurrent calls in debug builds.
DFAKE_MUTEX(push_pop_);
DISALLOW_COPY_AND_ASSIGN(ModelTypeStoreBackend);
};
} // namespace syncer_v2
#endif // SYNC_INTERNAL_API_PUBLIC_MODEL_TYPE_STORE_BACKEND_H_