#pragma once #include #include #include #include "database/counters.hpp" #include "database/storage.hpp" #include "database/storage_gc.hpp" #include "durability/wal.hpp" #include "io/network/endpoint.hpp" #include "storage/concurrent_id_mapper.hpp" #include "storage/types.hpp" #include "transactions/engine.hpp" #include "utils/scheduler.hpp" namespace database { /// Database configuration. Initialized from flags, but modifiable. struct Config { Config(); // Durability flags. bool durability_enabled; std::string durability_directory; bool db_recover_on_startup; int snapshot_cycle_sec; int snapshot_max_retained; int snapshot_on_exit; // Misc flags. int gc_cycle_sec; int query_execution_time_sec; // set of properties which will be stored on disk std::vector properties_on_disk; // Distributed master/worker flags. bool dynamic_graph_partitioner_enabled{false}; int rpc_num_workers{0}; int worker_id{0}; io::network::Endpoint master_endpoint{"0.0.0.0", 0}; io::network::Endpoint worker_endpoint{"0.0.0.0", 0}; int recovering_cluster_size{0}; }; class GraphDbAccessor; /// An abstract base class for a SingleNode/Master/Worker graph db. /// /// Always be sure that GraphDb object is destructed before main exits, i. e. /// GraphDb object shouldn't be part of global/static variable, except if its /// destructor is explicitly called before main exits. Consider code: /// /// GraphDb db; // KeyIndex is created as a part of database::Storage /// int main() { /// GraphDbAccessor dba(db); /// auto v = dba.InsertVertex(); /// v.add_label(dba.Label( /// "Start")); // New SkipList is created in KeyIndex for LabelIndex. /// // That SkipList creates SkipListGc which /// // initialises static Executor object. /// return 0; /// } /// /// After main exits: 1. Executor is destructed, 2. KeyIndex is destructed. /// Destructor of KeyIndex calls delete on created SkipLists which destroy /// SkipListGc that tries to use Excutioner object that doesn't exist anymore. /// -> CRASH class GraphDb { public: enum class Type { SINGLE_NODE, DISTRIBUTED_MASTER, DISTRIBUTED_WORKER }; GraphDb() {} GraphDb(const GraphDb &) = delete; GraphDb(GraphDb &&) = delete; GraphDb &operator=(const GraphDb &) = delete; GraphDb &operator=(GraphDb &&) = delete; virtual ~GraphDb() {} virtual Type type() const = 0; /// Create a new accessor by starting a new transaction. virtual std::unique_ptr Access() = 0; /// Create an accessor for a running transaction. virtual std::unique_ptr Access(tx::TransactionId) = 0; virtual Storage &storage() = 0; virtual durability::WriteAheadLog &wal() = 0; virtual tx::Engine &tx_engine() = 0; virtual storage::ConcurrentIdMapper &label_mapper() = 0; virtual storage::ConcurrentIdMapper &edge_type_mapper() = 0; virtual storage::ConcurrentIdMapper &property_mapper() = 0; virtual database::Counters &counters() = 0; virtual void CollectGarbage() = 0; /// Makes a snapshot from the visibility of the given accessor virtual bool MakeSnapshot(GraphDbAccessor &accessor) = 0; /// Releases the storage object safely and creates a new object. /// This is needed because of recovery, otherwise we might try to recover into /// a storage which has already been polluted because of a failed previous /// recovery virtual void ReinitializeStorage() = 0; /// When this is false, no new transactions should be created. bool is_accepting_transactions() const { return is_accepting_transactions_; } protected: std::atomic is_accepting_transactions_{true}; }; namespace impl { class SingleNode; } // namespace impl class SingleNode final : public GraphDb { public: explicit SingleNode(Config config = Config()); ~SingleNode(); Type type() const override { return GraphDb::Type::SINGLE_NODE; } std::unique_ptr Access() override; std::unique_ptr Access(tx::TransactionId) override; Storage &storage() override; durability::WriteAheadLog &wal() override; tx::Engine &tx_engine() override; storage::ConcurrentIdMapper &label_mapper() override; storage::ConcurrentIdMapper &edge_type_mapper() override; storage::ConcurrentIdMapper &property_mapper() override; database::Counters &counters() override; void CollectGarbage() override; bool MakeSnapshot(GraphDbAccessor &accessor) override; void ReinitializeStorage() override; private: std::unique_ptr impl_; std::unique_ptr snapshot_creator_; utils::Scheduler transaction_killer_; }; } // namespace database