Commit 5257edcf authored by Giorgio Azzinnaro's avatar Giorgio Azzinnaro

fixed Db template library and Server object creation

parent ff3221b3
......@@ -4,21 +4,11 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
set(CMAKE_CXX_STANDARD 14)
set(PROTOBUF_IMPORT_DIRS "${CMAKE_SOURCE_DIR}/src")
option(BUILD_SHARED_LIBS "Build libprofanedb.so, to embed ProfaneDB" ON)
option(BUILD_PROFANEDB_SERVER "Build ProfaneDB gRPC server" OFF)
# TODO Making stuff modular, each module will get its dir and dependencies
find_package(Threads REQUIRED)
find_package(Protobuf REQUIRED) # Protobuf does the serialisation for the DB
find_package(RocksDB REQUIRED) # RocksDB is used as storage
find_package(Boost REQUIRED COMPONENTS filesystem) # Boost Filesystem scans the .proto directory
# gRPC is only required by ProfaneDB server
if(BUILD_PROFANEDB_SERVER)
find_package(gRPC REQUIRED)
endif()
set(PROTOBUF_IMPORT_DIRS "${CMAKE_SOURCE_DIR}/src")
include_directories(${CMAKE_CURRENT_BINARY_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src)
......
......@@ -3,10 +3,10 @@ add_subdirectory(protobuf) # Generated Protobuf (& gRPC if neeeded) code
add_subdirectory(format)
add_subdirectory(vault)
add_library(profanedb db.cpp)
target_link_libraries(profanedb profanedb_format profanedb_vault profanedb_protobuf)
# TODO Maybe we could build for google::protobuf::Message somewhere
# add_library(profanedb db.cpp)
# target_link_libraries(profanedb profanedb_format profanedb_vault profanedb_protobuf)
# Nothing should depend on code in here, so it can be skipped entirely
if(BUILD_PROFANEDB_SERVER)
add_subdirectory(server)
endif()
/*
* ProfaneDB - A Protocol Buffers database.
* Copyright (C) 2017 "Giorgio Azzinnaro" <giorgio.azzinnaro@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "db.h"
template<typename Message>
profanedb::Db<Message>::Db(
std::shared_ptr< format::Marshaller<Message> > marshaller,
std::shared_ptr<profanedb::vault::Storage> storage)
: marshaller(marshaller)
, storage(storage)
{
}
template<typename Message>
profanedb::Db<Message>::~Db()
{
}
template<typename Message>
const Message & profanedb::Db<Message>::Get(const protobuf::Key & key) const
{
return this->marshaller->Unmarshal(this->storage->Retrieve(key));
}
template<typename Message>
bool profanedb::Db<Message>::Put(const Message & message)
{
this->storage->Store(this->marshaller->Marshal(message));
// TODO Check exceptions
return true;
}
template<typename Message>
bool profanedb::Db<Message>::Delete(const protobuf::Key & key)
{
// TODO in Storage
}
......@@ -34,18 +34,34 @@ template<typename Message>
class Db
{
public:
Db(
std::shared_ptr< format::Marshaller<Message> > marshaller,
std::shared_ptr<vault::Storage> storage);
~Db();
Db(std::shared_ptr<vault::Storage> storage,
std::shared_ptr< format::Marshaller<Message> > marshaller)
: storage(storage)
, marshaller(marshaller)
{
}
virtual const Message & Get(const protobuf::Key & key) const;
virtual bool Put(const Message & message);
virtual bool Delete(const protobuf::Key & key);
const Message & Get(const protobuf::Key & key) const
{
return this->marshaller->Unmarshal(this->storage->Retrieve(key));
}
bool Put(const Message & message)
{
this->storage->Store(this->marshaller->Marshal(message));
// TODO Check exceptions
return true;
}
bool Delete(const protobuf::Key & key)
{
// TODO
}
private:
std::shared_ptr< format::Marshaller<Message> > marshaller;
std::shared_ptr<vault::Storage> storage;
std::shared_ptr< format::Marshaller<Message> > marshaller;
};
}
......
add_library(profanedb_format protobuf/marshaller.cpp protobuf/loader.cpp)
find_package(Boost REQUIRED COMPONENTS filesystem) # Boost Filesystem scans the .proto directory
add_library(profanedb_format STATIC protobuf/marshaller.cpp protobuf/loader.cpp)
target_link_libraries(profanedb_format profanedb_protobuf ${Boost_LIBRARIES})
if(BUILD_SHARED_LIBS)
set_target_properties(profanedb_format PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
......@@ -29,8 +29,6 @@ template<typename Message>
class Marshaller
{
public:
virtual ~Marshaller() = 0;
virtual profanedb::protobuf::MessageTreeNode Marshal(const Message & message) = 0;
virtual const Message & Unmarshal(const profanedb::protobuf::StorableMessage & storable) = 0;
};
......
......@@ -32,17 +32,13 @@ using profanedb::protobuf::StorableMessage;
using profanedb::protobuf::Key;
profanedb::format::protobuf::Marshaller::Marshaller(
const Loader & loader,
const Storage & storage)
std::shared_ptr<Storage> storage,
std::shared_ptr<Loader> loader)
: loader(loader)
, storage(storage)
{
}
profanedb::format::protobuf::Marshaller::~Marshaller()
{
}
MessageTreeNode profanedb::format::protobuf::Marshaller::Marshal(const Message & message)
{
MessageTreeNode messageTree;
......@@ -51,7 +47,7 @@ MessageTreeNode profanedb::format::protobuf::Marshaller::Marshal(const Message &
// replacing references to other objects with their keys.
// It will then be serialized and set as storable message payload in messageTree;
Message * normalizedMessage =
this->messageFactory.GetPrototype(loader.GetNormalizedPool().FindMessageTypeByName(message.GetTypeName()))->New();
this->messageFactory.GetPrototype(loader->GetNormalizedPool().FindMessageTypeByName(message.GetTypeName()))->New();
// Only fields which are set in the message are processed
std::vector< const FieldDescriptor * > setFields;
......@@ -104,11 +100,11 @@ const Message & profanedb::format::protobuf::Marshaller::Unmarshal(const Storabl
{
// An empty normalized message is generated using the Key
Message * normalizedMessage = this->messageFactory.GetPrototype(
loader.GetNormalizedPool().FindMessageTypeByName(storable.key().message_type()))->New();
loader->GetNormalizedPool().FindMessageTypeByName(storable.key().message_type()))->New();
// The original message is also retrieved
Message * originalMessage = this->messageFactory.GetPrototype(
loader.GetSchemaPool().FindMessageTypeByName(storable.key().message_type()))->New();
loader->GetSchemaPool().FindMessageTypeByName(storable.key().message_type()))->New();
// StorableMessage payload contains the serialized normalized message,
// as previously stored into the DB
......@@ -129,7 +125,7 @@ const Message & profanedb::format::protobuf::Marshaller::Unmarshal(const Storabl
nestedKey.MergeFrom(normalizedMessage->GetReflection()->GetMessage(*normalizedMessage, normalizedField));
// Retrieve the nested message from storage and unmarshal it as well
const Message & nestedMessage = this->Unmarshal(this->storage.Retrieve(nestedKey));
const Message & nestedMessage = this->Unmarshal(this->storage->Retrieve(nestedKey));
// We need the original descriptor field to set the message
const FieldDescriptor * originalField = originalMessage->GetDescriptor()->field(normalizedField->index());
......
......@@ -20,6 +20,8 @@
#ifndef PROFANEDB_FORMAT_PROTOBUF_MARSHALLER_H
#define PROFANEDB_FORMAT_PROTOBUF_MARSHALLER_H
#include <memory>
#include <profanedb/protobuf/options.pb.h>
#include <profanedb/vault/storage.h>
......@@ -35,25 +37,24 @@ namespace profanedb {
namespace format {
namespace protobuf {
class Marshaller : profanedb::format::Marshaller<google::protobuf::Message>
class Marshaller : public profanedb::format::Marshaller<google::protobuf::Message>
{
public:
Marshaller(
const Loader & loader,
const profanedb::vault::Storage & storage
std::shared_ptr<profanedb::vault::Storage> storage,
std::shared_ptr<Loader> loader
);
~Marshaller();
virtual profanedb::protobuf::MessageTreeNode Marshal(const google::protobuf::Message & message) override;
virtual const google::protobuf::Message & Unmarshal(const profanedb::protobuf::StorableMessage & storable) override;
private:
// Loader contains the schemaPool and normalizedPool
const Loader & loader;
const std::shared_ptr<Loader> loader;
// Because a StorableMessage only holds references to its children objects,
// Storage is used to recursively retrieve them.
const profanedb::vault::Storage & storage;
const std::shared_ptr<profanedb::vault::Storage> storage;
google::protobuf::DynamicMessageFactory messageFactory;
......
find_package(Threads REQUIRED)
find_package(Protobuf REQUIRED) # Protobuf does the serialisation for the DB
# Protobuf messages should always be generated
file(GLOB Proto "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
PROTOBUF_GENERATE_CPP(PROTO_CC PROTO_H ${Proto})
......@@ -12,6 +15,8 @@ endif()
# libprofanedb_grpc.a has the service definitions, it's not required by the shared lib
if(BUILD_PROFANEDB_SERVER)
find_package(gRPC REQUIRED)
PROTOBUF_GENERATE_GRPC_CPP(GRPC_CC GRPC_H ${Proto})
add_library(profanedb_grpc STATIC ${GRPC_CC} ${GRPC_H})
target_link_libraries(profanedb_grpc profanedb_protobuf ${GRPC_LIBRARIES})
......
find_package(gRPC REQUIRED)
find_package(Boost REQUIRED COMPONENTS log)
add_definitions(-DBOOST_LOG_DYN_LINK) # This is for the Boost Log library to load the proper target namespace for the current platform
add_executable(profanedb_server main.cpp server.cpp)
target_link_libraries(profanedb_server profanedb profanedb_grpc)
target_link_libraries(profanedb_server ${Boost_LIBRARIES} profanedb_format profanedb_vault profanedb_grpc)
......@@ -20,23 +20,46 @@
#include "server.h"
using profanedb::format::protobuf::Loader;
using profanedb::format::Marshaller;
using ProtobufMarshaller = profanedb::format::protobuf::Marshaller;
using profanedb::vault::Storage;
using RocksStorage = profanedb::vault::rocksdb::Storage;
using google::protobuf::Message;
using grpc::ServerBuilder;
using rocksdb::DB;
profanedb::server::Server::Server()
{
boost::di::bind<profanedb::format::Marshaller<Message>>().to<ProtobufMarshaller>();
boost::di::bind<profanedb::vault::Storage>().to<RocksStorage>();
// TODO Config
boost::log::core::get()->set_filter(
boost::log::trivial::severity >= boost::log::trivial::debug
);
// TODO Config
rocksdb::Options rocksOptions;
rocksOptions.create_if_missing = true;
rocksdb::DB *rocks;
rocksdb::DB::Open(rocksOptions, "/tmp/profane", &rocks);
auto storage = std::make_shared<RocksStorage>(std::unique_ptr<rocksdb::DB>(rocks));
// TODO Should be from config
auto includeSourceTree = new Loader::RootSourceTree{
"/usr/include", "/home/giorgio/Documents/ProfaneDB/src"};
auto injector = boost::di::make_injector();
// service = std::make_unique<DbServiceImpl>(new DbServiceImpl(
// injector.create< profanedb::Db<google::protobuf::Message> >());
// TODO Config
auto schemaSourceTree = new Loader::RootSourceTree{"/home/giorgio/Documents/ProfaneDB/test"};
auto loader = std::make_shared<Loader>(
std::unique_ptr<Loader::RootSourceTree>(includeSourceTree),
std::unique_ptr<Loader::RootSourceTree>(schemaSourceTree));
auto marshaller = std::make_shared<ProtobufMarshaller>(storage, loader);
service = std::make_unique<DbServiceImpl>(
std::make_unique< profanedb::Db<Message> >(storage, marshaller));
}
profanedb::server::Server::~Server()
......@@ -55,7 +78,7 @@ void profanedb::server::Server::Run()
server = builder.BuildAndStart();
std::cout << "Server listening on " << address << std::endl;
BOOST_LOG_TRIVIAL(info) << "Server listening on " << address << std::endl;
HandleRpcs();
}
......@@ -65,20 +88,24 @@ void profanedb::server::Server::HandleRpcs()
server->Wait();
}
profanedb::server::Server::DbServiceImpl::DbServiceImpl(profanedb::Db<Message> & profanedb)
: profanedb(profanedb)
profanedb::server::Server::DbServiceImpl::DbServiceImpl(std::unique_ptr< profanedb::Db<Message> > profane)
: profane(std::move(profane))
{
}
grpc::Status profanedb::server::Server::DbServiceImpl::Get(grpc::ServerContext * context, const profanedb::protobuf::GetReq * request, profanedb::protobuf::GetResp * response)
{
response->mutable_message()->PackFrom(this->profanedb.Get(request->key()));
BOOST_LOG_TRIVIAL(debug) << "GET request from " << context->peer();
response->mutable_message()->PackFrom(this->profane->Get(request->key()));
return grpc::Status::OK;
}
grpc::Status profanedb::server::Server::DbServiceImpl::Put(grpc::ServerContext * context, const profanedb::protobuf::PutReq * request, profanedb::protobuf::PutResp * response)
{
BOOST_LOG_TRIVIAL(debug) << "PUT request from " << context->peer();
// TODO Unpack
// this->profanedb.Put(request->serializable());
......@@ -87,6 +114,7 @@ grpc::Status profanedb::server::Server::DbServiceImpl::Put(grpc::ServerContext *
grpc::Status profanedb::server::Server::DbServiceImpl::Delete(grpc::ServerContext * context, const profanedb::protobuf::DelReq * request, profanedb::protobuf::DelResp * response)
{
BOOST_LOG_TRIVIAL(debug) << "DELETE request from " << context->peer();
return grpc::Status::OK;
}
......@@ -27,15 +27,19 @@
#include <grpc/support/log.h>
#include <boost/di.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <profanedb/format/protobuf/marshaller.h>
#include <profanedb/vault/rocksdb/storage.h>
#include <profanedb/db.h>
#include <profanedb/db.hpp>
namespace profanedb {
namespace server {
// This is a thin layer to use ProfaneDB with gRPC
// This is a layer to use ProfaneDB with gRPC and Protobuf objects
class Server
{
public:
......@@ -51,7 +55,7 @@ private:
class DbServiceImpl : public profanedb::protobuf::Db::Service {
public:
DbServiceImpl(profanedb::Db<google::protobuf::Message> & profanedb);
DbServiceImpl(std::unique_ptr< profanedb::Db<google::protobuf::Message> > profane);
grpc::Status Get(grpc::ServerContext * context, const profanedb::protobuf::GetReq * request, profanedb::protobuf::GetResp* response) override;
......@@ -60,7 +64,7 @@ private:
grpc::Status Delete(grpc::ServerContext * context, const profanedb::protobuf::DelReq * request, profanedb::protobuf::DelResp * response) override;
private:
profanedb::Db<google::protobuf::Message> & profanedb;
std::unique_ptr< profanedb::Db<google::protobuf::Message> > profane;
};
std::unique_ptr<DbServiceImpl> service;
};
......
add_library(profanedb_vault rocksdb/storage.cpp)
find_package(RocksDB REQUIRED) # RocksDB is used as storage
add_library(profanedb_vault STATIC rocksdb/storage.cpp)
target_link_libraries(profanedb_vault profanedb_protobuf ${ROCKSDB_LIBRARIES})
if(BUILD_SHARED_LIBS)
set_target_properties(profanedb_vault PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
......@@ -19,8 +19,8 @@
#include "storage.h"
profanedb::vault::rocksdb::Storage::Storage(std::shared_ptr<DB> rocksDb)
: rocksDb(rocksDb)
profanedb::vault::rocksdb::Storage::Storage(std::unique_ptr<DB> rocksDb)
: rocksDb(std::move(rocksDb))
{
}
......
......@@ -30,16 +30,16 @@ namespace profanedb {
namespace vault {
namespace rocksdb {
class Storage : profanedb::vault::Storage
class Storage : public profanedb::vault::Storage
{
public:
Storage(std::shared_ptr<DB> rocksDb);
Storage(std::unique_ptr<DB> rocksDb);
virtual void Store(const profanedb::protobuf::StorableMessage & storable) override;
virtual profanedb::protobuf::StorableMessage Retrieve(const profanedb::protobuf::Key & key) const override;
private:
const std::shared_ptr<DB> rocksDb;
const std::unique_ptr<DB> rocksDb;
};
}
}
......
......@@ -28,8 +28,6 @@ namespace vault {
// Storage takes care of saving and retrieving the data from the actual DB
class Storage {
public:
virtual ~Storage() = 0;
virtual void Store(const protobuf::StorableMessage & storable) = 0;
virtual protobuf::StorableMessage Retrieve(const protobuf::Key & key) const = 0;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment