diff --git a/CI/docker/chornolog.dockerfile b/CI/docker/chornolog.dockerfile new file mode 100644 index 00000000..6062b9d4 --- /dev/null +++ b/CI/docker/chornolog.dockerfile @@ -0,0 +1,33 @@ +# Use scs-lab/base:1.0 as base image +FROM spack/ubuntu-jammy:latest as coeus-builder +ENV DOCKER_TAG=0.2 + +# What we want to install and how we want to install it +# is specified in a manifest file (spack.yaml) +RUN mkdir /opt/spack-environment \ +&& (echo "spack:" \ +&& echo " specs:" \ +&& echo " - cmake@3.25.1" \ +&& echo " - mpich@4.0.2~fortran +verbs +argobots ^libfabric@1.16.1 fabrics=mlx,rxd,rxm,shm,sockets,tcp,udp,verbs" \ +&& echo " - mochi-thallium@0.10.1 ^libfabric@1.16.1 fabrics=mlx,rxd,rxm,shm,sockets,tcp,udp,verbs" \ +&& echo " - mochi-margo@0.13 ^libfabric@1.16.1 fabrics=mlx,rxd,rxm,shm,sockets,tcp,udp,verbs" \ +&& echo " - mercury@2.2.0~boostsys ^libfabric@1.16.1 fabrics=mlx,rxd,rxm,shm,sockets,tcp,udp,verbs" \ +&& echo " - boost@1.80.0" \ +&& echo " concretizer:" \ +&& echo " unify: true" \ +&& echo " config:" \ +&& echo " install_tree: /opt/software" \ +&& echo " view: /opt/view") > /opt/spack-environment/spack.yaml + +# Install the software, remove unnecessary deps +RUN cd /opt/spack-environment && spack env activate . && spack install --fail-fast && spack gc -y + +FROM ubuntu:22.04 +ENV DEBIAN_FRONTEND="noninteractive" + +RUN apt-get update -y && apt-get upgrade -y +RUN apt-get install -y pkg-config cmake build-essential environment-modules gfortran git python3 gdb + +COPY --from=coeus-builder /opt/spack-environment /opt/spack-environment +COPY --from=coeus-builder /opt/software /opt/software +COPY --from=coeus-builder /opt/view /usr \ No newline at end of file diff --git a/CI/docker/chronolog-ssh.dockerfile b/CI/docker/chronolog-ssh.dockerfile new file mode 100644 index 00000000..169d0719 --- /dev/null +++ b/CI/docker/chronolog-ssh.dockerfile @@ -0,0 +1,15 @@ +FROM scslab/chronolog:0.1 +ENV DEBIAN_FRONTEND="noninteractive" + +RUN apt-get install -y openssh-server sudo + +RUN passwd -d root + +RUN mkdir /var/run/sshd +RUN sed -i'' -e's/^#PermitRootLogin prohibit-password$/PermitRootLogin yes/' /etc/ssh/sshd_config \ + && sed -i'' -e's/^#PasswordAuthentication yes$/PasswordAuthentication yes/' /etc/ssh/sshd_config \ + && sed -i'' -e's/^#PermitEmptyPasswords no$/PermitEmptyPasswords yes/' /etc/ssh/sshd_config \ + && sed -i'' -e's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config + +EXPOSE 22 +CMD ["/usr/bin/sudo", "/usr/sbin/sshd", "-D"] diff --git a/CMakeLists.txt b/CMakeLists.txt index 01ddad0b..23ad4071 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,7 @@ option(CHRONOLOG_ENABLE_DOXYGEN "Enable Doxygen documentation generation." OFF) # add_compile_options(-Wextra) #endif() +#set(CMAKE_BUILD_TYPE "Debug") # Change some compilation flags depending on the build type if(CMAKE_BUILD_TYPE STREQUAL "Debug") message("Compiling ChronoLog in Debug Mode") @@ -133,7 +134,7 @@ endif() #----------------------------------------------------------------------------- # Dependencies common to all subdirectories #----------------------------------------------------------------------------- -find_package(MPI REQUIRED COMPONENTS CXX) +#find_package(MPI REQUIRED COMPONENTS CXX) find_package(Boost REQUIRED) find_package(Thallium REQUIRED) #find_library(ROCKSDB_LIB rocksdb) @@ -201,18 +202,22 @@ if(CHRONOLOG_BUILD_TESTING) endif() # External header only libraries -add_subdirectory(external_libs) +#add_subdirectory(external_libs) -add_subdirectory(tools) +#add_subdirectory(tools) + +# ChronoLog client library +add_subdirectory(Client) # ChronoVisor -add_subdirectory(ChronoAPI) +#add_subdirectory(ChronoAPI) # ChronoVisor add_subdirectory(ChronoVisor) -# ChronoLog client library -add_subdirectory(Client) +# ChronoKeeper +add_subdirectory(ChronoKeeper) + # custom add_custom_target(make_all cd ${CMAKE_BINARY_DIR} && make) diff --git a/ChronoAPI/ChronoLog/include/ChronoLog.h b/ChronoAPI/ChronoLog/include/ChronoLog.h deleted file mode 100644 index 495168f3..00000000 --- a/ChronoAPI/ChronoLog/include/ChronoLog.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by jaime on 2/14/2022. -// - -#ifndef SOCKETPP_API_INCLUDE_CHRONOLOG_H_ -#define SOCKETPP_API_INCLUDE_CHRONOLOG_H_ - -class ChronoLog { - -}; - -#endif //SOCKETPP_API_INCLUDE_CHRONOLOG_H_ diff --git a/ChronoAPI/ChronoLog/include/ClocksourceManager.h b/ChronoAPI/ChronoLog/include/ClocksourceManager.h index 51c0f115..a61a79a9 100644 --- a/ChronoAPI/ChronoLog/include/ClocksourceManager.h +++ b/ChronoAPI/ChronoLog/include/ClocksourceManager.h @@ -10,12 +10,15 @@ #include #include #include -#include +//#include #include #include +#ifdef TSC_ENABLED +#include #define lfence() _mm_lfence() #define mfence() _mm_mfence() +#endif class Clocksource { public: @@ -38,6 +41,7 @@ class ClocksourceCStyle : public Clocksource { } }; +#ifdef TSC_ENABLED class ClocksourceTSC : public Clocksource { public: uint64_t getTimestamp() override { @@ -47,6 +51,8 @@ class ClocksourceTSC : public Clocksource { return t; } }; +#endif + class ClocksourceCPPStyle : public Clocksource { public: uint64_t getTimestamp() override { diff --git a/ChronoAPI/ChronoLog/include/RPCVisor.h b/ChronoAPI/ChronoLog/include/RPCVisor.h index e9caa939..a3f5ce17 100644 --- a/ChronoAPI/ChronoLog/include/RPCVisor.h +++ b/ChronoAPI/ChronoLog/include/RPCVisor.h @@ -16,46 +16,53 @@ #include "RPCFactory.h" #include "ClientRegistryManager.h" #include "ChronicleMetaDirectory.h" +#include "KeeperRegistry.h" + class RPCVisor { public: - RPCVisor() { + RPCVisor(chronolog::KeeperRegistry * keeper_registry) + : keeperRegistry(keeper_registry) + { LOGD("%s constructor is called", typeid(*this).name()); - rpc = std::make_shared(); + clientManager = ChronoLog::Singleton::GetInstance(); + chronicleMetaDirectory = ChronoLog::Singleton::GetInstance(); + clientManager->setChronicleMetaDirectory(chronicleMetaDirectory.get()); + chronicleMetaDirectory->set_client_registry_manager(clientManager.get()); + + rpc = std::make_shared(); set_prefix("ChronoLog"); LOGD("%s constructor finishes, object created@%p in thread PID=%d", typeid(*this).name(), this, getpid()); - clientManager = ChronoLog::Singleton::GetInstance(); - chronicleMetaDirectory = ChronoLog::Singleton::GetInstance(); } ~RPCVisor() { } - void Visor_start() { + void Visor_start( ) { //chronolog::KeeperRegistry * keeper_registry) { rpc->start(); } /** * Admin APIs */ - int LocalConnect(const std::string &uri, std::string &client_id, int &flags, uint64_t &clock_offset) { + int LocalConnect(const std::string &uri, std::string const& client_id, int &flags, uint64_t &clock_offset) { LOGD("%s in ChronoLogAdminRPCProxy@%p called in PID=%d, with args: uri=%s", __FUNCTION__, this, getpid(), uri.c_str()); ClientInfo record; record.addr_ = "127.0.0.1"; if (std::strtol(client_id.c_str(), nullptr, 10) < 0) { - LOGE("client id is invalid"); + LOGE("client_id=%s is invalid", client_id.c_str()); return CL_ERR_INVALID_ARG; } return clientManager->add_client_record(client_id,record); } - int LocalDisconnect(const std::string &client_id, int &flags) { + int LocalDisconnect(std::string const& client_id, int &flags) { LOGD("%s is called in PID=%d, with args: client_id=%s, flags=%d", __FUNCTION__, getpid(), client_id.c_str(), flags); if (std::strtol(client_id.c_str(), nullptr, 10) < 0) { - LOGE("client id is invalid"); + LOGE("client_id=%s is invalid", client_id.c_str()); return CL_ERR_INVALID_ARG; } return clientManager->remove_client_record(client_id,flags); @@ -64,7 +71,7 @@ class RPCVisor { /** * Metadata APIs */ - int LocalCreateChronicle(std::string &name, + int LocalCreateChronicle(std::string const& name, const std::unordered_map &attrs, int &flags) { LOGD("%s is called in PID=%d, with args: name=%s, attrs=", __FUNCTION__, getpid(), name.c_str()); @@ -80,21 +87,21 @@ class RPCVisor { } } - int LocalDestroyChronicle(std::string &name, int &flags) { - LOGD("%s is called in PID=%d, with args: name=%s, flags=%d", __FUNCTION__, getpid(), name.c_str(), flags); + int LocalDestroyChronicle(std::string const& name) { + LOGD("%s is called in PID=%d, with args: name=%s", __FUNCTION__, getpid(), name.c_str()); if (!name.empty()) { - return chronicleMetaDirectory->destroy_chronicle(name, flags); + return chronicleMetaDirectory->destroy_chronicle(name); } else { LOGE("name is empty"); return CL_ERR_INVALID_ARG; } } - int LocalDestroyStory(std::string &chronicle_name, std::string &story_name, int &flags) { - LOGD("%s is called in PID=%d, with args: chronicle_name=%s, story_name=%s, flags=%d", - __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str(), flags); + int LocalDestroyStory(std::string const& chronicle_name, std::string const& story_name) { + LOGD("%s is called in PID=%d, with args: chronicle_name=%s, story_name=%s", + __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str()); if (!chronicle_name.empty() && !story_name.empty()) { - return chronicleMetaDirectory->destroy_story(chronicle_name,story_name,flags); + return chronicleMetaDirectory->destroy_story(chronicle_name,story_name); } else { if (chronicle_name.empty()) LOGE("chronicle name is empty"); @@ -104,44 +111,90 @@ class RPCVisor { } } - int LocalAcquireStory(std::string &client_id, - std::string& chronicle_name, - std::string& story_name, +/////////////////// + + int LocalAcquireStory(std::string const& client_id, + std::string const& chronicle_name, + std::string const& story_name, const std::unordered_map &attrs, int& flags) { LOGD("%s is called in PID=%d, with args: chronicle_name=%s, story_name=%s, flags=%d", __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str(), flags); - for (auto iter = attrs.begin(); iter != attrs.end(); ++iter) { + + if( !keeperRegistry->is_running()) + { return CL_ERR_NO_KEEPERS; } + + /*for (auto iter = attrs.begin(); iter != attrs.end(); ++iter) { LOGD("%s=%s", iter->first.c_str(), iter->second.c_str()); - } - if (!chronicle_name.empty() && !story_name.empty()) { + }*/ + + if (chronicle_name.empty() || story_name.empty()) + { //TODO : add this check on the client side, + //there's no need to waste the RPC on empty strings... + return CL_ERR_INVALID_ARG; + } + // TODO : create_stroy should be part of acquire_story int ret = chronicleMetaDirectory->create_story(chronicle_name, story_name, attrs); - if (ret != CL_SUCCESS) return ret; - return chronicleMetaDirectory->acquire_story(client_id, chronicle_name, story_name, flags); - } else { - if (chronicle_name.empty()) - LOGE("chronicle name is empty"); - if (story_name.empty()) - LOGE("story name is empty"); - return CL_ERR_INVALID_ARG; - } - } + if (ret != CL_SUCCESS) { + return ret; + } - int LocalReleaseStory(std::string &client_id, std::string& chronicle_name, std::string& story_name, int& flags) { - LOGD("%s is called in PID=%d, with args: chronicle_name=%s, story_name=%s, flags=%d", - __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str(), flags); - if (!chronicle_name.empty() && !story_name.empty()) { - return chronicleMetaDirectory->release_story(client_id, chronicle_name, story_name, flags); - } else { - if (chronicle_name.empty()) - LOGE("chronicle name is empty"); - if (story_name.empty()) - LOGE("story name is empty"); - return CL_ERR_INVALID_ARG; - } + // TODO : StoryId token and recordingKeepers vector need to be returned to the client + // when the client side RPC is updated to receive them + StoryId story_id(0); + std::vector recording_keepers; + bool notify_keepers = false; + ret = chronicleMetaDirectory->acquire_story(client_id, chronicle_name, story_name, flags, story_id,notify_keepers); + if(ret != CL_SUCCESS) + { return ret; } + + // if this is the first client to acquire this story we need to notify the recording Keepers + // so that they are ready to start recording this story + if(notify_keepers) + { + recording_keepers = keeperRegistry->getActiveKeepers(recording_keepers); + if( 0 != keeperRegistry->notifyKeepersOfStoryRecordingStart(recording_keepers, chronicle_name, story_name,story_id)) + { // RPC notification to the keepers might have failed, release the newly acquired story + chronicleMetaDirectory->release_story(client_id, chronicle_name,story_name,story_id, notify_keepers); + //TODO: chronicleMetaDirectory->release_story(client_id, story_id, notify_keepers); + //we do know that there's no need notify keepers of the story ending in this case as it hasn't started... + return CL_ERR_NO_KEEPERS; + } + + } + + LOGD("%s finished in PID=%d, with args: chronicle_name=%s, story_name=%s", + __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str()); + return CL_SUCCESS; } +//TODO: check if flags are ever needed to release the story... + + int LocalReleaseStory(std::string const& client_id, std::string const& chronicle_name, std::string const& story_name) { + LOGD("%s is called in PID=%d, with args: chronicle_name=%s, story_name=%s", + __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str()); + + //TODO: add this check on the client side so we dont' waste RPC call on empty strings... + if (chronicle_name.empty() || story_name.empty()) + { return CL_ERR_INVALID_ARG; } + + StoryId story_id(0); + bool notify_keepers = false; + auto return_code = chronicleMetaDirectory->release_story(client_id, chronicle_name, story_name, story_id, notify_keepers); + if(CL_SUCCESS != return_code) + { return return_code; } + + if( notify_keepers && keeperRegistry->is_running() ) + { + std::vector recording_keepers; + keeperRegistry->notifyKeepersOfStoryRecordingStop( keeperRegistry->getActiveKeepers(recording_keepers), story_id); + } + LOGD("%s finished in PID=%d, with args: chronicle_name=%s, story_name=%s", + __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str() ); + return CL_SUCCESS; + } +////////////// - int LocalGetChronicleAttr(std::string &name, const std::string &key, std::string &value) { + int LocalGetChronicleAttr(std::string const& name, const std::string &key, std::string &value) { LOGD("%s is called in PID=%d, with args: name=%s, key=%s", __FUNCTION__, getpid(), name.c_str(), key.c_str()); if (!name.empty() && !key.empty()) { chronicleMetaDirectory->get_chronicle_attr(name, key, value); @@ -155,7 +208,7 @@ class RPCVisor { } } - int LocalEditChronicleAttr(std::string &name, const std::string &key, const std::string &value) { + int LocalEditChronicleAttr(std::string const& name, const std::string &key, const std::string &value) { LOGD("%s is called in PID=%d, with args: name=%s, key=%s, value=%s", __FUNCTION__, getpid(), name.c_str(), key.c_str(), value.c_str()); if (!name.empty() && !key.empty() && !value.empty()) { @@ -187,7 +240,7 @@ class RPCVisor { case CHRONOLOG_THALLIUM_ROCE: { std::function connectFunc( [this](auto && PH1, @@ -203,7 +256,7 @@ class RPCVisor { } ); std::function disconnectFunc( [this](auto && PH1, auto && PH2, @@ -214,7 +267,7 @@ class RPCVisor { } ); std::function &, int &)> createChronicleFunc( [this](auto && PH1, @@ -228,35 +281,35 @@ class RPCVisor { } ); std::function destroyChronicleFunc( + std::string const& + )> destroyChronicleFunc( [this](auto && PH1, - auto && PH2, - auto && PH3) { + auto && PH2 + ) { ThalliumLocalDestroyChronicle(std::forward(PH1), - std::forward(PH2), - std::forward(PH3)); + std::forward(PH2) + ); } ); std::function destroyStoryFunc( + std::string const&, + std::string const& + )> destroyStoryFunc( [this](auto && PH1, auto && PH2, - auto && PH3, - auto && PH4) { + auto && PH3 + ) { ThalliumLocalDestroyStory(std::forward(PH1), std::forward(PH2), - std::forward(PH3), - std::forward(PH4)); + std::forward(PH3) + ); } ); std::function &, int &)> acquireStoryFunc( [this](auto && PH1, @@ -274,25 +327,25 @@ class RPCVisor { } ); std::function releaseStoryFunc( + std::string const&, + std::string const&, + std::string const& + )> releaseStoryFunc( [this](auto && PH1, auto && PH2, auto && PH3, - auto && PH4, - auto && PH5) { + auto && PH4 + ) { ThalliumLocalReleaseStory(std::forward(PH1), std::forward(PH2), std::forward(PH3), - std::forward(PH4), - std::forward(PH5)); + std::forward(PH4) + ); } ); std::function getChronicleAttrFunc( [this](auto && PH1, @@ -306,7 +359,7 @@ class RPCVisor { } ); std::function editChronicleAttrFunc( [this](auto && PH1, @@ -359,33 +412,33 @@ class RPCVisor { } CHRONOLOG_THALLIUM_DEFINE(LocalConnect, (uri, client_id, flags, clock_offset), - const std::string &uri, std::string &client_id, int &flags, uint64_t &clock_offset) + const std::string &uri, std::string const &client_id, int &flags, uint64_t &clock_offset) - CHRONOLOG_THALLIUM_DEFINE(LocalDisconnect, (client_id, flags), std::string &client_id, int &flags) + CHRONOLOG_THALLIUM_DEFINE(LocalDisconnect, (client_id, flags), std::string const& client_id, int &flags) CHRONOLOG_THALLIUM_DEFINE(LocalCreateChronicle, (name, attrs, flags), - std::string &name, const std::unordered_map &attrs, int &flags) + std::string const&name, const std::unordered_map &attrs, int &flags) - CHRONOLOG_THALLIUM_DEFINE(LocalDestroyChronicle, (name, flags), std::string &name, int &flags) + CHRONOLOG_THALLIUM_DEFINE(LocalDestroyChronicle, (name), std::string const&name) - CHRONOLOG_THALLIUM_DEFINE(LocalDestroyStory, (chronicle_name, story_name, flags), - std::string &chronicle_name, std::string &story_name, int &flags) + CHRONOLOG_THALLIUM_DEFINE(LocalDestroyStory, (chronicle_name, story_name), + std::string const& chronicle_name, std::string const&story_name) CHRONOLOG_THALLIUM_DEFINE(LocalAcquireStory, (client_id, chronicle_name, story_name, attrs, flags), - std::string &client_id, - std::string &chronicle_name, - std::string &story_name, + std::string const&client_id, + std::string const&chronicle_name, + std::string const&story_name, const std::unordered_map &attrs, int &flags) - CHRONOLOG_THALLIUM_DEFINE(LocalReleaseStory, (client_id, chronicle_name, story_name, flags), - std::string &client_id, std::string &chronicle_name, std::string &story_name, int &flags) + CHRONOLOG_THALLIUM_DEFINE(LocalReleaseStory, (client_id, chronicle_name, story_name), + std::string const&client_id, std::string const&chronicle_name, std::string const&story_name) CHRONOLOG_THALLIUM_DEFINE(LocalGetChronicleAttr, (name, key, value), - std::string &name, const std::string &key, std::string &value) + std::string const&name, const std::string &key, std::string &value) CHRONOLOG_THALLIUM_DEFINE(LocalEditChronicleAttr, (name, key, value), - std::string &name, const std::string &key, const std::string &value) + std::string const&name, const std::string &key, const std::string &value) CHRONOLOG_THALLIUM_DEFINE(LocalShowChronicles, (client_id), std::string &client_id) @@ -406,6 +459,7 @@ class RPCVisor { ChronoLogCharStruct func_prefix; std::shared_ptr rpc; + chronolog::KeeperRegistry * keeperRegistry; std::shared_ptr clientManager; std::shared_ptr chronicleMetaDirectory; }; diff --git a/ChronoAPI/ChronoLog/include/errcode.h b/ChronoAPI/ChronoLog/include/errcode.h index 78601749..422b51b6 100644 --- a/ChronoAPI/ChronoLog/include/errcode.h +++ b/ChronoAPI/ChronoLog/include/errcode.h @@ -5,18 +5,21 @@ #ifndef CHRONOLOG_ERRCODE_H #define CHRONOLOG_ERRCODE_H -#define CL_SUCCESS 0 /* Success */ -#define CL_ERR_UNKNOWN -1 /* Error does not belong to any categories below */ -#define CL_ERR_INVALID_ARG -2 /* Invalid arguments */ -#define CL_ERR_NOT_EXIST -3 /* Specified Chronicle or Story or property does not exist */ -#define CL_ERR_ACQUIRED -4 /* Specified Chronicle or Story is acquired, cannot be destroyed */ -#define CL_ERR_CHRONICLE_EXISTS -5 /* Specified Chronicle exists, cannot be created/renamed to */ -#define CL_ERR_STORY_EXISTS -6 /* Specified Story exists, cannot be created/renamed to */ -#define CL_ERR_Archive_EXISTS -7 /* Specified Archive exists, cannot be created/renamed to */ -#define CL_ERR_CHRONICLE_PROPERTY_FULL -8 /* Property list of Chronicle is full, cannot add new property */ -#define CL_ERR_STORY_PROPERTY_FULL -9 /* Property list of Story is full, cannot add new property */ -#define CL_ERR_CHRONICLE_METADATA_FULL -10 /* Metadata list of Chronicle is full, cannot add new property */ -#define CL_ERR_STORY_METADATA_FULL -11 /* Metadata list of Story is full, cannot add new property */ -#define CL_ERR_INVALID_CONF -12 /* Content of configuration file is invalid */ +#define CL_SUCCESS 0 /* Success */ +#define CL_ERR_UNKNOWN -1 /* Error does not belong to any categories below */ +#define CL_ERR_INVALID_ARG -2 /* Invalid arguments */ +#define CL_ERR_NOT_EXIST -3 /* Specified Chronicle or Story or property does not exist */ +#define CL_ERR_ACQUIRED -4 /* Specified Chronicle or Story is acquired, cannot be destroyed */ +#define CL_ERR_NOT_ACQUIRED -5 /* Specified Chronicle or Story is not acquired, cannot be released */ +#define CL_ERR_CHRONICLE_EXISTS -6 /* Specified Chronicle exists, cannot be created/renamed to */ +#define CL_ERR_STORY_EXISTS -7 /* Specified Story exists, cannot be created/renamed to */ +#define CL_ERR_Archive_EXISTS -8 /* Specified Archive exists, cannot be created/renamed to */ +#define CL_ERR_CHRONICLE_PROPERTY_FULL -9 /* Property list of Chronicle is full, cannot add new property */ +#define CL_ERR_STORY_PROPERTY_FULL -10 /* Property list of Story is full, cannot add new property */ +#define CL_ERR_CHRONICLE_METADATA_FULL -11 /* Metadata list of Chronicle is full, cannot add new property */ +#define CL_ERR_STORY_METADATA_FULL -12 /* Metadata list of Story is full, cannot add new property */ +#define CL_ERR_INVALID_CONF -13 /* Content of configuration file is invalid */ +#define CL_ERR_NO_KEEPERS -14 /* No ChronoKeepers are available */ +#define CL_ERR_NO_CONNECTION -15 /* No valid connnection to ChronoVisor */ #endif //CHRONOLOG_ERRCODE_H diff --git a/ChronoAPI/ChronoLog/include/global_var_visor.h b/ChronoAPI/ChronoLog/include/global_var_visor.h deleted file mode 100644 index 6fa48d82..00000000 --- a/ChronoAPI/ChronoLog/include/global_var_visor.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Created by kfeng on 10/24/22. -// - -#ifndef CHRONOLOG_GLOBAL_VAR_VISOR_H -#define CHRONOLOG_GLOBAL_VAR_VISOR_H - -#include "ClocksourceManager.h" -#include -#include -#include -#include -#include -#include - -/** - * ClientRegistry-related global variables - */ -//std::shared_ptr g_clientRegistryManager = nullptr; - //ChronoLog::Singleton::GetInstance(); -//std::mutex g_clientRegistryMutex_; - -/** - * ChronicleMetaDirectory-related global variables - */ -//std::shared_ptr> g_chronicleMap = - // ChronoLog::Singleton>::GetInstance(); -//std::shared_ptr g_chronicleMetaDirectory = nullptr; - //ChronoLog::Singleton::GetInstance(); // ChronicleMetaDirectory has to been inited - // after global ChronicleMap since it tried to - // store a reference to it using Singleton - // template class in its constructor -//std::mutex g_chronicleMetaDirectoryMutex_; -//std::mutex g_acquiredChronicleMapMutex_; -//std::mutex g_acquiredStoryMapMutex_; - -/** - * RPC-related global variables - */ -// Shared RPC instance -//std::shared_ptr g_RPC = nullptr; - //ChronoLog::Singleton::GetInstance()->GetRPC(CHRONOLOG_CONF->RPC_BASE_SERVER_PORT); -// RPC proxy instance -//std::shared_ptr g_RPCProxy = nullptr; - //ChronoLog::Singleton::GetInstance(); - -#endif //CHRONOLOG_GLOBAL_VAR_VISOR_H diff --git a/ChronoAPI/ChronoLog/include/macro.h b/ChronoAPI/ChronoLog/include/macro.h index 177c1877..06b818e6 100644 --- a/ChronoAPI/ChronoLog/include/macro.h +++ b/ChronoAPI/ChronoLog/include/macro.h @@ -9,6 +9,7 @@ #include "ConfigurationManager.h" #include "singleton.h" +// it's a bad idea to call GetInstance every time object reference is mentioned ... #define CHRONOLOG_CONF ChronoLog::Singleton::GetInstance() #define CHRONOLOG_RPC_CALL_WRAPPER_THALLIUM_SOCKETS() case CHRONOLOG_THALLIUM_SOCKETS: diff --git a/ChronoAPI/ChronoLog/include/rpc.h b/ChronoAPI/ChronoLog/include/rpc.h index 92e691df..90b4a63b 100644 --- a/ChronoAPI/ChronoLog/include/rpc.h +++ b/ChronoAPI/ChronoLog/include/rpc.h @@ -120,6 +120,9 @@ class ChronoLogRPC { template void bind(const ChronoLogCharStruct &str, F func); + thallium::engine & get_tl_client_engine() + { return *thalliumClient_; } + void run(size_t workers = 1) { if (CHRONOLOG_CONF->ROLE == CHRONOLOG_VISOR) { /* only servers run */ diff --git a/ChronoAPI/ChronoLog/src/ClocksourceManager.cpp b/ChronoAPI/ChronoLog/src/ClocksourceManager.cpp index 9b7048ef..d7941f3d 100644 --- a/ChronoAPI/ChronoLog/src/ClocksourceManager.cpp +++ b/ChronoAPI/ChronoLog/src/ClocksourceManager.cpp @@ -12,9 +12,11 @@ Clocksource *Clocksource::Create(ClocksourceType type) { return new ClocksourceCStyle(); case ClocksourceType::CPP_STYLE: return new ClocksourceCPPStyle(); - case ClocksourceType::TSC: +#ifdef TSC_ENABLED + case ClocksourceType::TSC: return new ClocksourceTSC(); +#endif default: return nullptr; } -} \ No newline at end of file +} diff --git a/ChronoKeeper/CMakeLists.txt b/ChronoKeeper/CMakeLists.txt index 6fabcb12..904f09af 100644 --- a/ChronoKeeper/CMakeLists.txt +++ b/ChronoKeeper/CMakeLists.txt @@ -4,12 +4,7 @@ project(ChronoKeeper) message("Building CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}") -add_executable(keeper_registry) -#KeeperRegistryInstance.cpp) -target_include_directories(keeper_registry PRIVATE include) -target_sources( keeper_registry PRIVATE KeeperRegistryInstance.cpp ) -target_link_libraries(keeper_registry thallium) -message("buidl target : keeper_registry") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -O0 -g") add_executable(chrono_keeper) target_include_directories(chrono_keeper PRIVATE include) @@ -17,4 +12,3 @@ target_sources(chrono_keeper PRIVATE ChronoKeeperInstance.cpp StoryPipeline.cpp target_link_libraries(chrono_keeper thallium) message("build target : chrono_keeper") -add_subdirectory(storyteller_client) diff --git a/ChronoKeeper/ChronoKeeperInstance.cpp b/ChronoKeeper/ChronoKeeperInstance.cpp index 567b8fe2..13d63f83 100644 --- a/ChronoKeeper/ChronoKeeperInstance.cpp +++ b/ChronoKeeper/ChronoKeeperInstance.cpp @@ -1,11 +1,8 @@ #include -//#include "Storyteller.h" - - -#include "KeeperIdCard.h" -#include "KeeperStatsMsg.h" +#include "chrono_common/KeeperIdCard.h" +#include "chrono_common/KeeperStatsMsg.h" #include "KeeperRecordingService.h" #include "KeeperRegClient.h" #include "IngestionQueue.h" @@ -13,13 +10,13 @@ #include "DataStoreAdminService.h" #define KEEPER_GROUP_ID 7 -#define KEEPER_REGISTRY_SERVICE_NA_STRING "ofi+sockets://127.0.0.1:1234" -#define KEEPER_REGISTRY_SERVICE_PROVIDER_ID 25 +#define KEEPER_REGISTRY_SERVICE_NA_STRING "ofi+sockets://127.0.0.1:6666" +#define KEEPER_REGISTRY_SERVICE_PROVIDER_ID 22 #define KEEPER_RECORDING_SERVICE_PROTOCOL "ofi+sockets" #define KEEPER_RECORDING_SERVICE_IP "127.0.0.1" -#define KEEPER_RECORDING_SERVICE_PORT "5555" -#define KEEPER_RECORDING_SERVICE_PROVIDER_ID 22 +#define KEEPER_RECORDING_SERVICE_PORT "8888" +#define KEEPER_RECORDING_SERVICE_PROVIDER_ID 25 #define KEEPER_COLLECTION_SERVICE_PROTOCOL "ofi+sockets" #define KEEPER_COLLECTION_SERVICE_IP "127.0.0.1" @@ -83,7 +80,7 @@ int main(int argc, char** argv) { // Instantiate ChronoKeeper MemoryDataStore // chronolog::IngestionQueue ingestionQueue; - chronolog::KeeperDataStore theDataStore; + chronolog::KeeperDataStore theDataStore(ingestionQueue); // instantiate DataStoreAdminService std::string KEEPER_COLLECTION_SERVICE_NA_STRING = std::string(KEEPER_COLLECTION_SERVICE_PROTOCOL) @@ -162,11 +159,11 @@ int main(int argc, char** argv) { int i{0}; - while( !theDataStore.is_shutting_down() & (i <20)) + while( !theDataStore.is_shutting_down()) { keeperRegistryClient->send_stats_msg(keeperStatsMsg); - i++; - sleep(60); + theDataStore.collectIngestedEvents(); + sleep(10); } keeperRegistryClient->send_unregister_msg(keeperIdCard); diff --git a/ChronoKeeper/DataStoreAdminService.h b/ChronoKeeper/DataStoreAdminService.h index 5eb6cb8e..2980969d 100644 --- a/ChronoKeeper/DataStoreAdminService.h +++ b/ChronoKeeper/DataStoreAdminService.h @@ -6,7 +6,7 @@ #include #include -#include "chronolog_types.h" +#include "chrono_common/chronolog_types.h" #include "KeeperDataStore.h" namespace tl = thallium; @@ -45,18 +45,18 @@ class DataStoreAdminService : public tl::provider } void StartStoryRecording(tl::request const& request, - std::string const& chronicle_name, std::string const& story_name, StoryId const& story_id) + std::string const& chronicle_name, std::string const& story_name, StoryId const& story_id, uint64_t start_time) { - std::cout << "DataStoreAdminService: StartStoryRecoding {"<< story_name<<":"< #include -#include "chronolog_types.h" +#include "chrono_common/chronolog_types.h" +#include "StoryIngestionHandle.h" // // IngestionQueue is a funnel into the MemoryDataStore @@ -18,7 +19,7 @@ namespace chronolog { typedef std::deque EventDeque; - +/* class StoryIngestionHandle { @@ -56,7 +57,7 @@ class StoryIngestionHandle EventDeque * activeDeque; }; - +*/ class IngestionQueue { public: @@ -68,21 +69,30 @@ class IngestionQueue void addStoryIngestionHandle( StoryId const& story_id, StoryIngestionHandle * ingestion_handle) { std::lock_guard lock(ingestionQueueMutex); - storyIngestionHandles.emplace(story_id,ingestion_handle); + storyIngestionHandles.emplace(std::pair(story_id,ingestion_handle)); + std::cout <<"IngestionQueue: added handle for story {"< lock(ingestionQueueMutex); orphanEventQueue.push_back(event); } @@ -114,6 +124,7 @@ void drainOrphanEvents() void shutDown() { + std::cout <<"IngestionQueue: shutdown : storyIngestionHandles {"<< &storyIngestionHandles<<"} .size="< (story_id, new chl::StoryPipeline(chronicle, story, story_id, start_time, time_chunk_duration))); + if( result.second) + { pipeline_iter = result.first; } + else + { return 0; } + } + + //check it the pipeline was put on the waitingForExit list by the previous aquisition + // and remove it from there + auto waiting_iter = pipelinesWaitingForExit.find(story_id); + if(waiting_iter != pipelinesWaitingForExit.end()) + { + pipelinesWaitingForExit.erase(waiting_iter); + } + + //engage StoryPipeline with the IngestionQueue + + StoryIngestionHandle * ingestionHandle = (*pipeline_iter).second->getActiveIngestionHandle(); + + theIngestionQueue.addStoryIngestionHandle( story_id, ingestionHandle); + +return 1; } //////////////////////// @@ -18,22 +47,86 @@ int chronolog::KeeperDataStore::stopStoryRecording(chronolog::StoryId const& sto { std::cout<<"KeeperDataStore: received stopStoryRecording {"<scheduleForExit(revisionTime + acceptanceWindow); + + pipelinesWaitingForExit.insert(std::pair( (*pipeline_iter).first, (*pipeline_iter).second) ); + } + +return 1; +} + +//////////////////////// + +void chronolog::KeeperDataStore::collectIngestedEvents() +{ + + for( auto pipeline_iter = theMapOfStoryPipelines.begin(); + pipeline_iter != theMapOfStoryPipelines.end(); ++pipeline_iter) + { +//INNA: this can be delegated to different threads handling individual storylines... + (*pipeline_iter).second->collectIngestedEvents(); + } + + +} +//////////////////////// + +int chronolog::KeeperDataStore::readStoryFromArchive(std::string const& archiveLocation + , std::string const & chronicle, std::string const& story, chronolog::StoryId const & story_id + , uint64_t start_Time, uint64_t end_time, uint32_t time_chunk_granularity) +{ + //NOT implemented yet + return 1; } //////////////////////// +int chronolog::KeeperDataStore::writeStoryToArchive(std::string const& archiveLocation + , std::string const & chronicle, std::string const& story, chronolog::StoryId const & story_id + , uint64_t start_time, uint64_t end_time, uint32_t archive_granularity) +{ + //NOT implemented yet + return 1; +} +////////////////////////////// + void chronolog::KeeperDataStore::shutdownDataCollection() { - std::cout<<"KeeperDataStore: shutdownDataCollection" << std::endl; + if( is_shutting_down() ) + { return; } + + std::cout<<"KeeperDataStore: shutdownDataCollection" << std::endl; // switch the state to shuttingDown + std::lock_guard storeLock(dataStoreMutex); + if( is_shutting_down() ) + { return; } + + state = SHUTTING_DOWN; + + // Unregister the ChronoKeeper + // + //stop Recording service for all the active stories + // ? should we notify the Visor ??? + // + // Finalize and persist all the story lines to disk + // ? we should probably disregard acceptance window in this case + // + // } /////////////////////// - // stop Recording Service - // finalize & persist all active stories // chronolog::KeeperDataStore::~KeeperDataStore() { - + shutdownDataCollection(); + } diff --git a/ChronoKeeper/KeeperDataStore.h b/ChronoKeeper/KeeperDataStore.h index 406f2cbc..b4914908 100644 --- a/ChronoKeeper/KeeperDataStore.h +++ b/ChronoKeeper/KeeperDataStore.h @@ -7,115 +7,68 @@ #include #include "IngestionQueue.h" +#include "StoryPipeline.h" namespace chronolog { -typedef uint64_t StoryId; -typedef uint64_t StorytellerId; -typedef std::string StoryName; -typedef std::string ChronicleName; - -// Pool of Sequencing worker threads -// Pool of Sequencing mutexes -// Pool of indestion mutexes -// -// Story Pipeline -// 1. ingestion Queue + hashed ingestion mutex -// 2. map of 5 secs maps + hashed sequencing index -// -// on acquire story allocate StoryPipeLine object for the story, assign ingestion & sequencing mutex from the mutex pools -// -// Hashmap of story pipelines -// -// -// -// - -// StorycChunk contains all the events for the single story -// for the duration [startTime, endTime[ -// startTime included, endTime excluded -// startTime/endTime are invariant -class StoryChunk +class KeeperDataStore { -public: - int mergeEvents(std::deque const&); - int mergeEvents(std::vector const&); - -private: -StoryId storyId; -uint64_t startTime; -uint64_t endTime; -uint64_t lastRevisionTime; -std::map> logEvents; +enum DataStoreState +{ + UNKNOWN = 0, + INITIALIZED =1, // initialized, no active stories + RUNNING =2, // active stories + SHUTTING_DOWN=3 // Shutting down services }; -class StoryPipeline -{ + public: - StoryPipeline( StoryId const&, std::mutex &, std::mutex &); - - ~StoryPipeline(); + KeeperDataStore( IngestionQueue & ingestion_queue) + : state(UNKNOWN) + , theIngestionQueue(ingestion_queue) + {} -int mergeEvents(std::vector const&); -int mergeEvents(StoryChunk const&); + KeeperDataStore( KeeperDataStore const&) = delete; + KeeperDataStore& operator= ( KeeperDataStore const&) = delete; -private: + ~KeeperDataStore(); -StoryId storyId; -ChronicleName chronicleName; -StoryName storyName; -uint64_t revisionTime; //timestamp of the most recent merge -uint64_t tailTime; // timestamp of the most recent recorded event -uint64_t acquisitionTime; //timestamp of the most recent aquisition - -// this mutex will be assigned to the story from the DataStore IngestionMutexPool -// based on the StoryId, it is used to protect the IngestionQueue from concurrent access -// by RecordingService threads -std::mutex & ingestionMutex; -// two ingestion queues so that they can take turns playing -// active/passive ingestion duty -// -std::deque eventQueue1; -std::deque eventQueue2; - -StoryIngestionHandle * ingestionQueueHandle; - -// this mutex will be assigned to the story from the DataStore SequencingMutexPool -// based on the StoryId; it is used to protect Story sequencing operations -// from concurrent access by the DataStore Sequencing threads -std::mutex & sequencingMutex; - -// map of storyChunks ordered by inclusive startTime -std::map storyTimeline; + bool is_initialized() const + { return (INITIALIZED == state); } -}; + bool is_running() const + { return (RUNNING == state); } -class KeeperDataStore -{ -public: - KeeperDataStore() - {} + bool is_shutting_down() const + { return (SHUTTING_DOWN == state); } - ~KeeperDataStore(); + int startStoryRecording(ChronicleName const&, StoryName const&, StoryId const& + , uint64_t start_time =0, uint32_t time_chunk_ranularity=30, uint32_t access_window = 60 ); //INNA: dummy values that eventually would come from Visor Metadata + int stopStoryRecording(StoryId const&); -bool is_shutting_down() const -{ - return (false); // INNA: implement state_management -} + void collectIngestedEvents(); -int startStoryRecording(ChronicleName const&, StoryName const&, StoryId const&, uint32_t timeGranularity=30 ); //INNA: 30 seconds? -int stopStoryRecording(StoryId const&); + int readStoryFromArchive(std::string const& archiveLocation + , std::string const & chronicle, std::string const& story, chronolog::StoryId const & story_id + , uint64_t start_time, uint64_t end_time, uint32_t time_chunk_granularity); -void shutdownDataCollection(); + int writeStoryToArchive(std::string const& archiveLocation + , std::string const & chronicle, std::string const& story, chronolog::StoryId const & story_id + , uint64_t start_time, uint64_t end_time, uint32_t archive_granularity); + + void shutdownDataCollection(); private: -std::unordered_map StoryPipelines; -std::mutex theStoryPipelinesMutex; + DataStoreState state; + IngestionQueue & theIngestionQueue; + std::mutex dataStoreMutex; + std::unordered_map theMapOfStoryPipelines; + std::unordered_map pipelinesWaitingForExit; //INNA: we might get away with simple list .. revisit later + -std::unordered_map ingestionMutexes; }; } diff --git a/ChronoKeeper/KeeperRecordingService.h b/ChronoKeeper/KeeperRecordingService.h index 143ca5e1..e3c00015 100644 --- a/ChronoKeeper/KeeperRecordingService.h +++ b/ChronoKeeper/KeeperRecordingService.h @@ -5,8 +5,8 @@ #include #include #include -#include "KeeperIdCard.h" -#include "chronolog_types.h" +#include "chrono_common/KeeperIdCard.h" +#include "chrono_common/chronolog_types.h" #include "IngestionQueue.h" namespace tl = thallium; @@ -35,20 +35,12 @@ class KeeperRecordingService : public tl::provider private: - void record_event(tl::request const& request, - StorytellerId teller_id, StoryId story_id, - uint64_t timeStamp, const std::string& record) + void record_event(tl::request const& request, LogEvent const & log_event) + // ClientId teller_id, StoryId story_id, + // ChronoTick const& chrono_tick, std::string const& record) { - std::cout << "recording {"<< teller_id<<":"<(record.size()) ); - } - - void record_event_no_response( StorytellerId teller_id, StoryId story_id, - uint64_t timeStamp, const std::string& record) - { - std::cout << "recording {"<< teller_id<<":"< : tl::provider(tl_engine, service_provider_id) , theIngestionQueue(ingestion_queue) { - define("record_event", &KeeperRecordingService::record_event); - define("record_event_no_response", &KeeperRecordingService::record_event_no_response,tl::ignore_return_value() ); + define("record_event", &KeeperRecordingService::record_event, tl::ignore_return_value()); //set up callback for the case when the engine is being finalized while this provider is still alive get_engine().push_finalize_callback(this, [p=this](){delete p;} ); } diff --git a/ChronoKeeper/KeeperRegClient.h b/ChronoKeeper/KeeperRegClient.h index 29a7c17c..a408ff6d 100644 --- a/ChronoKeeper/KeeperRegClient.h +++ b/ChronoKeeper/KeeperRegClient.h @@ -6,9 +6,9 @@ #include #include -#include "KeeperIdCard.h" -#include "KeeperRegistrationMsg.h" -#include "KeeperStatsMsg.h" +#include "chrono_common/KeeperIdCard.h" +#include "chrono_common/KeeperRegistrationMsg.h" +#include "chrono_common/KeeperStatsMsg.h" namespace tl = thallium; diff --git a/ChronoKeeper/StoryChunk.h b/ChronoKeeper/StoryChunk.h new file mode 100644 index 00000000..cde46743 --- /dev/null +++ b/ChronoKeeper/StoryChunk.h @@ -0,0 +1,132 @@ +#ifndef STORY_CHUNK_H +#define STORY_CHUNK_H + +#include +#include + +#include "chrono_common/chronolog_types.h" + +namespace chronolog +{ + + +typedef uint64_t chrono_time; +typedef uint32_t chrono_index; + +// StoryChunk contains all the events for the single story +// for the duration [startTime, endTime[ +// startTime included, endTime excluded +// startTime/endTime are invariant + +typedef std::tuple< chrono_time, chrono_index> ArrivalSequence; + +typedef std::tuple< chrono_time, ClientId, chrono_index> EventSequence; + + +class StoryChunk +{ +public: + + StoryChunk( StoryId const & story_id = 0, uint64_t start_time = 0, uint64_t end_time = 0) + : storyId(story_id) + , startTime(start_time) + , endTime(end_time) + , revisionTime(start_time) + { } + + ~StoryChunk() = default; + + uint64_t getStartTime() const + { return startTime; } + uint64_t getEndTime() const + { return endTime; } + + bool empty() const + { return ( logEvents.empty() ? true : false ); } + + std::map::const_iterator begin() const + { return logEvents.begin(); } + + std::map::const_iterator end() const + { return logEvents.end(); } + + std::map::const_iterator lower_bound( uint64_t chrono_time) const + { return logEvents.lower_bound( EventSequence{chrono_time,0,0});} + + int insertEvent(LogEvent const& event) + { + std::cout<<"StoryChunk:{"<= startTime) + && (event.time() < endTime)) + { + logEvents.insert( std::pair({event.time(),event.clientId, event.index()}, event)); + return 1; + } + else + { return 0; } + } + + + uint32_t mergeEvents( std::map & events + , std::map::iterator & merge_start ) + + { + uint32_t merged_event_count = 0; + std::map::iterator first_merged, last_merged; + + if ( (*merge_start).second.time() < startTime) + { merge_start = events.lower_bound(EventSequence{startTime,0,0}); } + + for( auto iter = merge_start; iter != events.end(); ++iter) + { + if( insertEvent( (*iter).second ) > 0 ) + { + if( merged_event_count ==0) + { first_merged = iter; } + last_merged = iter; + merged_event_count++; + } + else + { break; } //stop at the first record that can't be merged + } + + if ( merged_event_count >0) + { + //remove the merged records from the original map + events.erase( first_merged, last_merged); + } + + return merged_event_count; + } + + uint32_t mergeEvents(StoryChunk & other_chunk) + { return 0; } + + uint32_t mergeEvents(StoryChunk & other_chunk + , uint64_t start_time, uint64_t end_time) + { return 0; } + + + uint32_t extractEvents( std::map & target_map + , std::map::iterator first_pos + , std::map::iterator last_pos) + { return 0;} + uint32_t extractEvents( std::map & target_map + , uint64_t start_time, uint64_t end_time) + { return 0;} + uint32_t eraseEvents(uint64_t start_time, uint64_t end_time) + { return 0;} + +private: +StoryId storyId; +uint64_t startTime; +uint64_t endTime; +uint64_t revisionTime; + +std::map logEvents; + +}; + +} +#endif diff --git a/ChronoKeeper/StoryIngestionHandle.h b/ChronoKeeper/StoryIngestionHandle.h index 443c1165..7265e63c 100644 --- a/ChronoKeeper/StoryIngestionHandle.h +++ b/ChronoKeeper/StoryIngestionHandle.h @@ -11,21 +11,6 @@ namespace chronolog { -typedef uint64_t StoryId; -typedef uint64_t ClientId; -typedef std::mutex ChronoMutex; - -struct LogEvent -{ - LogEvent(StoryId const& story_id, ClientId const& client_id, uint64_t time, std::string const& record) - : storyId(story_id), clientId(client_id) - , timestamp(time),logRecord(record) - {} - StoryId storyId; - ClientId clientId; - uint64_t timestamp; - std::string logRecord; -}; typedef std::deque EventDeque; @@ -33,30 +18,39 @@ class StoryIngestionHandle { public: - StoryIngestionHandle( ChronoMutex & a_mutex, EventDeque & event_deque) + StoryIngestionHandle( std::mutex & a_mutex, EventDeque * active, EventDeque * passive) : ingestionMutex(a_mutex) - , activeDeque(&eventDeque) + , activeDeque(active) + , passiveDeque(passive) {} - ~StoryIngestionQueue() = default; + ~StoryIngestionHandle() = default; - void ingestLogEvent( LogEvent const& logEvent) + EventDeque & getActiveDeque() const + { return *activeDeque; } + + EventDeque & getPassiveDeque () const + { return *passiveDeque; } + + void ingestEvent( LogEvent const& logEvent) { // assume multiple service threads pushing events on ingestionQueue - std::lock_guard lock(); + std::lock_guard lock(ingestionMutex); activeDeque->push_back(logEvent); } - void swapActiveDeque( EventDeque * empty_deque, EventDeque * full_deque) + void swapActiveDeque( ) //EventDeque * empty_deque, EventDeque * full_deque) { - if( activeDeque->is_empty()) + if( !passiveDeque->empty() || activeDeque->empty()) { return ; } + //INNA: check if atomic compare_and_swap will work here - std::lock_guard lock_guard(ingestionMutex); - if( activeDeque->is_empty() ) + std::lock_guard lock_guard(ingestionMutex); + if( !passiveDeque->empty() || activeDeque->empty()) { return ; } - full_queue = activeDeque; - activeDeque = empty_deque; + EventDeque * full_deque = activeDeque; + activeDeque = passiveDeque; + passiveDeque = full_deque; } @@ -65,6 +59,7 @@ class StoryIngestionHandle std::mutex & ingestionMutex; EventDeque * activeDeque; + EventDeque * passiveDeque; }; } diff --git a/ChronoKeeper/StoryPipeline.cpp b/ChronoKeeper/StoryPipeline.cpp index 5a07aea8..2d528c94 100644 --- a/ChronoKeeper/StoryPipeline.cpp +++ b/ChronoKeeper/StoryPipeline.cpp @@ -1,44 +1,271 @@ +#include #include #include -#include "KeeperDataStore.h" + +#include "StoryChunk.h" +#include "StoryPipeline.h" +#include "StoryIngestionHandle.h" + +#define TRACE_CHUNKING + +namespace chl = chronolog; //////////////////////// -chronolog::StoryPipeline::StoryPipeline( chronolog::StoryId const& story_id, std::mutex & ingestion_mutex, std::mutex & sequencing_mutex) +chronolog::StoryPipeline::StoryPipeline( std::string const& chronicle_name, std::string const& story_name, chronolog::StoryId const& story_id + , uint64_t story_start_time, uint16_t chunk_granularity, uint16_t archive_granularity, uint16_t acceptance_window) : storyId(story_id) - , ingestionMutex(ingestion_mutex) - , sequencingMutex(sequencing_mutex) + , chronicleName(chronicle_name) + , storyName(story_name) + , timelineStart(story_start_time) + , timelineEnd(story_start_time) + , chunkGranularity(chunk_granularity) + , archiveGranularity(archive_granularity) + , acceptanceWindow(acceptance_window) + , activeIngestionHandle(nullptr) { + activeIngestionHandle = new chl::StoryIngestionHandle( ingestionMutex, &eventQueue1, &eventQueue2); + + //pre-initialize the pipeline map with the StoryChunks of chunkGranulary + // with the total time window of max(acceptance_window, chunk_granularity*2) + + auto story_start_point = std::chrono::time_point{} + + std::chrono::nanoseconds(timelineStart); + std::time_t time_t_story_start = std::chrono::high_resolution_clock::to_time_t(story_start_point); + std::cout <<"StoryPipeline: storyId {"<nanoseconds + archiveGranularity = archiveGranularity*60*60*1000000000; //hours =>nanoseconds + + //adjust the timelineStart to the closest prior boundary of chunkGanularity + timelineStart -= (timelineStart%chunkGranularity); + timelineEnd=timelineStart; + + for(uint64_t start = timelineStart; timelineEnd < (timelineStart + chunkGranularity*2 );) + { + appendStoryChunk(); + } + +#ifdef TRACE_CHUNKING + //std::chrono::time_point epoch_time_point{}; + auto chunk_start_point = std::chrono::time_point{} // epoch_time_point{}; + + std::chrono::nanoseconds(timelineStart); + std::time_t time_t_chunk_start = std::chrono::high_resolution_clock::to_time_t(chunk_start_point); + auto chunk_end_point = std::chrono::time_point{} + + std::chrono::nanoseconds(timelineEnd); + std::time_t time_t_chunk_end = std::chrono::high_resolution_clock::to_time_t(chunk_end_point); + std::cout <<"Created StoryPipeline: storyId { " << storyId<<"} " <<" with adjusted timeline {" << timelineStart<<" "<< std::ctime(&time_t_chunk_start) + <<"} {" << timelineEnd<<" " < const&) +std::map::iterator chronolog::StoryPipeline::prependStoryChunk() { - int status =0; + // prepend a storyChunk at the begining of storyTimeline and return the iterator to the new node +#ifdef TRACE_CHUNKING + std::chrono::time_point epoch_time_point{}; + auto chunk_start_point = epoch_time_point + std::chrono::nanoseconds(timelineStart); + std::time_t time_t_chunk_start = std::chrono::high_resolution_clock::to_time_t(chunk_start_point); + auto chunk_end_point = epoch_time_point + std::chrono::nanoseconds(timelineStart-chunkGranularity); + std::time_t time_t_chunk_end = std::chrono::high_resolution_clock::to_time_t(chunk_end_point); + std::cout <<"StoryPipeline: storyId { " << storyId<<"} prepend chunk {" << timelineStart<<" "<< std::ctime(&time_t_chunk_start) + <<"} {" << timelineStart-chunkGranularity <<" " < + ( timelineStart-chunkGranularity, chronolog::StoryChunk(storyId, timelineStart-chunkGranularity, timelineStart))); + if( !result.second) + { + return storyTimelineMap.end(); + } + else + { + timelineStart -= chunkGranularity; + return result.first; + } +} +///////////////////////////// + +std::map::iterator chronolog::StoryPipeline::appendStoryChunk() +{ + // append the next storyChunk at the end of storyTimeline and return the iterator to the new node +#ifdef TRACE_CHUNKING + std::chrono::time_point epoch_time_point{}; + auto chunk_start_point = epoch_time_point + std::chrono::nanoseconds(timelineEnd); + std::time_t time_t_chunk_start = std::chrono::high_resolution_clock::to_time_t(chunk_start_point); + auto chunk_end_point = epoch_time_point + std::chrono::nanoseconds(timelineEnd+chunkGranularity); + std::time_t time_t_chunk_end = std::chrono::high_resolution_clock::to_time_t(chunk_end_point); + std::cout <<"StoryPipeline: storyId { "<< storyId<<"} append chunk {" << timelineEnd <<" "<< std::ctime(&time_t_chunk_start) + <<"} {" << timelineEnd+chunkGranularity <<" " <( timelineEnd, chronolog::StoryChunk(storyId, timelineEnd, timelineEnd+chunkGranularity))); + if( !result.second) + { + return storyTimelineMap.end(); + } + else + { + timelineEnd += chunkGranularity; + return result.first; + } +} +////////////////////// + +void chronolog::StoryPipeline::collectIngestedEvents() +{ + activeIngestionHandle->swapActiveDeque(); + + if( !activeIngestionHandle->getPassiveDeque().empty()) + { mergeEvents(activeIngestionHandle->getPassiveDeque()); } -return status; } //////////////////// -int chronolog::StoryPipeline::mergeEvents(chronolog::StoryChunk const&) +void chronolog::StoryPipeline::mergeEvents(chronolog::EventDeque & event_deque) +{ + + if(event_deque.empty()) + { return;} + + std::lock_guard lock(sequencingMutex); + chl::LogEvent event; + // the last chunk is most likely the one that would get the events, so we'd start with the last + // chunk and do the lookup only if it's not the one + // NOTE: we should never have less than 2 chunks in the active storyTimelineMap !!! + std::map::iterator chunk_to_merge_iter = --storyTimelineMap.end(); + while( !event_deque.empty()) + { + event = event_deque.front(); + {std::cout << "StoryPipeline: {"<< storyId<<":"< event.time() + chunk_to_merge_iter = storyTimelineMap.upper_bound(event.time()); + //merge into the preceeding chunk + if( ! (*(--chunk_to_merge_iter)).second.insertEvent(event) ) + { std::cout << "ERROR : StoryPipeline: {"<< storyId<<"} merge discards event {"<< event.time()<<"}"<= timelineEnd) + { //extend timeline forward + while(event.time() >= timelineEnd) + { + chunk_to_merge_iter= appendStoryChunk(); + if ( chunk_to_merge_iter == storyTimelineMap.end()) + { break; } + } + if (chunk_to_merge_iter != storyTimelineMap.end()) + { (*chunk_to_merge_iter).second.insertEvent(event); } + else + { std::cout << "ERROR : StoryPipeline: {"<< storyId<<"} merge discards event {"<< event.time()<<"}"< lock(sequencingMutex); + + std::cout << "StoryPipeline: {"<< storyId<<"} merge StoryChunk {"<::iterator chunk_to_merge_iter; + + if( timelineStart <= other_chunk.getStartTime() ) + { + // find the chunk_to_merge into : we are lookingt for + // the chunk preceeding the one with the startTime > other_chunk.getStartTime() + chunk_to_merge_iter = --storyTimelineMap.upper_bound(other_chunk.getStartTime()); + } + else + { + // unlikely but possible that we get some delayed events and need to prepend some chunks + // extending the timeline back to the past + std::cout << "StoryPipeline: {"<< storyId<<"} merge prepending at {"< other_chunk.getStartTime()) + { + chunk_to_merge_iter = chl::StoryPipeline::prependStoryChunk(); + if(chunk_to_merge_iter==storyTimelineMap.end()) + { //INNA:: if prepend fails we have no choice but to discard the events we can't merge !! + std::cout << "ERROR : StoryPipeline: {"<< storyId<<"} merge discards events {"< +#include +#include +#include +#include + +#include "chrono_common/chronolog_types.h" +#include "StoryChunk.h" + +namespace chronolog +{ + + +class StoryIngestionHandle; + +class StoryPipeline +{ + + + +public: + StoryPipeline( std::string const& chronicle_name, std::string const& story_name + , StoryId const& story_id + , uint64_t start_time + , uint16_t chunk_granularity = 30 //seconds + , uint16_t archive_granularity = 3 // hours + , uint16_t acceptance_window = 1 // hour + + ); + + StoryPipeline(StoryPipeline const&) = delete; + StoryPipeline& operator=(StoryPipeline const&) = delete; + + ~StoryPipeline(); + + + StoryIngestionHandle * getActiveIngestionHandle(); + + void collectIngestedEvents(); + void mergeEvents(std::deque &); + void mergeEvents(StoryChunk &); + +private: + + StoryId storyId; + ChronicleName chronicleName; + StoryName storyName; + uint64_t timelineStart; + uint64_t timelineEnd; + uint64_t chunkGranularity; + uint64_t archiveGranularity; + uint64_t acceptanceWindow; + uint64_t revisionTime; //time of the most recent merge + uint64_t exitTime; //time the story can be removed from memory + + // mutex used to protect the IngestionQueue from concurrent access + // by RecordingService threads + std::mutex ingestionMutex; + // two ingestion queues so that they can take turns playing + // active/passive ingestion duty + // + std::deque eventQueue1; + std::deque eventQueue2; + + StoryIngestionHandle * activeIngestionHandle; + + // mutex used to protect Story sequencing operations + // from concurrent access by the DataStore Sequencing threads + std::mutex sequencingMutex; + + // map of storyChunks ordered by StoryChunck.startTime + std::map storyTimelineMap; + + std::map::iterator prependStoryChunk(); + std::map::iterator appendStoryChunk(); + +}; + +} +#endif diff --git a/ChronoKeeper/Storyteller.cpp b/ChronoKeeper/Storyteller.cpp deleted file mode 100644 index 3ac2bb1e..00000000 --- a/ChronoKeeper/Storyteller.cpp +++ /dev/null @@ -1,8 +0,0 @@ - - -#include - -#include -#include -#include - diff --git a/ChronoKeeper/Storyteller.h b/ChronoKeeper/Storyteller.h deleted file mode 100644 index d51a40c2..00000000 --- a/ChronoKeeper/Storyteller.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef STRORYTELLER_CLIENT_H -#define STROYTELLER_CLIENT_H - - -namespace chronolog - - - -template -class Storyteller -{ -public: - Storyteller( ClientId const&); - ~Storyteller(); - - StoryAccessToken const & getStoryAccessToken ( StoryId const&) const; - ChronoTime const& getStorytellerTime (ClientId const&) const; - void updateStorytellerTime ( ChronoTime cosnt&); - StoryMetadata const& beginStoryRecording( StoryId const&, StoryAccessToken cosnt&); - StoryMetadata const& endStoryRecording( StoryId const&); - -private: - ClientId clientId; - ChronoTime clientTime; - RPCChannel rpcChannel; - std::map < StoryId, std::pair > activeStories; - -}; - -} //namespace chronolog - - - - - -#endif STORYTELLER_CLIENT_H diff --git a/ChronoKeeper/KeeperIdCard.h b/ChronoKeeper/chrono_common/KeeperIdCard.h similarity index 96% rename from ChronoKeeper/KeeperIdCard.h rename to ChronoKeeper/chrono_common/KeeperIdCard.h index fad3e997..282b29f5 100644 --- a/ChronoKeeper/KeeperIdCard.h +++ b/ChronoKeeper/chrono_common/KeeperIdCard.h @@ -78,7 +78,7 @@ std::string & getIPasDottedString ( std::string & a_string ) const } //namespace chronolog -std::ostream & operator<< (std::ostream & out , chronolog::KeeperIdCard const & keeper_id_card) +inline std::ostream & operator<< (std::ostream & out , chronolog::KeeperIdCard const & keeper_id_card) { std::string a_string; out << "KeeperIdCard{"< + void serialize( SerArchiveT & serT) + { + serT (storyId, eventTime, clientId, eventIndex, logRecord); + } +}; + + +} +#endif diff --git a/ChronoKeeper/chronolog_types.h b/ChronoKeeper/chronolog_types.h deleted file mode 100644 index d45535c8..00000000 --- a/ChronoKeeper/chronolog_types.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CHRONOLOG_TYPE_DEFINITIONS_H -#define CHRONOLOG_TYPE_DEFINITIONS_H - - -namespace chronolog -{ - -typedef uint64_t StoryId; -typedef uint64_t StorytellerId; -typedef uint64_t ClientId; -typedef std::string StoryName; -typedef std::string ChronicleName; -typedef uint64_t ChronoTick; -//typedef std::pair ChronoTick; //INNA : use a pair throughout - - -struct LogEvent -{ - LogEvent(StoryId const& story_id, ClientId const& client_id, uint64_t time, std::string const& record) - : storyId(story_id), clientId(client_id) - , timestamp(time),logRecord(record) //INNA: keep both tick integers - {} - StoryId storyId; - ClientId clientId; - uint64_t timestamp; - std::string logRecord; -}; - - -} -#endif diff --git a/ChronoKeeper/storyteller_client/CMakeLists.txt b/ChronoKeeper/storyteller_client/CMakeLists.txt deleted file mode 100644 index 1e0bd67d..00000000 --- a/ChronoKeeper/storyteller_client/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_executable(storyteller_client storyteller_client.cpp) - -target_link_libraries(storyteller_client thallium) - diff --git a/ChronoKeeper/storyteller_client/storyteller_client.cpp b/ChronoKeeper/storyteller_client/storyteller_client.cpp deleted file mode 100644 index bb5635f6..00000000 --- a/ChronoKeeper/storyteller_client/storyteller_client.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include - -#include -#include - -namespace tl = thallium; - -int main(int argc, char** argv) { - if(argc != 3) { - std::cerr << "Usage: " << argv[0] << "
" << std::endl; - exit(0); - } - tl::engine myEngine("ofi+sockets", THALLIUM_CLIENT_MODE); - tl::remote_procedure record_event = myEngine.define("record_event"); - tl::endpoint server = myEngine.lookup(argv[1]); - uint16_t provider_id = atoi(argv[2]); - tl::provider_handle ph(server, provider_id); - - try // timed request throws timeout exception - { - std::string log_record("story_line_1"); - uint64_t log_time= std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - int ret = record_event.on(ph).timed(std::chrono::milliseconds(3), - static_cast(123), static_cast(321), log_time, log_record); - std::cout << "(record_event) response " << ret << std::endl; - } - catch(thallium::timeout const&) - { std::cout << "(record_event timed (3mls) :timeout" << std::endl; } - - - return 0; -} diff --git a/ChronoVisor/CMakeLists.txt b/ChronoVisor/CMakeLists.txt index d6bf9bed..055dc2af 100644 --- a/ChronoVisor/CMakeLists.txt +++ b/ChronoVisor/CMakeLists.txt @@ -1,42 +1,27 @@ -project(Chronovisor) +find_package(thallium REQUIRED) +find_package(Threads REQUIRED) -#add_library(ChronoVisor_lib STATIC -# include/ChronoVisorServer.h include/ClientRegistryInfo.h -# include/SerVector.h include/TimeRecord.h -# src/ChronoVisorServer.cpp src/ClientRegistryRecord.cpp -# src/TimeRecord.cpp -# ../ChronoAPI/ChronoLog/src/TimeManager.cpp ../ChronoAPI/ChronoLog/include/TimeManager.h -# ../ChronoAPI/ChronoLog/src/ClocksourceManager.cpp ../ChronoAPI/ChronoLog/include/ClocksourceManager.h -# src/ChronicleMetaDirectory.cpp include/ChronicleMetaDirectory.h -# include/Chronicle.h include/Story.h include/Archive.h include/Event.h -# ../ChronoAPI/ChronoLog/src/city.cpp ../ChronoAPI/ChronoLog/include/city.h ../ChronoAPI/ChronoLog/include/config.h include/ClientRegistryManager.h src/ClientRegistryManager.cpp) -#target_include_directories(ChronoVisor_lib PUBLIC include -# ../ChronoAPI/ChronoLog/include -# ${ROCKSDB_INCLUDE}) #-I/usr/include -#target_link_libraries(ChronoVisor_lib socketpp Serde ${ROCKSDB_LIB} pthread) #_L/usr/bin/mpi.so -#add_dependencies(ChronoVisor_lib socketpp Serde) +add_executable(chronovisor_server) -#add_executable(ChronoVisor main.cpp include/ClientRegistryManager.h src/ClientInfo.cpp include/ClientInfo.h) -#target_link_libraries(ChronoVisor ChronoVisor_lib socketpp) -#add_dependencies(ChronoVisor ChronoVisor_lib socketpp) +target_sources ( chronovisor_server PRIVATE + ./src/chronovisor_instance.cpp + ./src/ChronoVisorServer2.cpp + #../ChronoAPI/ChronoLog/src/ClocksourceManager.cpp + ./src/ClientRegistryManager.cpp + ./src/ClientRegistryRecord.cpp + ./src/ChronicleMetaDirectory.cpp + ./src/KeeperRegistry.cpp + ../ChronoAPI/ChronoLog/src/city.cpp) -# For new RPC-based ChronoVisor implementation -find_package(mercury REQUIRED) -find_package(thallium REQUIRED) -find_package(Threads REQUIRED) +target_include_directories(chronovisor_server PRIVATE + ../ChronoAPI/ChronoLog/include + ../chrono_common + ./include) + +target_link_libraries(chronovisor_server chronolog_client thallium) -add_library(ChronoVisor_lib2 STATIC - include/ChronoVisorServer2.h include/ClientInfo.h - src/ChronoVisorServer2.cpp src/ClientRegistryRecord.cpp - ../ChronoAPI/ChronoLog/src/ClocksourceManager.cpp ../ChronoAPI/ChronoLog/include/ClocksourceManager.h - src/ChronicleMetaDirectory.cpp include/ChronicleMetaDirectory.h - include/Chronicle.h include/Story.h include/Archive.h include/Event.h - ../ChronoAPI/ChronoLog/src/city.cpp ../ChronoAPI/ChronoLog/include/city.h ../ChronoAPI/ChronoLog/include/config.h include/ClientRegistryManager.h src/ClientRegistryManager.cpp) -target_include_directories(ChronoVisor_lib2 PUBLIC include - ../ChronoAPI/ChronoLog/include) -target_link_libraries(ChronoVisor_lib2 thallium) +# prep the stage... +configure_file(${CMAKE_SOURCE_DIR}/default_conf.json.in + ${CMAKE_CURRENT_BINARY_DIR}/default_conf.json COPYONLY) +add_test(NAME ChronoVisorServerTest COMMAND chronovisor_server) -if(BUILD_TESTING) - enable_testing() - add_subdirectory(test) -endif() diff --git a/ChronoVisor/include/Chronicle.h b/ChronoVisor/include/Chronicle.h index f638b698..fd51b876 100644 --- a/ChronoVisor/include/Chronicle.h +++ b/ChronoVisor/include/Chronicle.h @@ -144,7 +144,7 @@ class Chronicle { } } - int addStory(std::string &chronicle_name, uint64_t &cid, const std::string &story_name, + int addStory(std::string const&chronicle_name, uint64_t &cid, const std::string &story_name, const std::unordered_map &attrs) { // add cid to name before hash to allow same story name across chronicles std::string story_name_for_hash = chronicle_name + story_name; @@ -165,7 +165,7 @@ class Chronicle { else return CL_ERR_UNKNOWN; } - int removeStory(std::string &chronicle_name, const std::string& story_name, int flags) { + int removeStory(std::string const&chronicle_name, const std::string& story_name) { // add chronicle_name to story_name before hash to allow same story name across chronicles std::string story_name_for_hash = chronicle_name + story_name; /* Check if Story exists, fail if true */ diff --git a/ChronoVisor/include/ChronicleMetaDirectory.h b/ChronoVisor/include/ChronicleMetaDirectory.h index e9f8daee..cc9a475d 100644 --- a/ChronoVisor/include/ChronicleMetaDirectory.h +++ b/ChronoVisor/include/ChronicleMetaDirectory.h @@ -1,7 +1,3 @@ -// -// Created by kfeng on 3/9/22. -// - #ifndef CHRONOLOG_CHRONICLEMETADIRECTORY_H #define CHRONOLOG_CHRONICLEMETADIRECTORY_H @@ -9,47 +5,45 @@ #include #include #include -#include + + +class ClientRegistryManager; + +typedef uint64_t StoryId; class ChronicleMetaDirectory { public: ChronicleMetaDirectory(); ~ChronicleMetaDirectory(); -// std::shared_ptr> getChronicleMap() { return chronicleMap_; } + void set_client_registry_manager(ClientRegistryManager *pClientRegistryManager) { + clientRegistryManager_ = pClientRegistryManager; + } + std::unordered_map *getChronicleMap() { return chronicleMap_; } int create_chronicle(const std::string& name); int create_chronicle(const std::string& name, const std::unordered_map& attrs); - int destroy_chronicle(const std::string& name, int& flags); + int destroy_chronicle(const std::string& name); - int create_story(std::string &chronicle_name, const std::string& story_name, + int create_story(std::string const& chronicle_name, const std::string& story_name, const std::unordered_map& attrs); - int destroy_story(std::string &chronicle_name, const std::string& story_name, int& flags); + int destroy_story(std::string const& chronicle_name, const std::string& story_name); int acquire_story(const std::string& client_id, const std::string& chronicle_name, - const std::string& story_name, int& flags); + const std::string& story_name, int& flags, StoryId &, bool&); int release_story(const std::string& client_id, const std::string& chronicle_name, - const std::string& story_name, int& flags); - - uint64_t record_event(uint64_t sid, void *data); - uint64_t playback_event(uint64_t sid); + const std::string& story_name, StoryId &, bool&); - int get_chronicle_attr(std::string& name, const std::string& key, std::string& value); - int edit_chronicle_attr(std::string& name, const std::string& key, const std::string& value); + int get_chronicle_attr(std::string const& name, const std::string& key, std::string& value); + int edit_chronicle_attr(std::string const& name, const std::string& key, const std::string& value); std::vector show_chronicles(std::string& client_id); std::vector show_stories(std::string& client_id, const std::string& chronicle_name); private: -// std::shared_ptr> chronicleMap_; std::unordered_map *chronicleMap_; -// std::unordered_map *acquiredChronicleMap_; - std::unordered_map *acquiredStoryMap_; - std::unordered_multimap *acquiredChronicleClientMap_; - std::unordered_multimap *acquiredStoryClientMap_; std::mutex g_chronicleMetaDirectoryMutex_; - std::mutex g_acquiredChronicleMapMutex_; - std::mutex g_acquiredStoryMapMutex_; + ClientRegistryManager *clientRegistryManager_ = nullptr; // std::unordered_map *chronicleName2IdMap_; // std::unordered_map *chronicleId2NameMap_; }; diff --git a/ChronoVisor/include/ChronoVisorServer2.h b/ChronoVisor/include/ChronoVisorServer2.h index 2446fb0c..3487ccdc 100644 --- a/ChronoVisor/include/ChronoVisorServer2.h +++ b/ChronoVisor/include/ChronoVisorServer2.h @@ -1,22 +1,20 @@ -// -// Created by kfeng on 7/19/22. -// - #ifndef CHRONOLOG_CHRONOVISORSERVER2_H #define CHRONOLOG_CHRONOVISORSERVER2_H -#include +//#include #include -#include -#include +//#include +//#include #include #include -#include -#include -#include -#include +//#include +//#include +//#include +//#include #include +class ClocksourceManager; + namespace ChronoVisor { namespace tl = thallium; @@ -26,7 +24,7 @@ namespace ChronoVisor { explicit ChronoVisorServer2(const ChronoLog::ConfigurationManager &conf_manager); - int start(); + int start( chronolog::KeeperRegistry *); private: void init(); diff --git a/ChronoVisor/include/ClientInfo.h b/ChronoVisor/include/ClientInfo.h index 0ec27fea..797111ee 100644 --- a/ChronoVisor/include/ClientInfo.h +++ b/ChronoVisor/include/ClientInfo.h @@ -5,14 +5,39 @@ #ifndef CHRONOLOG_CLIENTINFO_H #define CHRONOLOG_CLIENTINFO_H +#include + +class Story; class ClientInfo { public: ClientInfo() = default; + [[nodiscard]] std::string to_string() const { + std::string str = addr_ + ":" + std::to_string(port_) + ", acquiredStories: "; + std::stringstream ss; + auto it = acquiredStoryList_.begin(); + ss << it->first; + for (++it; it != acquiredStoryList_.end(); ++it) { + ss << ", " << it->first; + } + return str + ss.str(); + } + + template friend void serialize(A& ar, ClientInfo& r); + std::string addr_; - uint16_t port_{}; + uint16_t port_; + std::unordered_map acquiredStoryList_; }; +std::ostream &operator<<(std::ostream &out, const ClientInfo &r); + +template +void serialize(A& ar, ClientInfo& r) { + ar & r.addr_; + ar & r.port_; + ar & r.acquiredStoryList_; +} #endif //CHRONOLOG_CLIENTINFO_H diff --git a/ChronoVisor/include/ClientRegistryManager.h b/ChronoVisor/include/ClientRegistryManager.h index 48547e14..e87b2f02 100644 --- a/ChronoVisor/include/ClientRegistryManager.h +++ b/ChronoVisor/include/ClientRegistryManager.h @@ -9,17 +9,29 @@ #include #include #include +#include + +class ChronicleMetaDirectory; class ClientRegistryManager { public: ClientRegistryManager(); ~ClientRegistryManager(); + void setChronicleMetaDirectory(ChronicleMetaDirectory *pChronicleMetaDirectory) { + chronicleMetaDirectory_ = pChronicleMetaDirectory; + } + + ClientInfo& get_client_info(const std::string &client_id); + int add_story_acquisition(const std::string &client_id, uint64_t &sid, Story *pStory); + int remove_story_acquisition(const std::string &client_id, uint64_t &sid); + int add_client_record(const std::string &client_id, const ClientInfo &record); int remove_client_record(const std::string& client_id, int &flags); private: std::unordered_map *clientRegistry_; std::mutex g_clientRegistryMutex_; + ChronicleMetaDirectory *chronicleMetaDirectory_{}; }; #endif //CHRONOLOG_CLIENTREGISTRYMANAGER_H diff --git a/ChronoKeeper/DataStoreAdminClient.h b/ChronoVisor/include/DataStoreAdminClient.h similarity index 93% rename from ChronoKeeper/DataStoreAdminClient.h rename to ChronoVisor/include/DataStoreAdminClient.h index 46ded749..d8077d75 100644 --- a/ChronoKeeper/DataStoreAdminClient.h +++ b/ChronoVisor/include/DataStoreAdminClient.h @@ -42,10 +42,10 @@ class DataStoreAdminClient return shutting_down; } - int send_start_story_recording( ChronicleName const& chronicle_name, StoryName const& story_name,StoryId const& story_id ) + int send_start_story_recording( ChronicleName const& chronicle_name, StoryName const& story_name,StoryId const& story_id, uint64_t start_time ) { - std::cout<< "DataStoreAdminClient: start_story_recording:"<, KeeperProcessEntry> keeperProcessRegistry; - thallium::engine & registryEngine; + thallium::engine * registryEngine; KeeperRegistryService * keeperRegistryService; }; diff --git a/ChronoKeeper/KeeperRegistryService.h b/ChronoVisor/include/KeeperRegistryService.h similarity index 99% rename from ChronoKeeper/KeeperRegistryService.h rename to ChronoVisor/include/KeeperRegistryService.h index c90f1700..228c2438 100644 --- a/ChronoKeeper/KeeperRegistryService.h +++ b/ChronoVisor/include/KeeperRegistryService.h @@ -2,7 +2,7 @@ #define KEEPER_REGISTRY_SERVICE_H #include -#include +//#include #include #include diff --git a/ChronoVisor/include/Story.h b/ChronoVisor/include/Story.h index 5bfb6aed..4cea6fcd 100644 --- a/ChronoVisor/include/Story.h +++ b/ChronoVisor/include/Story.h @@ -8,8 +8,10 @@ #include #include #include -#include "city.h" +#include #include +#include +#include enum StoryIndexingGranularity { story_gran_ns = 0, @@ -41,6 +43,8 @@ typedef struct StoryStats_ { uint64_t count; } StoryStats; +class ClientInfo; + class Story { public: Story() { @@ -63,6 +67,37 @@ class Story { void setSid(uint64_t sid) { sid_ = sid; } void setCid(uint64_t cid) { cid_ = cid; } void setStats(const StoryStats &stats) { stats_ = stats; } + + std::unordered_map &getAcquirerMap() { + return acquirerClientMap_; + } + + void addAcquirerClient(const std::string &client_id, ClientInfo *clientInfo) { + std::lock_guard acquirerClientListLock(acquirerClientMapMutex_); + acquirerClientMap_.emplace(client_id, clientInfo); + LOGD("acquirer client_id=%s is added to Story name=%s", client_id.c_str(), name_.c_str()); + } + + int removeAcquirerClient(const std::string &client_id) { + std::lock_guard acquirerClientListLock(acquirerClientMapMutex_); + if (isAcquiredByClient(client_id)) { + acquirerClientMap_.erase(client_id); + LOGD("acquirer client_id=%s is removed from Story name=%s", client_id.c_str(), name_.c_str()); + return CL_SUCCESS; + } else { + LOGD("Story name=%s is not acquired by client_id=%s", client_id.c_str(), name_.c_str()); + return CL_ERR_UNKNOWN; + } + } + + bool isAcquiredByClient(const std::string &client_id) { + if (acquirerClientMap_.find(client_id) != acquirerClientMap_.end()) { + return true; + } else { + return false; + } + } + void setProperty(const std::unordered_map& attrs) { for (auto const& entry : attrs) { propertyList_.emplace(entry.first, entry.second); @@ -88,6 +123,8 @@ class Story { uint64_t cid_{}; StoryAttrs attrs_{}; StoryStats stats_{}; + std::unordered_map acquirerClientMap_; + std::mutex acquirerClientMapMutex_; std::unordered_map propertyList_; std::unordered_map eventMap_; }; diff --git a/ChronoVisor/main.cpp b/ChronoVisor/main.cpp deleted file mode 100644 index 42646fd3..00000000 --- a/ChronoVisor/main.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by jaime on 2/16/2022. -// - -#include -#include -using namespace std; - -int main(){ - - return 0; -} \ No newline at end of file diff --git a/ChronoVisor/src/ChronicleMetaDirectory.cpp b/ChronoVisor/src/ChronicleMetaDirectory.cpp index dddc6c5e..2e553d60 100644 --- a/ChronoVisor/src/ChronicleMetaDirectory.cpp +++ b/ChronoVisor/src/ChronicleMetaDirectory.cpp @@ -1,21 +1,14 @@ -// -// Created by kfeng on 3/9/22. -// - #include #include "city.h" #include #include #include #include - +#include ChronicleMetaDirectory::ChronicleMetaDirectory() { LOGD("%s constructor is called", typeid(*this).name()); chronicleMap_ = new std::unordered_map(); - acquiredStoryMap_ = new std::unordered_map(); - acquiredChronicleClientMap_ = new std::unordered_multimap (); - acquiredStoryClientMap_ = new std::unordered_multimap (); // chronicleName2IdMap_ = new std::unordered_map(); // chronicleId2NameMap_ = new std::unordered_map(); LOGD("%s constructor finishes, object created@%p in thread PID=%d", @@ -24,9 +17,6 @@ ChronicleMetaDirectory::ChronicleMetaDirectory() { ChronicleMetaDirectory::~ChronicleMetaDirectory() { delete chronicleMap_; - delete acquiredStoryMap_; - delete acquiredChronicleClientMap_; - delete acquiredStoryClientMap_; // delete chronicleName2IdMap_; // delete chronicleId2NameMap_; } @@ -38,7 +28,7 @@ ChronicleMetaDirectory::~ChronicleMetaDirectory() { * CL_ERR_CHRONICLE_EXISTS if a Chronicle with the same name already exists \n * CL_ERR_UNKNOWN otherwise */ -int ChronicleMetaDirectory::create_chronicle(const std::string& name) { +int ChronicleMetaDirectory::create_chronicle(const std::string &name) { std::unordered_map attrs; return create_chronicle(name, attrs); } @@ -51,8 +41,8 @@ int ChronicleMetaDirectory::create_chronicle(const std::string& name) { * CL_ERR_CHRONICLE_EXISTS if a Chronicle with the same name already exists \n * CL_ERR_UNKNOWN otherwise */ -int ChronicleMetaDirectory::create_chronicle(const std::string& name, - const std::unordered_map& attrs) { +int ChronicleMetaDirectory::create_chronicle(const std::string &name, + const std::unordered_map &attrs) { LOGD("creating Chronicle name=%s", name.c_str()); for (auto iter = attrs.begin(); iter != attrs.end(); ++iter) { LOGD("%s=%s", iter->first.c_str(), iter->second.c_str()); @@ -71,6 +61,7 @@ int ChronicleMetaDirectory::create_chronicle(const std::string& name, cid = CityHash64(name.c_str(), name.length()); auto chronicleMapRecord = chronicleMap_->find(cid); if (chronicleMapRecord != chronicleMap_->end()) { + LOGD("A Chronicle with the same name=%s already exists", name.c_str()); return CL_ERR_CHRONICLE_EXISTS; } auto *pChronicle = new Chronicle(); @@ -83,8 +74,10 @@ int ChronicleMetaDirectory::create_chronicle(const std::string& name, std::chrono::duration duration = (t2 - t1); LOGD("time in %s: %lf ns", __FUNCTION__, duration.count()); if (res.second) { + LOGD("Chronicle name=%s is created", name.c_str()); return CL_SUCCESS; } else { + LOGE("Fail to create Chronicle name=%s", name.c_str()); return CL_ERR_UNKNOWN; } } @@ -99,9 +92,9 @@ int ChronicleMetaDirectory::create_chronicle(const std::string& name, * CL_ERR_ACQUIRED if the Chronicle is acquired by others and cannot be destroyed \n * CL_ERR_UNKNOWN otherwise */ -int ChronicleMetaDirectory::destroy_chronicle(const std::string& name, - int& flags) { - LOGD("destroying Chronicle name=%s, flags=%d", name.c_str(), flags); +int ChronicleMetaDirectory::destroy_chronicle(const std::string &name) +{ + LOGD("destroying Chronicle name=%s", name.c_str()); std::chrono::steady_clock::time_point t1, t2; t1 = std::chrono::steady_clock::now(); std::lock_guard chronicleMapLock(g_chronicleMetaDirectoryMutex_); @@ -113,15 +106,29 @@ int ChronicleMetaDirectory::destroy_chronicle(const std::string& name, cid = CityHash64(name.c_str(), name.length()); auto chronicleMapRecord = chronicleMap_->find(cid); if (chronicleMapRecord != chronicleMap_->end()) { - /* Check if Chronicle is acquired, fail if true */ - std::lock_guard acquiredChronicleMapLock(g_acquiredChronicleMapMutex_); - if (acquiredStoryMap_->find(cid) != acquiredStoryMap_->end()) { - return CL_ERR_ACQUIRED; + /* Check if Chronicle is acquired by checking if each of its Story is acquired, fail if true */ + Chronicle *pChronicle = chronicleMapRecord->second; + auto storyMap = pChronicle->getStoryMap(); + int ret = CL_SUCCESS; + for (auto storyMapRecord: storyMap) { + Story *pStory = storyMapRecord.second; + if (!pStory->getAcquirerMap().empty()) { + ret = CL_ERR_ACQUIRED; + for (const auto &acquirerMapRecord: pStory->getAcquirerMap()) { + LOGD("StoryID=%lu in Chronicle name=%s is still acquired by client_id=%s", + pStory->getSid(), name.c_str(), acquirerMapRecord.first.c_str()); + } + } + } + if (ret != CL_SUCCESS) { + return ret; } - Chronicle *pChronicle = chronicleMap_->find(cid)->second; if (pChronicle->getAcquisitionCount() != 0) { + LOGE("Something is wrong, no Story is being acquired, but Chronicle name=%s's acquisitionCount is not 0", + name.c_str()); return CL_ERR_UNKNOWN; } + /* No Stories in Chronicle is acquired, ready to destroy */ delete pChronicle; auto nErased = chronicleMap_->erase(cid); // chronicleName2IdMap_->erase(name); @@ -130,12 +137,14 @@ int ChronicleMetaDirectory::destroy_chronicle(const std::string& name, std::chrono::duration duration = (t2 - t1); LOGD("time in %s: %lf ns", __FUNCTION__, duration.count()); if (nErased == 1) { + LOGD("Chronicle name=%s is destroyed", name.c_str()); return CL_SUCCESS; } else { + LOGE("Fail to destroy Chronicle name=%s", name.c_str()); return CL_ERR_UNKNOWN; } } else { - LOGE("Cannot find Chronicle name=%s", name.c_str()); + LOGD("Chronicle name=%s does not exist", name.c_str()); return CL_ERR_NOT_EXIST; } } @@ -150,9 +159,9 @@ int ChronicleMetaDirectory::destroy_chronicle(const std::string& name, * CL_ERR_STORY_EXISTS if a Story with the same name already exists \n * CL_ERR_UNKNOWN otherwise */ -int ChronicleMetaDirectory::create_story(std::string& chronicle_name, - const std::string& story_name, - const std::unordered_map& attrs) { +int ChronicleMetaDirectory::create_story(std::string const& chronicle_name, + const std::string &story_name, + const std::unordered_map &attrs) { LOGD("creating Story name=%s in Chronicle name=%s", story_name.c_str(), chronicle_name.c_str()); std::chrono::steady_clock::time_point t1, t2; t1 = std::chrono::steady_clock::now(); @@ -175,7 +184,7 @@ int ChronicleMetaDirectory::create_story(std::string& chronicle_name, /* Forward its return value */ return res; } else { - LOGE("Cannot find Chronicle name=%s", chronicle_name.c_str()); + LOGD("Chronicle name=%s does not exist", chronicle_name.c_str()); return CL_ERR_NOT_EXIST; } } @@ -190,9 +199,9 @@ int ChronicleMetaDirectory::create_story(std::string& chronicle_name, * CL_ERR_NOT_EXIST if the Chronicle does not exist \n * CL_ERR_UNKNOWN otherwise */ -int ChronicleMetaDirectory::destroy_story(std::string& chronicle_name, - const std::string& story_name, - int& flags) { +int ChronicleMetaDirectory::destroy_story(std::string const& chronicle_name, + const std::string &story_name + ) { LOGD("destroying Story name=%s in Chronicle name=%s", story_name.c_str(), chronicle_name.c_str()); std::lock_guard chronicleMapLock(g_chronicleMetaDirectoryMutex_); /* First check if Chronicle exists, fail if false */ @@ -207,39 +216,51 @@ int ChronicleMetaDirectory::destroy_story(std::string& chronicle_name, /* Then check if Story exists, fail if false */ uint64_t sid = pChronicle->getStoryId(story_name); if (sid == 0) { + LOGD("StoryID=%lu name=%s does not exist", sid, story_name.c_str()); return CL_ERR_NOT_EXIST; } /* Then check if Story is acquired, fail if true */ - std::lock_guard acquiredStoryMapLock(g_acquiredStoryMapMutex_); - if (acquiredStoryMap_->find(sid) != acquiredStoryMap_->end()) { + Story *pStory = pChronicle->getStoryMap().at(sid); + if (!pStory->getAcquirerMap().empty()) { + for (const auto &acquirerMapRecord: pStory->getAcquirerMap()) { + LOGD("StoryID=%lu in Chronicle name=%s is still acquired by client_id=%s", + pStory->getSid(), chronicle_name.c_str(), acquirerMapRecord.first.c_str()); + } return CL_ERR_ACQUIRED; } /* Ask the Chronicle to destroy the Story */ - CL_Status res = pChronicle->removeStory(chronicle_name, story_name, flags); + CL_Status res = pChronicle->removeStory(chronicle_name, story_name); if (res != CL_SUCCESS) { LOGE("Fail to remove Story name=%s in Chronicle name=%s", story_name.c_str(), chronicle_name.c_str()); } return res; } else { + LOGD("Chronicle name=%s does not exist", chronicle_name.c_str()); return CL_ERR_NOT_EXIST; } } /** * Acquire a Story + * @param client_id: ClientID to acquire the Story * @param chronicle_name: name of the Chronicle that the Story belongs to * @param story_name: name of the Story * @param flags: flags + * @param story_id to populate with the story_id assigned to the story + * @param notify_keepers , bool value that would be set to true if this is the first client to acquire the story * @return CL_SUCCESS if succeed to destroy the Story \n * CL_ERR_NOT_EXIST if the Chronicle does not exist \n * CL_ERR_UNKNOWN otherwise */ int ChronicleMetaDirectory::acquire_story(const std::string &client_id, - const std::string& chronicle_name, - const std::string& story_name, - int& flags) { + const std::string &chronicle_name, + const std::string &story_name, + int &flags + , StoryId & story_id, bool& notify_keepers) +{ LOGD("client_id=%s acquiring Story name=%s in Chronicle name=%s, flags=%d", client_id.c_str(), story_name.c_str(), chronicle_name.c_str(), flags); + std::lock_guard chronicleMapLock(g_chronicleMetaDirectoryMutex_); /* First check if Chronicle exists, fail if false */ uint64_t cid; @@ -249,65 +270,61 @@ int ChronicleMetaDirectory::acquire_story(const std::string &client_id, cid = CityHash64(chronicle_name.c_str(), chronicle_name.length()); int ret = CL_ERR_NOT_EXIST; auto chronicleMapRecord = chronicleMap_->find(cid); - if (chronicleMapRecord != chronicleMap_->end()) { + if (chronicleMapRecord == chronicleMap_->end()) { + LOGD("Chronicle name=%s does not exist", chronicle_name.c_str()); + return CL_ERR_NOT_EXIST; + } Chronicle *pChronicle = chronicleMapRecord->second; - /* Then check if Story exists, fail if false */ + /* Then check if Story already_acquired_by_this_client, fail if false */ uint64_t sid = pChronicle->getStoryId(story_name); if (sid == 0) { - return CL_ERR_NOT_EXIST; + LOGD("StoryID=%lu name=%s does not exist", sid, story_name.c_str()); + return CL_ERR_NOT_EXIST; } - /* Last check if this client has acquired this Story already, return success if true */ - auto range = acquiredStoryClientMap_->equal_range(sid); - bool exists = false; - if (range.first != range.second) { - for (auto t = range.first; t != range.second; ++t) { - if (t->second.compare(client_id) == 0) { - exists = true; - break; - } - } + + /* Last check if this client has acquired this Story already, do nothing and return success if true */ + auto acquirerMap = pChronicle->getStoryMap().at(sid)->getAcquirerMap(); + auto acquirerMapRecord = acquirerMap.find(client_id); + if (acquirerMapRecord != acquirerMap.end()) { + LOGD("Story name=%s has already been acquired by client_id=%s", story_name.c_str(), client_id.c_str()); + /* All checks passed, manipulate metadata */ + return CL_ERR_ACQUIRED; } - if (!exists) { - /* All checks passed, increment AcquisitionCount */ + + /* All checks passed, manipulate metadata */ Story *pStory = pChronicle->getStoryMap().find(sid)->second; + story_id = pStory->getSid(); + notify_keepers = (pStory->getAcquisitionCount() == 0? true :false); + + /* Increment AcquisitionCount */ pStory->incrementAcquisitionCount(); - std::lock_guard acquiredStoryMapLock(g_acquiredStoryMapMutex_); - std::pair p(sid, client_id); - acquiredStoryClientMap_->insert(p); + /* Add this client to acquirerClientList of the Story */ + pStory->addAcquirerClient(client_id, &clientRegistryManager_->get_client_info(client_id)); + /* Add this Story to acquiredStoryMap for this client */ + clientRegistryManager_->add_story_acquisition(client_id, sid, pStory); ret = CL_SUCCESS; - if (acquiredStoryMap_->find(sid) == acquiredStoryMap_->end()) { - auto res = acquiredStoryMap_->emplace(sid, pStory); - if (res.second) { - ret = CL_SUCCESS; - } else { - ret = CL_ERR_UNKNOWN; - } - } - } else { - ret = CL_ERR_UNKNOWN; - } - ret = CL_SUCCESS; - } else { - return CL_ERR_NOT_EXIST; - } return ret; } /** * Release a Story + * @param client_id: ClientID to release the Story * @param chronicle_name: name of the Chronicle that the Story belongs to * @param story_name: name of the Story * @param flags: flags + * @param story_id to populate with the story_id assigned to the story + * @param notify_keepers , bool value that would be set to true if this is the last client to release the story * @return CL_SUCCESS if succeed to destroy the Story \n * CL_ERR_NOT_EXIST if the Chronicle does not exist \n * CL_ERR_UNKNOWN otherwise */ +//TO_DO return acquisition_count after the story has been released int ChronicleMetaDirectory::release_story(const std::string &client_id, - const std::string& chronicle_name, - const std::string& story_name, - int& flags) { - LOGD("client_id=%s releasing Story name=%s in Chronicle name=%s, flags=%d", - client_id.c_str(), story_name.c_str(), chronicle_name.c_str(), flags); + const std::string &chronicle_name, + const std::string &story_name + , StoryId & story_id, bool & notify_keepers ) { + LOGD("client_id=%s releasing Story name=%s in Chronicle name=%s", + client_id.c_str(), story_name.c_str(), chronicle_name.c_str()); std::lock_guard chronicleMapLock(g_chronicleMetaDirectoryMutex_); /* First check if Chronicle exists, fail if false */ uint64_t cid; @@ -325,40 +342,32 @@ int ChronicleMetaDirectory::release_story(const std::string &client_id, return CL_ERR_NOT_EXIST; } Story *pStory = pChronicle->getStoryMap().find(sid)->second; - /* Decrement AcquisitionCount */ - auto range = acquiredStoryClientMap_->equal_range(sid); - if (range.first != range.second) { - for (auto t = range.first; t != range.second;) { - if (t->second.compare(client_id) == 0) { - t = acquiredStoryClientMap_->erase(t); - pStory->decrementAcquisitionCount(); - ret = CL_SUCCESS; - if (pStory->getAcquisitionCount() == 0) { - auto nErased = acquiredStoryMap_->erase(sid); - if (nErased == 1) ret = CL_SUCCESS; - else ret = CL_ERR_UNKNOWN; - } - break; - } else ++t; + /* Check if this client actually acquired this Story before, fail if false */ + auto acquirerMap = pChronicle->getStoryMap().at(sid)->getAcquirerMap(); + auto acquirerMapRecord = acquirerMap.find(client_id); + if (acquirerMapRecord != acquirerMap.end()) { + /* All checks passed and entry found, manipulate metadata */ + /* Decrement AcquisitionCount */ + pStory->decrementAcquisitionCount(); + story_id = pStory->getSid(); + notify_keepers = (pStory->getAcquisitionCount() == 0? true :false); + /* Remove this client from acquirerClientList of the Story */ + pStory->removeAcquirerClient(client_id); + /* Remove this Story from acquiredStoryMap for this client */ + ret = clientRegistryManager_->remove_story_acquisition(client_id, sid); + if (ret != CL_SUCCESS) { + return ret; } } else { - ret = CL_ERR_UNKNOWN; + LOGD("Story name=%s is not acquired by client_id=%s, cannot release", story_name.c_str(), + client_id.c_str()); + ret = CL_ERR_NOT_ACQUIRED; } } return ret; } -uint64_t ChronicleMetaDirectory::record_event(uint64_t sid, void *data) { - LOGD("recording Event to Story sid=%lu", sid); - return 0; -} - -uint64_t ChronicleMetaDirectory::playback_event(uint64_t sid) { - LOGD("playing back Event from Story sid=%lu", sid); - return 0; -} - -int ChronicleMetaDirectory::get_chronicle_attr(std::string& name, const std::string& key, std::string& value) { +int ChronicleMetaDirectory::get_chronicle_attr(std::string const& name, const std::string &key, std::string &value) { LOGD("getting attributes key=%s from Chronicle name=%s", key.c_str(), name.c_str()); std::lock_guard chronicleMapLock(g_chronicleMetaDirectoryMutex_); /* First check if Chronicle exists, fail if false */ @@ -377,19 +386,22 @@ int ChronicleMetaDirectory::get_chronicle_attr(std::string& name, const std::str value = propertyRecord->second; return CL_SUCCESS; } else { + LOGD("Property key=%s does not exist in Chronicle name=%s", key.c_str(), name.c_str()); return CL_ERR_NOT_EXIST; } } else { + LOGE("Something is wrong, stored Chronicle object is null"); return CL_ERR_UNKNOWN; } } else { + LOGD("Chronicle name=%s does not exist", name.c_str()); return CL_ERR_NOT_EXIST; } } -int ChronicleMetaDirectory::edit_chronicle_attr(std::string& name, - const std::string& key, - const std::string& value) { +int ChronicleMetaDirectory::edit_chronicle_attr(std::string const& name, + const std::string &key, + const std::string &value) { LOGD("editing attribute key=%s, value=%s from Chronicle name=%s", key.c_str(), value.c_str(), name.c_str()); std::lock_guard chronicleMapLock(g_chronicleMetaDirectoryMutex_); /* First check if Chronicle exists, fail if false */ @@ -409,15 +421,19 @@ int ChronicleMetaDirectory::edit_chronicle_attr(std::string& name, if (res.second) { return CL_SUCCESS; } else { + LOGE("Something is wrong, fail to insert property key=%s, value=%s", key.c_str(), value.c_str()); return CL_ERR_UNKNOWN; } } else { + LOGD("Property key=%s does not exist in Chronicle name=%s", key.c_str(), name.c_str()); return CL_ERR_NOT_EXIST; } } else { + LOGE("Something is wrong, stored Chronicle object is null"); return CL_ERR_UNKNOWN; } } else { + LOGD("Chronicle name=%s does not exist", name.c_str()); return CL_ERR_NOT_EXIST; } } @@ -431,7 +447,7 @@ std::vector ChronicleMetaDirectory::show_chronicles(std::string &cl LOGD("showing all Chronicles client %s", client_id.c_str()); std::vector chronicle_names; std::lock_guard lock(g_chronicleMetaDirectoryMutex_); - for (auto &[key, value] : *chronicleMap_) { + for (auto &[key, value]: *chronicleMap_) { chronicle_names.emplace_back(value->getName()); } return chronicle_names; @@ -459,7 +475,7 @@ ChronicleMetaDirectory::show_stories(std::string &client_id, const std::string & if (chronicleMapRecord != chronicleMap_->end()) { Chronicle *pChronicle = chronicleMap_->find(cid)->second; LOGD("Chronicle@%p", &(*pChronicle)); - for (auto &[key, value] : pChronicle->getStoryMap()) { + for (auto &[key, value]: pChronicle->getStoryMap()) { std::string story_name = value->getName(); // story_names.emplace_back(story_name.erase(story_name.find(chronicle_name), chronicle_name.length())); story_names.emplace_back(story_name); diff --git a/ChronoVisor/src/ChronoVisorServer2.cpp b/ChronoVisor/src/ChronoVisorServer2.cpp index 38450a36..4f20ee4a 100644 --- a/ChronoVisor/src/ChronoVisorServer2.cpp +++ b/ChronoVisor/src/ChronoVisorServer2.cpp @@ -1,10 +1,9 @@ -// -// Created by kfeng on 7/19/22. -// #include "ChronoVisorServer2.h" #include "macro.h" +#include "KeeperRegistry.h" + namespace ChronoVisor { ChronoVisorServer2::ChronoVisorServer2(const std::string &conf_file_path) { if (!conf_file_path.empty()) @@ -14,10 +13,13 @@ namespace ChronoVisor { ChronoVisorServer2::ChronoVisorServer2(const ChronoLog::ConfigurationManager &conf_manager) { CHRONOLOG_CONF->SetConfiguration(conf_manager); + CHRONOLOG_CONF->ROLE = CHRONOLOG_VISOR; init(); } - int ChronoVisorServer2::start() { + int ChronoVisorServer2::start( chronolog::KeeperRegistry * keeper_registry) { + rpcVisor_ = ChronoLog::Singleton::GetInstance( keeper_registry); + LOGI("ChronoVisor server starting, listen on %d ports starting from %d ...", numPorts_, basePorts_); // bind functions first (defining RPC routines on engines) @@ -30,34 +32,8 @@ namespace ChronoVisor { } void ChronoVisorServer2::init() { - pClocksourceManager_ = ClocksourceManager::getInstance(); - pClocksourceManager_->setClocksourceType(CHRONOLOG_CONF->CLOCKSOURCE_TYPE); - CHRONOLOG_CONF->ROLE = CHRONOLOG_VISOR; - switch (CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.RPC_IMPLEMENTATION) { - CHRONOLOG_RPC_CALL_WRAPPER_THALLIUM_SOCKETS() - [[fallthrough]]; - CHRONOLOG_RPC_CALL_WRAPPER_THALLIUM_TCP() { - protocol_ = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); - break; - } - CHRONOLOG_RPC_CALL_WRAPPER_THALLIUM_ROCE() { - protocol_ = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); - break; - } - } - baseIP_ = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - basePorts_ = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; - numPorts_ = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_PORTS; - numStreams_ = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_SERVICE_THREADS; - serverAddrVec_.reserve(CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_PORTS); - for (int i = 0; i < numPorts_; i++) { - std::string server_addr = protocol_ + "://" + - baseIP_ + ":" + - std::to_string(basePorts_ + i); - serverAddrVec_.emplace_back(std::move(server_addr)); - } - engineVec_.reserve(numPorts_); - midVec_.reserve(numPorts_); - rpcVisor_ = ChronoLog::Singleton::GetInstance(); + //pClocksourceManager_ = ClocksourceManager::getInstance(); + //pClocksourceManager_->setClocksourceType(CHRONOLOG_CONF->CLOCKSOURCE_TYPE); + //CHRONOLOG_CONF->ROLE = CHRONOLOG_VISOR; } } diff --git a/ChronoVisor/src/ClientInfo.cpp b/ChronoVisor/src/ClientInfo.cpp index 67671461..6441b09d 100644 --- a/ChronoVisor/src/ClientInfo.cpp +++ b/ChronoVisor/src/ClientInfo.cpp @@ -3,3 +3,13 @@ // #include "ClientInfo.h" + +std::ostream &operator<<(std::ostream &out, const ClientInfo &r) { + std::stringstream ss; + auto it = r.acquiredStoryList_.begin(); + ss << it->first; + for (++it; it != r.acquiredStoryList_.end(); ++it) { + ss << ", " << it->first; + } + return out << r.addr_ << ":" << r.port_ << ", acquiredStories: " << ss.str(); +} \ No newline at end of file diff --git a/ChronoVisor/src/ClientRegistryManager.cpp b/ChronoVisor/src/ClientRegistryManager.cpp index b12dbdb0..56802721 100644 --- a/ChronoVisor/src/ClientRegistryManager.cpp +++ b/ChronoVisor/src/ClientRegistryManager.cpp @@ -7,7 +7,7 @@ #include "ClientRegistryManager.h" #include "errcode.h" #include "log.h" -#include +#include ClientRegistryManager::ClientRegistryManager() { LOGD("%s constructor is called, object created@%p in thread PID=%d", @@ -22,6 +22,66 @@ ClientRegistryManager::~ClientRegistryManager() { delete clientRegistry_; } +ClientInfo& ClientRegistryManager::get_client_info(const std::string &client_id) { + std::lock_guard clientRegistryLock(g_clientRegistryMutex_); + auto clientRegistryRecord = clientRegistry_->find(client_id); + if (clientRegistryRecord != clientRegistry_->end()) { + return clientRegistryRecord->second; + } +} + +int ClientRegistryManager::add_story_acquisition(const std::string &client_id, uint64_t &sid, Story *pStory) { + std::lock_guard clientRegistryLock(g_clientRegistryMutex_); + auto clientRegistryRecord = clientRegistry_->find(client_id); + if (clientRegistryRecord != clientRegistry_->end()) { + auto clientInfo = clientRegistryRecord->second; + if (clientInfo.acquiredStoryList_.find(sid) != clientInfo.acquiredStoryList_.end()) { + LOGD("client_id=%s has already acquired StoryID=%lu", client_id.c_str(), sid); + return CL_ERR_ACQUIRED; + } else { + clientInfo.acquiredStoryList_.emplace(sid, pStory); + auto res = clientRegistry_->insert_or_assign(client_id, clientInfo); + if (res.second) { + LOGD("added a new entry for client_id=%s acquiring StoryID=%lu", client_id.c_str(), sid); + return CL_SUCCESS; + } else { + LOGD("updated an existing entry for client_id=%s acquiring StoryID=%lu", client_id.c_str(), sid); + return CL_ERR_UNKNOWN; + } + } + } else { + LOGD("client_id=%s does not exist", client_id.c_str()); + return CL_ERR_UNKNOWN; + } +} + +int ClientRegistryManager::remove_story_acquisition(const std::string &client_id, uint64_t &sid) { + std::lock_guard clientRegistryLock(g_clientRegistryMutex_); + auto clientRegistryRecord = clientRegistry_->find(client_id); + if (clientRegistryRecord != clientRegistry_->end()) { + if (clientRegistryRecord->second.acquiredStoryList_.find(sid) != + clientRegistryRecord->second.acquiredStoryList_.end()) { + auto nErased = clientRegistryRecord->second.acquiredStoryList_.erase(sid); + if (nErased == 1) { + LOGD("removed StoryID=%lu from acquiredStoryList for client_id=%s", sid, client_id.c_str()); + LOGD("acquiredStoryList of client_id=%s has %zu entries left", client_id.c_str(), + clientRegistryRecord->second.acquiredStoryList_.size()); + return CL_SUCCESS; + } else { + LOGD("failed to remove StoryID=%lu from acquiredStoryList for client_id=%s", sid, client_id.c_str()); + return CL_ERR_UNKNOWN; + } + } else { + LOGD("StoryID=%lu is not acquired by client_id=%s, cannot remove from acquiredStoryList for it", + sid, client_id.c_str()); + return CL_ERR_NOT_ACQUIRED; + } + } else { + LOGD("client_id=%s does not exist", client_id.c_str()); + return CL_ERR_UNKNOWN; + } +} + int ClientRegistryManager::add_client_record(const std::string &client_id, const ClientInfo &record) { LOGD("%s in ClientRegistryManager@%p", __FUNCTION__, this); LOGD("clientRegistry_@%p has %ld entries stored", clientRegistry_, clientRegistry_->size()); @@ -29,17 +89,33 @@ int ClientRegistryManager::add_client_record(const std::string &client_id, const if (clientRegistry_->insert_or_assign(client_id, record).second) { LOGD("a new entry has been added to clientRegistry_@%p", clientRegistry_); return CL_SUCCESS; - } else + } else { + LOGE("Fail to add entry to clientRegistry_"); return CL_ERR_UNKNOWN; + } } int ClientRegistryManager::remove_client_record(const std::string &client_id, int &flags) { LOGD("%s in ClientRegistryManager@%p", __FUNCTION__, this); LOGD("clientRegistry_@%p has %ld entries", clientRegistry_, clientRegistry_->size()); std::lock_guard lock(g_clientRegistryMutex_); + auto clientRegistryRecord = clientRegistry_->find(client_id); + if (clientRegistryRecord != clientRegistry_->end()) { + auto clientInfo = clientRegistryRecord->second; + if (!clientInfo.acquiredStoryList_.empty()) { + LOGD("ClientID=%s still has %zu stories acquired, entry cannot be removed", + client_id.c_str(), clientInfo.acquiredStoryList_.size()); + return CL_ERR_ACQUIRED; + } + } else { + LOGD("client_id=%s does not exist", client_id.c_str()); + return CL_ERR_UNKNOWN; + } if (clientRegistry_->erase(client_id)) { LOGD("an entry has been removed from clientRegistry_@%p", clientRegistry_); return CL_SUCCESS; - } else + } else { + LOGE("Fail to remove entry from clientRegistry_"); return CL_ERR_UNKNOWN; + } } diff --git a/ChronoKeeper/KeeperRegistryInstance.cpp b/ChronoVisor/src/KeeperRegistry.cpp similarity index 80% rename from ChronoKeeper/KeeperRegistryInstance.cpp rename to ChronoVisor/src/KeeperRegistry.cpp index 1a3d2f10..8af89f32 100644 --- a/ChronoKeeper/KeeperRegistryInstance.cpp +++ b/ChronoVisor/src/KeeperRegistry.cpp @@ -6,28 +6,53 @@ #include "KeeperRegistry.h" #include "KeeperRegistryService.h" #include "DataStoreAdminClient.h" -// this file allows testing of the KeeperRegistryService and KeeperRegistry classes -// as the standalone process without the rest of the ChronoVizor modules -// - -#define KEEPER_REGISTRY_SERVICE_NA_STRING "ofi+sockets://127.0.0.1:1234" -#define KEEPER_REGISTRY_SERVICE_PROVIDER_ID 25 - +#include "ConfigurationManager.h" ///////////////////////// -namespace thallium = tl; +namespace tl = thallium; +namespace chl = chronolog; namespace chronolog { -int KeeperRegistry::InitializeRegistryService(uint16_t service_provider_id) +int KeeperRegistry::InitializeRegistryService(ChronoLog::ConfigurationManager const& confManager ) { std::lock_guard lock(registryLock); - keeperRegistryService = - KeeperRegistryService::CreateKeeperRegistryService(registryEngine,service_provider_id, *this); + if(registryState == UNKNOWN) + { + //INNA: TODO: add exception handling ... + // initialise thalium engine for KeeperRegistryService + + std::string KEEPER_REGISTRY_SERVICE_NA_STRING= + confManager.RPC_CONF.VISOR_KEEPER_CONF.PROTO_CONF.string() + +"://" + confManager.RPC_CONF.VISOR_KEEPER_CONF.VISOR_END_CONF.VISOR_IP.string() + +":" + std::to_string(confManager.RPC_CONF.VISOR_KEEPER_CONF.VISOR_END_CONF.VISOR_BASE_PORT); + + uint16_t provider_id = 22;//REGISTRY_SERVICE_PROVIDER_ID; + + margo_instance_id margo_id=margo_init(KEEPER_REGISTRY_SERVICE_NA_STRING.c_str(), MARGO_SERVER_MODE, 1, 2); + + if(MARGO_INSTANCE_NULL == margo_id) + { + std::cout<<"KeeperRegistryService: Failed to initialize margo_instance"<self() + << " with provider id " << provider_id << std::endl; + + + + keeperRegistryService = + KeeperRegistryService::CreateKeeperRegistryService(*registryEngine, provider_id, *this); - registryState = INITIALIZED; + registryState = INITIALIZED; + } return 1; } @@ -74,6 +99,8 @@ return 1; KeeperRegistry::~KeeperRegistry() { ShutdownRegistryService(); + registryEngine->finalize(); + delete registryEngine; } ///////////////// @@ -96,7 +123,7 @@ int KeeperRegistry::registerKeeperProcess( KeeperRegistrationMsg const& keeper_r KeeperProcessEntry(keeper_id_card, admin_service_id) ) ); if( false == insert_return.second) - { + {//INNA: revisit this paragraph... std::cout<<"KeeperRegistry: registerKeeper {"< & KeeperRegistry::getActiveKeepers( std::vector const& vectorOfKeepers , ChronicleName const& chronicle, StoryName const& story, StoryId const& storyId) { - int ret_status = 1; + int ret_status = 0; if (!is_running()) { std::cout<<"Registry has no Keeper processes to start story recording" << std::endl; return -1; } + + std::chrono::time_point time_now = std::chrono::system_clock::now(); + + uint64_t story_start_time = time_now.time_since_epoch().count() ; std::lock_guard lock(registryLock); if (!is_running()) { return -1;} - int keepers_left_to_notify = vectorOfKeepers.size(); + size_t keepers_left_to_notify = vectorOfKeepers.size(); for ( KeeperIdCard keeper_id_card : vectorOfKeepers) { auto keeper_process_iter = keeperProcessRegistry.find(std::pair(keeper_id_card.getIPaddr(),keeper_id_card.getPort())); @@ -240,13 +271,13 @@ int KeeperRegistry::notifyKeepersOfStoryRecordingStart( std::vectorsend_start_story_recording(chronicle, story, storyId); + int rpc_return = keeper_process.keeperAdminClient->send_start_story_recording(chronicle, story, storyId, story_start_time); if (rpc_return <0) { std::cout<<"WARNING: Registry failed notification RPC to keeper {"< const& vectorOfKeepers, StoryId const& storyId) { - int ret_status = 1; + int ret_status = 0; if (!is_running()) { std::cout<<"Registry has no Keeper processes to notify of story release" << std::endl; @@ -279,7 +310,7 @@ int KeeperRegistry::notifyKeepersOfStoryRecordingStop(std::vector if(!is_running()) { return -1; } - int keepers_left_to_notify = vectorOfKeepers.size(); + size_t keepers_left_to_notify = vectorOfKeepers.size(); for (KeeperIdCard keeper_id_card : vectorOfKeepers) { auto keeper_process_iter = keeperProcessRegistry.find(std::pair(keeper_id_card.getIPaddr(),keeper_id_card.getPort())); @@ -324,62 +355,3 @@ int KeeperRegistry::notifyKeepersOfStoryRecordingStop(std::vector }//namespace chronolog -/////////////////////////////////////////////// -int main(int argc, char** argv) { - - chronolog::RegistryConfiguration registryConfig; - registryConfig.REGISTRY_SERVICE_PROTOCOL = std::string(argv[1]); - registryConfig.REGISTRY_SERVICE_IP=std::string(argv[2]); - registryConfig.REGISTRY_SERVICE_PORT= atoi(argv[3]); - registryConfig.REGISTRY_SERVICE_PROVIDER_ID =atoi(argv[4]); - registryConfig.SERVICE_THREAD_COUNT=2; - - uint16_t provider_id = KEEPER_REGISTRY_SERVICE_PROVIDER_ID; - - margo_instance_id margo_id=margo_init(KEEPER_REGISTRY_SERVICE_NA_STRING, MARGO_SERVER_MODE, 1, 2); - - if(MARGO_INSTANCE_NULL == margo_id) - { - std::cout<<"FAiled to initialise margo_instance"< vectorOfKeepers; - while( !keeperRegistry.is_shutting_down()) - { - - if (keeperRegistry.is_running()) - { vectorOfKeepers.clear(); - vectorOfKeepers = keeperRegistry.getActiveKeepers(vectorOfKeepers); - - story_id++; - keeperRegistry.notifyKeepersOfStoryRecordingStart( vectorOfKeepers, - chronicle +std::to_string(story_id), story +std::to_string(story_id), story_id); - if (story_id >5) - { break;} - - } - sleep(10); - } - - - keeperRegistry.ShutdownRegistryService(); - - keeper_reg_engine.finalize(); - - return 0; -} diff --git a/ChronoVisor/src/chronovisor_instance.cpp b/ChronoVisor/src/chronovisor_instance.cpp new file mode 100644 index 00000000..92c664cc --- /dev/null +++ b/ChronoVisor/src/chronovisor_instance.cpp @@ -0,0 +1,42 @@ + +#include "ChronoVisorServer2.h" + +#include "KeeperRegistry.h" + +/////////////////////////////////////////////// +int main(int argc, char** argv) +{ + + // IMPORTANT NOTE!!!! + // we need to instantiate Client Registry, + // MetadataDirectory, & KeeperRegistry + // without initializing any of the related RPC communication objects + // to ensure that the main thread is the only one running at this point. + // After they are instantiated and tied together + // we can start RPC engines initialization that would start + // a bunch of new threads.... + // + // If we can't ensure the instantiation of registries on the main thread + // we'd need to add static mutex protection to all the registry singleton objects + + ChronoLog::ConfigurationManager confManager("./default_conf.json"); + + chronolog::KeeperRegistry keeperRegistry; + + ChronoVisor::ChronoVisorServer2 visor(confManager); + + keeperRegistry.InitializeRegistryService( confManager);//provider_id=22); + + visor.start(&keeperRegistry); + + ///// + + while( !keeperRegistry.is_shutting_down()) + { + sleep(60); + } + + + keeperRegistry.ShutdownRegistryService(); + return 0; +} diff --git a/Client/CMakeLists.txt b/Client/CMakeLists.txt index 459e211e..f3d64399 100644 --- a/Client/CMakeLists.txt +++ b/Client/CMakeLists.txt @@ -2,24 +2,31 @@ project(ChronoLogClient) set(CMAKE_CXX_STANDARD 17) -#set(CMAKE_FIND_DEBUG_MODE TRUE) - -find_package(mercury REQUIRED) find_package(thallium REQUIRED) -#set(CMAKE_FIND_DEBUG_MODE FALSE) - -add_library(ChronoLogClient_lib - src/client.cpp - include/client.h - include/RPCClient.h +add_library(chronolog_client + include/chronolog_client.h + src/ChronologClientImpl.h + src/KeeperRecordingClient.h + src/StorytellerClient.h + src/StorytellerClient.cpp + src/ChronologClient.cpp + src/ChronologClientImpl.cpp + + # include/client.h + include/RPCClient.h ../ChronoAPI/ChronoLog/include/macro.h - ../ChronoAPI/ChronoLog/include/rpc.h - ../ChronoAPI/ChronoLog/include/RPCFactory.h - ../ChronoAPI/ChronoLog/include/singleton.h - ../ChronoAPI/ChronoLog/src/city.cpp - ../ChronoAPI/ChronoLog/include/city.h) -target_include_directories(ChronoLogClient_lib PUBLIC include + ../ChronoAPI/ChronoLog/include/rpc.h + ../ChronoAPI/ChronoLog/include/RPCFactory.h + ../ChronoAPI/ChronoLog/include/singleton.h + ../ChronoAPI/ChronoLog/src/city.cpp + ../ChronoAPI/ChronoLog/include/city.h) + +target_include_directories(chronolog_client PUBLIC include ../ChronoAPI/ChronoLog/include + ../chrono_common/ ../Client/include) -target_link_libraries(ChronoLogClient_lib thallium) + +target_link_libraries(chronolog_client thallium) + +add_subdirectory(storyteller_test) diff --git a/Client/include/ChronoKeeperClient.h b/Client/include/ChronoKeeperClient.h deleted file mode 100644 index cd689487..00000000 --- a/Client/include/ChronoKeeperClient.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CHRONOLOG_KEEPER_CLIENT_H -#define CHRONOLOG_KEEPER_CLIENT_H - -#include -#include - -#include - -namespace chronolog -{ - -template -class ChronoKeeperClient -{ -public: - ChronoKeeperClient( std::vector const&); - ~ChronoKeeperClient(); - - void AppendLogRecord( void* data, size_t data_size); - -private: - //ip*port pair for sending events to the specific keeper process - // is incoporated into the KeeprIdCard - std::map< KeeperProcessId, std::pair > keeperRPCChannels; -}; - - - -}//namespace cronolog - -#endif CHRONOLOG_KEEPER_CLIENT_H diff --git a/Client/include/RPCClient.h b/Client/include/RPCClient.h index 7ce31b91..912d1f40 100644 --- a/Client/include/RPCClient.h +++ b/Client/include/RPCClient.h @@ -29,19 +29,19 @@ class RPCClient { { } - int Connect(const std::string &uri, std::string &client_id, int &flags, uint64_t &clock_offset) { + int Connect(const std::string &uri, std::string const &client_id, int &flags, uint64_t &clock_offset) { LOGD("%s in ChronoLogAdminRPCProxy at addresss %p called in PID=%d, with args: uri=%s, client_id=%s", __FUNCTION__, this, getpid(), uri.c_str(), client_id.c_str()); return CHRONOLOG_RPC_CALL_WRAPPER("Connect", 0, int, uri, client_id, flags, clock_offset); } - int Disconnect(const std::string &client_id, int &flags) { + int Disconnect(std::string const& client_id, int &flags) { LOGD("%s is called in PID=%d, with args: client_id=%s, flags=%d", __FUNCTION__, getpid(), client_id.c_str(), flags); return CHRONOLOG_RPC_CALL_WRAPPER("Disconnect", 0, int, client_id, flags); } - int CreateChronicle(std::string &name, + int CreateChronicle(std::string const& name, const std::unordered_map &attrs, int &flags) { LOGD("%s is called in PID=%d, with args: name=%s, flags=%d, attrs=", @@ -52,18 +52,18 @@ class RPCClient { return CHRONOLOG_RPC_CALL_WRAPPER("CreateChronicle", 0, int, name, attrs, flags); } - int DestroyChronicle(std::string &name, const int &flags) { - LOGD("%s is called in PID=%d, with args: name=%s, flags=%d", __FUNCTION__, getpid(), name.c_str(), flags); - return CHRONOLOG_RPC_CALL_WRAPPER("DestroyChronicle", 0, int, name, flags); + int DestroyChronicle(std::string const& name) { + LOGD("%s is called in PID=%d, with args: name=%s", __FUNCTION__, getpid(), name.c_str()); + return CHRONOLOG_RPC_CALL_WRAPPER("DestroyChronicle", 0, int, name); } - int DestroyStory(std::string &chronicle_name, std::string &story_name, const int &flags) { - LOGD("%s is called in PID=%d, with args: chronicle_name=%s, story_name=%s, flags=%d", - __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str(), flags); - return CHRONOLOG_RPC_CALL_WRAPPER("DestroyStory", 0, int, chronicle_name, story_name, flags); + int DestroyStory(std::string const& chronicle_name, std::string const& story_name) { + LOGD("%s is called in PID=%d, with args: chronicle_name=%s, story_name=%s", + __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str()); + return CHRONOLOG_RPC_CALL_WRAPPER("DestroyStory", 0, int, chronicle_name, story_name); } - int AcquireStory(std::string &client_id, std::string &chronicle_name, std::string &story_name, + int AcquireStory(std::string &client_id, std::string const& chronicle_name, std::string const& story_name, const std::unordered_map &attrs, const int &flags) { LOGD("%s is called in PID=%d, with args: client_id=%s, chronicle_name=%s, story_name=%s, flags=%d", __FUNCTION__, getpid(), client_id.c_str(), chronicle_name.c_str(), story_name.c_str(), flags); @@ -73,34 +73,37 @@ class RPCClient { return CHRONOLOG_RPC_CALL_WRAPPER("AcquireStory", 0, int, client_id, chronicle_name, story_name, attrs, flags); } - int ReleaseStory(std::string &client_id, std::string &chronicle_name, std::string &story_name, const int &flags) { - LOGD("%s is called in PID=%d, with args: client_id=%s, chronicle_name=%s, story_name=%s, flags=%d", - __FUNCTION__, getpid(), client_id.c_str(), chronicle_name.c_str(), story_name.c_str(), flags); - return CHRONOLOG_RPC_CALL_WRAPPER("ReleaseStory", 0, int, client_id, chronicle_name, story_name, flags); + int ReleaseStory(std::string &client_id, std::string const& chronicle_name, std::string const& story_name) { + LOGD("%s is called in PID=%d, with args: client_id=%s, chronicle_name=%s, story_name=%s", + __FUNCTION__, getpid(), client_id.c_str(), chronicle_name.c_str(), story_name.c_str()); + return CHRONOLOG_RPC_CALL_WRAPPER("ReleaseStory", 0, int, client_id, chronicle_name, story_name); } - int GetChronicleAttr(std::string &name, const std::string &key, std::string &value) { + int GetChronicleAttr(std::string const& name, const std::string &key, std::string &value) { LOGD("%s is called in PID=%d, with args: name=%s, key=%s", __FUNCTION__, getpid(), name.c_str(), key.c_str()); return CHRONOLOG_RPC_CALL_WRAPPER("GetChronicleAttr", 0, int, name, key, value); } - int EditChronicleAttr(std::string &name, const std::string &key, const std::string &value) { + int EditChronicleAttr(std::string const& name, const std::string &key, const std::string &value) { LOGD("%s is called in PID=%d, with args: name=%s, key=%s, value=%s", __FUNCTION__, getpid(), name.c_str(), key.c_str(), value.c_str()); return CHRONOLOG_RPC_CALL_WRAPPER("EditChronicleAttr", 0, int, name, key, value); } - std::vector ShowChronicles(std::string &client_id) { + std::vector ShowChronicles(std::string const& client_id) { LOGD("%s is called in PID=%d, with args: client_id=%s", __FUNCTION__, getpid(), client_id.c_str()); return CHRONOLOG_RPC_CALL_WRAPPER("ShowChronicles", 0, std::vector, client_id); } - std::vector ShowStories(std::string &client_id, const std::string &chronicle_name) { + std::vector ShowStories(std::string const& client_id, const std::string &chronicle_name) { LOGD("%s is called in PID=%d, with args: client_id=%s, chronicle_name=%s", __FUNCTION__, getpid(), client_id.c_str(), chronicle_name.c_str()); return CHRONOLOG_RPC_CALL_WRAPPER("ShowStories", 0, std::vector, client_id, chronicle_name); } + tl::engine & get_tl_client_engine() + { return rpc->get_tl_client_engine(); } + private: void set_prefix(std::string prefix) { func_prefix = std::move(prefix); diff --git a/Client/include/chronolog_client.h b/Client/include/chronolog_client.h new file mode 100644 index 00000000..6b073f1f --- /dev/null +++ b/Client/include/chronolog_client.h @@ -0,0 +1,65 @@ +#ifndef CHRONOLOG_CLIENT_H +#define CHRONOLOG_CLIENT_H + +#include +#include +#include + +#include "ConfigurationManager.h" //TODO: not sure this is a good idea , but will keep it for now ... + +namespace chronolog +{ + +//Abstract StoryHandle will be returnrned to the cleitn in AcquireStory() API call +class StoryHandle +{ +public: + virtual ~StoryHandle(); + + virtual int log_event( std::string const&) = 0; + + // to be implemented with libfabric/thallium bulk transfer... + //virtual int log_event( size_t , void*) = 0; +}; + +class ChronologClientImpl; + +// top level Chronolog Client... +// implementation details are in the ChronologClientImpl class +class Client +{ +public: + Client( ChronoLog::ConfigurationManager const&); + + ~Client(); + + int Connect(const std::string &server_uri, + std::string const& client_account, + int &flags); + int Disconnect( ); //std::string const& client_account); + + int CreateChronicle( std::string const& chronicle_name, + std::unordered_map const& attrs, + int &flags); + int DestroyChronicle(std::string const& chronicle_name); + +//TODO: unordered_map? how many attributes do we expect ??? + std::pair AcquireStory(std::string const& chronicle_name, std::string const& story_name, + const std::unordered_map &attrs, int &flags); + + int ReleaseStory(std::string const& chronicle_name, std::string const& story_name); + int DestroyStory(std::string const& chronicle_name, std::string const& story_name); + + int GetChronicleAttr(std::string const& chronicle_name, const std::string &key, std::string &value); + int EditChronicleAttr(std::string const& chronicle_name, const std::string &key, const std::string &value); + + std::vector & ShowChronicles( std::vector &); + std::vector & ShowStories( std::string const& chronicle_name, std::vector & ); + +private: + ChronologClientImpl * chronologClientImpl; +}; + +} //namespace chronolog + +#endif diff --git a/Client/include/client.h b/Client/include/tmp.client.h similarity index 89% rename from Client/include/client.h rename to Client/include/tmp.client.h index d6908aee..fff3e1f4 100644 --- a/Client/include/client.h +++ b/Client/include/tmp.client.h @@ -8,9 +8,11 @@ #include "RPCClient.h" #include "errcode.h" #include "ConfigurationManager.h" -#include "ClocksourceManager.h" +//#include "ClocksourceManager.h" -ClocksourceManager *ClocksourceManager::clocksourceManager_ = nullptr; +//ClocksourceManager *ClocksourceManager::clocksourceManager_ = nullptr; + +class ClocksourceManager; class ChronoLogClient { public: @@ -33,8 +35,8 @@ class ChronoLogClient { } void init() { - pClocksourceManager_ = ClocksourceManager::getInstance(); - pClocksourceManager_->setClocksourceType(CHRONOLOG_CONF->CLOCKSOURCE_TYPE); + //pClocksourceManager_ = ClocksourceManager::getInstance(); + //pClocksourceManager_->setClocksourceType(CHRONOLOG_CONF->CLOCKSOURCE_TYPE); CHRONOLOG_CONF->ROLE = CHRONOLOG_CLIENT; rpcClient_ = ChronoLog::Singleton::GetInstance(); } diff --git a/Client/src/ChronologClient.cpp b/Client/src/ChronologClient.cpp new file mode 100644 index 00000000..57c98f87 --- /dev/null +++ b/Client/src/ChronologClient.cpp @@ -0,0 +1,77 @@ + +#include "ChronologClientImpl.h" + + +chronolog::Client::Client( ChronoLog::ConfigurationManager const& confManager) +{ + //TODO: the pointer must be protected with the static mutex ... + chronologClientImpl = chronolog::ChronologClientImpl::GetClientImplInstance( confManager); +} + +chronolog::Client::~Client() +{ + delete chronologClientImpl; +} + +//TODO: get the client_account & client ip from the process itself .... +int chronolog::Client::Connect(std::string const& server_uri, + std::string const& client_account, + int &flags) +{ + return chronologClientImpl->Connect(server_uri, client_account, flags); +} + +int chronolog::Client::Disconnect() +{ + return chronologClientImpl->Disconnect(); +} + +int chronolog::Client::CreateChronicle( std::string const& chronicle_name, + std::unordered_map const& attrs, + int &flags) +{ + return chronologClientImpl->CreateChronicle( chronicle_name, attrs, flags); +} + +int chronolog::Client::DestroyChronicle(std::string const& chronicle_name) +{ + return chronologClientImpl->DestroyChronicle(chronicle_name); +} + +std::pair chronolog::Client::AcquireStory(std::string const& chronicle_name, std::string const& story_name, + const std::unordered_map &attrs, int &flags) +{ + return chronologClientImpl->AcquireStory(chronicle_name, story_name, attrs,flags); +} + +int chronolog::Client::ReleaseStory(std::string const& chronicle_name, std::string const& story_name) +{ + return chronologClientImpl->ReleaseStory( chronicle_name, story_name); +} + +int chronolog::Client::DestroyStory(std::string const& chronicle_name, std::string const& story_name) +{ + return chronologClientImpl->DestroyStory(chronicle_name,story_name); +} + +int chronolog::Client::GetChronicleAttr(std::string const& chronicle_name, const std::string &key, std::string &value) +{ + return chronologClientImpl->GetChronicleAttr( chronicle_name, key, value); +} + +int chronolog::Client::EditChronicleAttr(std::string const& chronicle_name, const std::string &key, const std::string &value) +{ + return chronologClientImpl->EditChronicleAttr(chronicle_name, key, value); +} + +std::vector & chronolog::Client::ShowChronicles( std::vector & chronicles) +{ + return chronologClientImpl->ShowChronicles(chronicles); +} + +std::vector & chronolog::Client::ShowStories(std::string const& chronicle_name, std::vector & stories ) +{ + return chronologClientImpl->ShowStories( chronicle_name, stories); +} + + diff --git a/Client/src/ChronologClientImpl.cpp b/Client/src/ChronologClientImpl.cpp new file mode 100644 index 00000000..dfcbf7d6 --- /dev/null +++ b/Client/src/ChronologClientImpl.cpp @@ -0,0 +1,193 @@ + +#include +#include "ChronologClientImpl.h" +#include "StorytellerClient.h" +#include "city.h" + +std::mutex chronolog::ChronologClientImpl::chronologClientMutex; +chronolog::ChronologClientImpl * chronolog::ChronologClientImpl::chronologClientImplInstance{nullptr}; + + +chronolog::ChronologClientImpl * chronolog::ChronologClientImpl::GetClientImplInstance(ChronoLog::ConfigurationManager const& confManager) +{ + std::lock_guard lock_client(chronologClientMutex); + if( chronologClientImplInstance == nullptr) + { + chronologClientImplInstance = new ChronologClientImpl(confManager); + } + + return chronologClientImplInstance; +} + +chronolog::ChronologClientImpl::~ChronologClientImpl() +{ + //TODO: implement + delete storyteller; +// shared_ptr.. delete rpcClient_; +} + +int chronolog::ChronologClientImpl::Connect(const std::string &server_uri, + std::string const& client_account, + int &flags) +{ + std::lock_guard lock_client(chronologClientMutex); + // if already connected return success + // if disconencting return failure.... + if((clientState != UNKNOWN) && (clientState != SHUTTING_DOWN)) + { return CL_SUCCESS; } + +/* if (client_id.empty()) { + char ip[16]; + struct hostent *he = gethostbyname("localhost"); + auto **addr_list = (struct in_addr **) he->h_addr_list; + strcpy(ip, inet_ntoa(*addr_list[0])); + std::string addr_str = ip + std::string(",") + std::to_string(getpid()); + uint64_t client_id_hash = CityHash64(addr_str.c_str(), addr_str.size()); + client_id = std::to_string(client_id_hash); + } + */ + clientAccount = client_account; + //TODO: client_id must be assigned by the Visor server + uint64_t clock_offset = 0; //TODO: use this value with the clocksource... + + auto return_code = rpcClient_->Connect(server_uri, clientAccount, flags, clock_offset); + + if(return_code == CL_SUCCESS) + { + clientState = CONNECTED; + clientId = 7; //TODO: retain clientId provided by he Visor + } + return return_code; +} + +int chronolog::ChronologClientImpl::Disconnect( ) //const std::string &client_id, int &flags) +{ + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return CL_SUCCESS; } + + //TODO : release all the acquired stories before asking to disconnect... + + int flags=1; + auto return_code = rpcClient_->Disconnect(clientAccount , flags); + if(return_code == CL_SUCCESS) + { + clientState = SHUTTING_DOWN; + } + return return_code; + +} +//TODO: client account must be passed into the rpc call +int chronolog::ChronologClientImpl::CreateChronicle(std::string const& chronicle_name, + const std::unordered_map &attrs, + int &flags) +{ + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return CL_ERR_NO_CONNECTION; } + + return rpcClient_->CreateChronicle(chronicle_name, attrs, flags); +} + +//TODO: client account must be passed into the rpc call +int chronolog::ChronologClientImpl::DestroyChronicle(std::string const& chronicle_name) +{ + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return CL_ERR_NO_CONNECTION; } + + return rpcClient_->DestroyChronicle(chronicle_name); +} + +//TODO: client account must be passed into the rpc call +int chronolog::ChronologClientImpl::DestroyStory(std::string const& chronicle_name, std::string const& story_name) +{ + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return CL_ERR_NO_CONNECTION; } + + return rpcClient_->DestroyStory(chronicle_name, story_name); +} + +std::pair chronolog::ChronologClientImpl::AcquireStory(std::string const& chronicle_name, std::string const& story_name, + const std::unordered_map &attrs, int &flags) +{ + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return std::pair(CL_ERR_NO_CONNECTION,nullptr); } + + chronolog::StoryHandle * storyHandle = nullptr; + //TODO: this function should return StoryId & vector that will be used to create StoryWritingHandle + + int ret = rpcClient_->AcquireStory(clientAccount, chronicle_name, story_name, attrs, flags); + if(ret == CL_SUCCESS) + { + // storyHandle = storytellerClient->initializeStoryWritingHandle(...) + } + + return std::pair(ret,storyHandle); +} + +// TODO: remove flags ... +int chronolog::ChronologClientImpl::ReleaseStory(std::string const& chronicle_name, std::string const& story_name) + //, int &flags) +{ + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return CL_ERR_NO_CONNECTION; } + + auto ret = rpcClient_->ReleaseStory(clientAccount, chronicle_name, story_name); + if (ret == CL_SUCCESS) + { + //storytellerClient->removeAcquireStoryHandle(...) + } + return ret; +} + +//TODO: client account must be passed into the rpc call +int chronolog::ChronologClientImpl::GetChronicleAttr(std::string const& chronicle_name, const std::string &key, std::string &value) { + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return CL_ERR_NO_CONNECTION; } + + return rpcClient_->GetChronicleAttr(chronicle_name, key, value); +} + +//TODO: client account must be passed into the rpc call +int chronolog::ChronologClientImpl::EditChronicleAttr(std::string const& chronicle_name, const std::string &key, std::string const& value) { + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return CL_ERR_NO_CONNECTION; } + + return rpcClient_->EditChronicleAttr(chronicle_name, key, value); +} + +std::vector & chronolog::ChronologClientImpl::ShowChronicles( std::vector & chronicles ) +{ + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return chronicles; } + + chronicles = rpcClient_->ShowChronicles(clientAccount); + return chronicles; +} + +std::vector & chronolog::ChronologClientImpl::ShowStories( std::string const& chronicle_name, std::vector & stories) +{ + std::lock_guard lock_client(chronologClientMutex); + + if((clientState == UNKNOWN) || (clientState == SHUTTING_DOWN)) + { return stories; } + + stories = rpcClient_->ShowStories(clientAccount, chronicle_name); + return stories; +} diff --git a/Client/src/ChronologClientImpl.h b/Client/src/ChronologClientImpl.h new file mode 100644 index 00000000..8518a40f --- /dev/null +++ b/Client/src/ChronologClientImpl.h @@ -0,0 +1,121 @@ +#ifndef CHRONOLOG_CLIENT_IMPL_H +#define CHRONOLOG_CLIENT_IMPL_H + +#include "RPCClient.h" +#include "errcode.h" +#include "ConfigurationManager.h" +//#include "ClocksourceManager.h" + +#include "chronolog_types.h" +//#include "StorytellerClient.h" + + +//ClocksourceManager *ClocksourceManager::clocksourceManager_ = nullptr; +//class ClocksourceManager; +//class StorytellerClient; + +#include "chronolog_client.h" +#include "rpcVisorClient.h" +#include "StorytellerClient.h" + +namespace chronolog +{ + +enum ChronologClientState +{ + UNKNOWN = 0, + CONNECTED = 1, + READING = 2, + WRITING = 3, + SHUTTING_DOWN = 4 +}; + +class ChronologClientImpl +{ +public: + + // static mutex ensures that there'd be the single instance + // of ChronologClientImpl ever created regardless of the + // thread(s) GetClientImplInstance() is called from + static std::mutex chronologClientMutex; + static ChronologClientImpl * chronologClientImplInstance; + static ChronologClientImpl * GetClientImplInstance(ChronoLog::ConfigurationManager const &); + + // the classs is non-copyable + ChronologClientImpl( ChronologClientImpl const&) = delete; + ChronologClientImpl & operator=(ChronologClientImpl const&) = delete; + + ~ChronologClientImpl(); + + int Connect(const std::string &server_uri, + std::string const& client_id, + int &flags); + //uint64_t &clock_offset); + int Disconnect( ); //const std::string &client_account, int &flags); + + int CreateChronicle(std::string const& chronicle_name, + const std::unordered_map &attrs, + int &flags); + int DestroyChronicle(std::string const& chronicle_name); //, int &flags); + + std::pair AcquireStory(std::string const& chronicle_name, std::string const& story_name, + const std::unordered_map &attrs, int &flags); + int ReleaseStory(std::string const&chronicle_name, std::string const& story_name); //, int &flags); + int DestroyStory(std::string const& chronicle_name, std::string const& story_name); + + int GetChronicleAttr(std::string const& chronicle_name, const std::string &key, std::string &value); + int EditChronicleAttr(std::string const& chronicle_name, const std::string &key, const std::string &value); + + std::vector & ShowChronicles( std::vector &); //std::string &client_id); + std::vector & ShowStories( const std::string &chronicle_name, std::vector &); + +private: + + ChronologClientState clientState; + std::string clientAccount; + ClientId clientId; + ChronologTimer clockProxy; + std::shared_ptr rpcClient_; + RpcVisorClient * rpcVisorClient; + StorytellerClient * storyteller; + // ClocksourceManager *pClocksourceManager_; + + //TODO : client_account & client_ip will be acquired from the cleitn process itself .... + // for now they can be passed in.... + ChronologClientImpl(const ChronoLog::ConfigurationManager& conf_manager) + : clientState(UNKNOWN) + , clientAccount("") + , clientId(0) + , rpcVisorClient(nullptr) + , storyteller(nullptr) + { + CHRONOLOG_CONF->SetConfiguration(conf_manager); + init(); + } + + ChronologClientImpl(const ChronoLogRPCImplementation& protocol, const std::string& visor_ip, int visor_port) + : clientState(UNKNOWN) + , clientAccount("") + , clientId(0) + , rpcVisorClient(nullptr) + , storyteller(nullptr) + { + CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.RPC_IMPLEMENTATION = protocol; + CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP = visor_ip; + CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT = visor_port; + init(); + } + + void init() { + //pClocksourceManager_ = ClocksourceManager::getInstance(); + //pClocksourceManager_->setClocksourceType(CHRONOLOG_CONF->CLOCKSOURCE_TYPE); + CHRONOLOG_CONF->ROLE = CHRONOLOG_CLIENT; + rpcClient_ = ChronoLog::Singleton::GetInstance(); + storyteller = new StorytellerClient( clockProxy, rpcClient_->get_tl_client_engine(), 0 ); //clientId field will be accessable later... + } + + +}; +} //namespace chronolog + +#endif diff --git a/Client/src/KeeperRecordingClient.h b/Client/src/KeeperRecordingClient.h new file mode 100644 index 00000000..6de415f8 --- /dev/null +++ b/Client/src/KeeperRecordingClient.h @@ -0,0 +1,73 @@ + +#ifndef KEEPER_RECORDING_CLIENT_H +#define KEEPER_RECORDING_CLIENT_H + +#include +#include +#include + +#include "chronolog_types.h" +#include "KeeperIdCard.h" + +namespace tl = thallium; + + +namespace chronolog +{ + + +class KeeperRecordingClient +{ + +public: + static KeeperRecordingClient * CreateKeeperRecordingClient( tl::engine & tl_engine + , KeeperIdCard const& keeper_id_card + , std::string const & rpc_protocol) + { + try + { + return new KeeperRecordingClient( tl_engine, keeper_id_card, rpc_protocol); + } catch( tl::exception const&) + { + std::cout<<"KeeperRecordingClient: failed construction"< + +#include +#include +#include + +#include "../chrono_common/chronolog_types.h" +#include "StorytellerClient.h" +#include "KeeperRecordingClient.h" + +namespace tl = thallium; + +namespace chl = chronolog; +///////////////////// + +uint64_t chronolog::ChronologTimer::getTimestamp() +{ + return std::chrono::high_resolution_clock::now().time_since_epoch().count(); +} + +///////////////////// +chronolog::StoryHandle::~StoryHandle() +{ } +//////////////////// +template // = chronolog::RoundRobinKeeperChoice> +chronolog::StoryWritingHandle::~StoryWritingHandle() +{ delete keeperChoicePolicy; } + +//////////////////// +template< class KeeperChoicePolicy> +void chronolog::StoryWritingHandle::addRecordingClient(chronolog::KeeperRecordingClient* keeperClient) +{ + storyKeepers.push_back(keeperClient); +} +/////////////////// +template< class KeeperChoicePolicy> +void chronolog::StoryWritingHandle::removeRecordingClient(chronolog::KeeperIdCard const& keeper_id_card) +{ + // this should only be called when the ChronoKeeper process unexpectedly exits + // so it's ok to use rather inefficient vector iteration.... + for( auto iter = storyKeepers.begin(); iter != storyKeepers.end(); ++iter) + { + if( (*iter)->getKeeperId() == keeper_id_card) + { storyKeepers.erase(iter); break; } + } +} +////////////////// +template< class KeeperChoicePolicy> +int chronolog::StoryWritingHandle::log_event( std::string const& event_record) +{ + + chronolog::LogEvent log_event(storyId, + theClient.getTimestamp(), + theClient.getClientId(), + theClient.get_event_index(), + event_record); + + auto keeperRecordingClient = keeperChoicePolicy->chooseKeeper(storyKeepers, log_event.time()); + + if(nullptr == keeperRecordingClient) //very unlikely... + { return 0; } + + // INNA: make send event returm 0 in case of tl RPC failure .... + keeperRecordingClient->send_event_msg( log_event); + +return 1; +} +///////////////////// + +template< class KeeperChoicePolicy> +int chronolog::StoryWritingHandle::log_event( size_t , void*) +{ + return 0; // not implemented yet ; to be implemented with tl bulk transfer ... +} +////////////////////////////////////////// + + +chronolog::StorytellerClient::~StorytellerClient() +{ + std::cout<<"StorytellerClient::~StorytellerClient()"< lock(acquiredStoryMapMutex); + +/* for( auto story_record_iter : acquiredStoryHandles) + { + delete story_record_iter.second; + } + acquiredStoryHandles.clear(); + */ } + // stop & delete keeperRecordingClients + std::lock_guard lock(recordingClientMapMutex); + for ( auto keeper_client : recordingClientMap) + { + delete keeper_client.second; + } + recordingClientMap.clear(); +} + +int chronolog::StorytellerClient::get_event_index() +{ + // we only aqcuire mutex in the rare case when + // the atomic index has reached INT_MAX value + // otherwise proceed lock-free + if( (atomic_index == INT_MAX) ) + { + std::lock_guard lock(recordingClientMapMutex); + //recheck when mutex is acquired, only one thread changes the value + if(atomic_index == INT_MAX) + { atomic_index = 0; } + } +return ++atomic_index; +} +//////////////// + + +int chronolog::StorytellerClient::addKeeperRecordingClient( chronolog::KeeperIdCard const& keeper_id_card) +{ + std::lock_guard lock(recordingClientMapMutex); + + try + { + chronolog::KeeperRecordingClient * keeperRecordingClient = chronolog::KeeperRecordingClient::CreateKeeperRecordingClient + (client_engine, keeper_id_card, rpc_protocol_string); + + auto insert_return = recordingClientMap.insert( std::pair, chronolog::KeeperRecordingClient*> + ( std::pair(keeper_id_card.getIPaddr(),keeper_id_card.getPort()), keeperRecordingClient)); + if( false == insert_return.second) + { + return 0; + } + + std::cout<<"StorytellerClient: created keeperRecordingClient for {"< lock(recordingClientMapMutex); + + // stop & delete keeperRecordingClient before erasing keeper_process entry + auto keeper_client_iter = recordingClientMap.find(std::pair(keeper_id_card.getIPaddr(),keeper_id_card.getPort())); + if(keeper_client_iter != recordingClientMap.end()) + { + delete (*keeper_client_iter).second; + recordingClientMap.erase(keeper_client_iter); + } + + //INNA: TODO: if this function is triggered by the Vizor calls when the ChronoKeeper process unexpectedly unregistered/exited + // we need to iterate through the known WritingHandles and make sure this keeperClient is removed from all the active storyHandles + // serialize the log events by switching the state to PENDING and forcing the log event calls to wait by locking + //recording clientMutex during this time .... +return 1; +} +/////////////////////////// + +std::pair chronolog::StorytellerClient::initializeStoryWritingHandle( + ChronicleName const& chronicle, StoryName const& story + , StoryId const& story_id, std::vector const& vectorOfKeepers) + //INNA: TODO :KeeperChoicePolicy will have to be communicated here as well .... +{ + + + std::lock_guard lock(acquiredStoryMapMutex); + + auto story_record_iter = acquiredStoryHandles.find( std::pair(chronicle,story)); + if(story_record_iter != acquiredStoryHandles.end()) + { + return std::pair(1, (*story_record_iter).second); + } + + // create new StoryWritingHandle & initialize it's keeperClients vector + chronolog::StoryWritingHandle * storyWritingHandle = + new StoryWritingHandle( *this, chronicle,story, story_id); + + for ( KeeperIdCard keeper_id_card : vectorOfKeepers) + { + auto keeper_client_iter = recordingClientMap.find(std::pair(keeper_id_card.getIPaddr(),keeper_id_card.getPort())); + if(keeper_client_iter == recordingClientMap.end()) + { + // unlikely but we better check + if (0 == addKeeperRecordingClient(keeper_id_card) ) + continue; + } + keeper_client_iter = recordingClientMap.find(std::pair(keeper_id_card.getIPaddr(),keeper_id_card.getPort())); + storyWritingHandle->addRecordingClient((*keeper_client_iter).second); + } + + + auto insert_return = acquiredStoryHandles.insert( std::pair< std::pair,chronolog::StoryHandle*>( + std::pair(chronicle,story), storyWritingHandle)); + if( false == insert_return.second) + { + delete storyWritingHandle; + return std::pair(0,nullptr); + } + +return std::pair(1,storyWritingHandle); +/* + // now check the state of the handle: + // it's possible the other thread is still pending the acquisition response from the Vizor, + // or the handle's keeper vector is being updated , etc .... + if (state == PENDING_RESPONSE || state== UPDATING_KEEPERS) ) + { + // get the handle lock and wait for the thread that sent the request to Vizor to get the response + std::lock_guard story_lock(storyHandleMutex); + + } + */ + +} + +////////////////////// +void chronolog::StorytellerClient::removeAcquiredStoryHandle(ChronicleName const& chronicle, StoryName const& story) +{ + std::lock_guard lock(acquiredStoryMapMutex); + + auto story_record_iter = acquiredStoryHandles.find(std::pair (chronicle,story)); + if(story_record_iter != acquiredStoryHandles.end()) + { + delete (*story_record_iter).second; + acquiredStoryHandles.erase(story_record_iter); + } +} + +///////////////// + + diff --git a/Client/src/StorytellerClient.h b/Client/src/StorytellerClient.h new file mode 100644 index 00000000..37a65be8 --- /dev/null +++ b/Client/src/StorytellerClient.h @@ -0,0 +1,118 @@ +#ifndef STORYTELLER_CLIENT_H +#define STORYTELLER_CLIENT_H + + +#include +#include + +#include + +#include "KeeperIdCard.h" +#include "chronolog_types.h" +#include "chronolog_client.h" + +namespace chronolog +{ + +class ChronologTimer +{ + public: + uint64_t getTimestamp(); +}; + +class KeeperRecordingClient; + +class RoundRobinKeeperChoice +{ +public: + KeeperRecordingClient* chooseKeeper( std::vector const& vectorOfKeepers, uint64_t chrono_tick ) + { + return vectorOfKeepers[ chrono_tick % vectorOfKeepers.size()]; + } +}; + + +class StorytellerClient +{ +public: + StorytellerClient( ChronologTimer & chronolog_timer, thallium::engine & client_tl_engine, ClientId const& client_id + , std::string const& rpc_protocol = std::string("ofi+sockets") ) + : theTimer(chronolog_timer) + , client_engine(client_tl_engine) + , clientId(client_id) + , rpc_protocol_string(rpc_protocol) + { + std::cout<<"StorytellerClient::StorytellerClient"< initializeStoryWritingHandle(ChronicleName const&, StoryName const&, StoryId const&, std::vector const&); + void removeAcquiredStoryHandle(ChronicleName const&, StoryName const&); + + uint64_t getTimestamp() + { return theTimer.getTimestamp(); } + + ClientId const& getClientId() const + { return clientId; } + + int get_event_index(); + + +private: + StorytellerClient(StorytellerClient const&) = delete; + StorytellerClient & operator= (StorytellerClient const&) = delete; + + thallium::engine & client_engine; + ChronologTimer & theTimer; + ClientId clientId; + std::string rpc_protocol_string; + std::atomic atomic_index; + + std::mutex recordingClientMapMutex; + std::mutex acquiredStoryMapMutex; + + std::map, KeeperRecordingClient*> recordingClientMap; + std::map, StoryHandle*> acquiredStoryHandles; + +}; + + +// this class definition lives in the client lib +template< class KeeperChoicePolicy> +class StoryWritingHandle : public StoryHandle +{ + public: + StoryWritingHandle(StorytellerClient & client, ChronicleName const& a_chronicle, StoryName const& a_story, StoryId const& story_id) + : theClient(client) + , chronicle(a_chronicle) + , story(a_story) + , storyId(story_id) + , keeperChoicePolicy( new KeeperChoicePolicy) + { } + + + virtual ~StoryWritingHandle(); + virtual int log_event( std::string const&); + virtual int log_event( size_t size, void* data); + + void addRecordingClient(KeeperRecordingClient *); + void removeRecordingClient(KeeperIdCard const&); + +private: + + StorytellerClient& theClient; + ChronicleName chronicle; + StoryName story; + StoryId storyId; + KeeperChoicePolicy * keeperChoicePolicy; + std::vector storyKeepers; + +}; + +}//namespace + +#endif diff --git a/Client/src/rpcVisorClient.h b/Client/src/rpcVisorClient.h new file mode 100644 index 00000000..1f2901c5 --- /dev/null +++ b/Client/src/rpcVisorClient.h @@ -0,0 +1,121 @@ + +#ifndef RPC_VISOR_CLIENT_H +#define RPC_VISOR_CLIENT_H + +#include +#include +#include +#include +#include + +#include "error.h" +//#include "../chrono_common/chronolog_types.h" + +namespace tl = thallium; + + +namespace chronolog +{ + + +class RpcVisorClient +{ + +public: + static RpcVisorClient * CreateRpcVisorClient( tl::engine & tl_engine, + std::string const & service_addr, uint16_t provider_id ) + { + try{ + return new RpcVisorClient( tl_engine,service_addr, provider_id); + } catch( tl::exception const&) + { + std::cout<<"KeeperRecordingClient: failed construction"< &attrs, + int &flags) { +// LOGD("%s is called in PID=%d, with args: name=%s, flags=%d, attrs=", + // __FUNCTION__, getpid(), name.c_str(), flags); + return CL_SUCCESS; //CHRONOLOG_RPC_CALL_WRAPPER("CreateChronicle", 0, int, name, attrs, flags); + } + + int DestroyChronicle(std::string const& name) + { + //LOGD("%s is called in PID=%d, with args: name=%s, flags=%d", __FUNCTION__, getpid(), name.c_str(), flags); + return CL_SUCCESS; //CHRONOLOG_RPC_CALL_WRAPPER("DestroyChronicle", 0, int, name, flags); + } + + int DestroyStory(std::string const& chronicle_name, std::string const& story_name) + { + //LOGD("%s is called in PID=%d, with args: chronicle_name=%s, story_name=%s, flags=%d", + // __FUNCTION__, getpid(), chronicle_name.c_str(), story_name.c_str(), flags); + return CL_SUCCESS; //CHRONOLOG_RPC_CALL_WRAPPER("DestroyStory", 0, int, chronicle_name, story_name, flags); + } + + + ~RpcVisorClient() + { + visor_connect.deregister(); + visor_disconnect.deregister(); + create_chronicle.deregister(); + destroy_chronicle.deregister(); + acquire_story.deregister(); + release_story.deregister(); + destroy_story.deregister(); + } + + private: + + + std::string service_addr; // na address of ChronoVisor ClientService + uint16_t service_provider_id; // ChronoVisor ClientService provider_id id + tl::provider_handle service_ph; //provider_handle for client registry service + tl::remote_procedure visor_connect; + tl::remote_procedure visor_disconnect; + tl::remote_procedure create_chronicle; + tl::remote_procedure destroy_chronicle; + tl::remote_procedure acquire_story; + tl::remote_procedure release_story; + tl::remote_procedure destroy_story; + + RpcVisorClient(RpcVisorClient const&) = delete; + RpcVisorClient& operator= (RpcVisorClient const&) = delete; + + + // constructor is private to make sure thalium rpc objects are created on the heap, not stack + RpcVisorClient( tl::engine & tl_engine, std::string const& service_addr, uint16_t provider_id) + : service_addr(service_addr), service_provider_id(provider_id) + , service_ph(tl_engine.lookup( service_addr),provider_id) + { + std::cout<<" RpcVisorClient created for Visor Service at {"< +#include +#include + +#include +#include + +#include "chronolog_types.h" +#include "chronolog_client.h" + +namespace tl = thallium; +namespace chl = chronolog; + +uint64_t get_chrono_timestamp() { + return std::chrono::system_clock::now().time_since_epoch().count(); + } + +int main(int argc, char** argv) { + if(argc != 3) { + std::cerr << "Usage: " << argv[0] << "
" << std::endl; + exit(0); + } + tl::engine myEngine("ofi+sockets", THALLIUM_CLIENT_MODE); + tl::remote_procedure record_event = myEngine.define("record_event"); + tl::endpoint server = myEngine.lookup(argv[1]); + uint16_t provider_id = atoi(argv[2]); + + + + //chronolog::StorytellerClient storytellerClient(myEngine, argv[1], provider_id); + + + for ( int i =0; i <10; ++i) + { + sleep(10); + uint64_t log_time= get_chrono_timestamp(); + chl::LogEvent event( 1, log_time, 7, i, "line_"+std::to_string(i)); + std::cout<<"generated_event {"<< event.storyId<<":"<send_event_msg(event); + } + + + return 0; +} diff --git a/ChronoAPI/ChronoLog/include/ConfigurationManager.h b/chrono_common/ConfigurationManager.h similarity index 99% rename from ChronoAPI/ChronoLog/include/ConfigurationManager.h rename to chrono_common/ConfigurationManager.h index c8071a31..8cd9e451 100644 --- a/ChronoAPI/ChronoLog/include/ConfigurationManager.h +++ b/chrono_common/ConfigurationManager.h @@ -1,7 +1,3 @@ -// -// Created by kfeng on 3/30/22. -// - #ifndef CHRONOLOG_CONFIGURATIONMANAGER_H #define CHRONOLOG_CONFIGURATIONMANAGER_H diff --git a/chrono_common/KeeperIdCard.h b/chrono_common/KeeperIdCard.h new file mode 100644 index 00000000..3838ac0f --- /dev/null +++ b/chrono_common/KeeperIdCard.h @@ -0,0 +1,97 @@ +#ifndef _KEEPER_ID_CARD_H +#define _KEEPER_ID_CARD_H + +#include + +#include + +// this class wrapps ChronoKeeper Process identification +// that will be used by all the ChronoLog Processes +// to both identofy the Keepr process and create RPC client channels +// to send the data to the Keeper Recording service + +namespace chronolog +{ + +// Keeper Process can be uniquely identified by the combination of +// the host IP address + client_port + +typedef uint32_t in_addr_t; +typedef uint16_t in_port_t; +typedef std::pair service_endpoint; + +// KeeperGroup is the logical grouping of KeeperProcesses +typedef uint64_t KeeperGroupId; + + +class KeeperIdCard +{ + + uint64_t keeper_group_id; + uint32_t ip_addr; //IP address as uint32_t in host byte order + uint16_t port; //port number as uint16_t in host byte order + uint16_t tl_provider_id; // id of thallium service provider + +public: + + + KeeperIdCard( uint64_t group_id = 0, uint32_t addr = 0, uint16_t a_port=0, uint16_t provider_id=0) + : keeper_group_id(group_id), ip_addr(addr), port(a_port),tl_provider_id(provider_id) + {} + + KeeperIdCard( KeeperIdCard const& other) + : keeper_group_id(other.getGroupId()), ip_addr(other.getIPaddr()), port(other.getPort()),tl_provider_id(other.getProviderId()) + {} + + ~KeeperIdCard()=default; + + uint64_t getGroupId() const { return keeper_group_id; } + uint32_t getIPaddr() const {return ip_addr; } + uint16_t getPort() const { return port;} + uint16_t getProviderId () const { return tl_provider_id; } + + + // serialization function used by thallium RPC providers + // to serialize/deserialize KeeperIdCard + template + void serialize( SerArchiveT & serT) + { + serT & keeper_group_id; + serT & ip_addr; + serT & port; + serT & tl_provider_id; + } + + std::string & getIPasDottedString ( std::string & a_string ) const + { + + char buffer[INET_ADDRSTRLEN]; + // convert ip from host to network byte order uint32_t + uint32_t ip_net_order = htonl(ip_addr); + // convert network byte order uint32_t to a dotted string + if (NULL != inet_ntop(AF_INET, &ip_net_order, buffer, INET_ADDRSTRLEN)) + { a_string += std::string(buffer); } + return a_string; + } + +}; + +} //namespace chronolog + +inline bool operator==(chronolog::KeeperIdCard const& card1, chronolog::KeeperIdCard const& card2) +{ + return ( (card1.getIPaddr()==card2.getIPaddr() && card1.getPort() == card2.getPort() + && card1.getProviderId() == card2.getProviderId()) ? true : false ); + +} +inline std::ostream & operator<< (std::ostream & out , chronolog::KeeperIdCard const & keeper_id_card) +{ + std::string a_string; + out << "KeeperIdCard{"< +#include +#include "KeeperIdCard.h" + + +namespace chronolog +{ + +class ServiceId +{ +public: + ServiceId( uint32_t addr, uint16_t a_port, uint16_t a_provider_id) + : ip_addr(addr), port(a_port), provider_id(a_provider_id) + {} + ~ServiceId() = default; + + uint32_t ip_addr; //32int IP representation in host notation + uint16_t port; //16int port representation in host notation + uint16_t provider_id; //thalium provider id + + template + void serialize( SerArchiveT& serT) + { + serT & ip_addr; + serT & port; + serT & provider_id; + } + + std::string & getIPasDottedString ( std::string & a_string ) const + { + + char buffer[INET_ADDRSTRLEN]; + // convert ip from host to network byte order uint32_t + uint32_t ip_net_order = htonl(ip_addr); + // convert network byte order uint32_t to a dotted string + if (NULL != inet_ntop(AF_INET, &ip_net_order, buffer, INET_ADDRSTRLEN)) + {a_string += std::string(buffer); } + return a_string; + } +}; + +class KeeperRegistrationMsg +{ + + KeeperIdCard keeperIdCard; + ServiceId adminServiceId; + +public: + + + KeeperRegistrationMsg ( KeeperIdCard const & keeper_card = KeeperIdCard{0,0,0} + , ServiceId const & admin_service_id = ServiceId{0,0,0}) + : keeperIdCard(keeper_card) + , adminServiceId(admin_service_id) + {} + + ~KeeperRegistrationMsg()=default; + + KeeperIdCard const& getKeeperIdCard() const + { return keeperIdCard; } + + ServiceId const& getAdminServiceId() const + { return adminServiceId; } + + template + void serialize( SerArchiveT& serT) + { + serT & keeperIdCard; + serT & adminServiceId; + } + +}; + +}//namespace + +inline std::ostream & operator << (std::ostream & out, chronolog::ServiceId const serviceId) +{ + std::string a_string; + out <<"{"<< serviceId.getIPasDottedString(a_string)<<":"< +#include "KeeperIdCard.h" + + +namespace chronolog +{ + +class KeeperStatsMsg +{ + + KeeperIdCard keeperIdCard; + uint32_t active_story_count; + +public: + + + KeeperStatsMsg ( KeeperIdCard const & keeper_card = KeeperIdCard{0,0,0} + , uint32_t count=0) + : keeperIdCard(keeper_card) + , active_story_count(count) + {} + + ~KeeperStatsMsg()=default; + + KeeperIdCard const& getKeeperIdCard() const + { return keeperIdCard; } + + uint32_t getActiveStoryCount() const + { return active_story_count; } + + template + void serialize( SerArchiveT& serT) + { + serT & keeperIdCard; + serT & active_story_count; + } + +}; + +} + +inline std::ostream & operator << (std::ostream & out,chronolog::KeeperStatsMsg const& stats_msg) +{ + out<<"KeeperStatsMsg{"< + void serialize( SerArchiveT & serT) + { + serT (storyId, eventTime, clientId, eventIndex, logRecord); + } +}; + + +} +#endif diff --git a/default_conf.json.in b/default_conf.json.in new file mode 100644 index 00000000..44579623 --- /dev/null +++ b/default_conf.json.in @@ -0,0 +1,68 @@ +{ + "clock": { + "clocksource_type": "CPP_STYLE", + "drift_cal_sleep_sec": 10, + "drift_cal_sleep_nsec": 0 + }, + "rpc": { + "available_protocol": { + "sockets_conf": "ofi+sockets", + "tcp_conf": "ofi+tcp", + "shm_conf": "ofi+shm", + "verbs_conf": "ofi+verbs", + "verbs_domain": "mlx5_0" + }, + "rpc_client_visor": { + "rpc_implementation": "Thallium_sockets", + "protocol_conf": "ofi+sockets", + "rpc_client_end": { + "client_port": 4444, + "client_service_threads": 1 + }, + "rpc_visor_end": { + "visor_ip": "127.0.0.1", + "visor_base_port": 5555, + "visor_ports": 1, + "visor_service_threads": 1 + } + }, + "rpc_visor_keeper": { + "rpc_implementation": "Thallium_sockets", + "protocol_conf": "ofi+sockets", + "rpc_visor_end": { + "visor_ip": "127.0.0.1", + "visor_base_port": 6666, + "visor_ports": 1, + "visor_service_threads": 1 + }, + "rpc_keeper_end": { + "keeper_ip": "127.0.0.1", + "keeper_port": 7777, + "keeper_service_threads": 1 + } + }, + "rpc_client_keeper": { + "rpc_implementation": "Thallium_sockets", + "protocol_conf": "ofi+sockets", + "rpc_client_end": { + "client_port": 8888, + "client_service_threads": 1 + }, + "rpc_keeper_end": { + "keeper_ip": "127.0.0.1", + "keeper_port": 9999, + "keeper_service_threads": 1 + } + } + }, + "authentication": { + "auth_type": "RBAC", + "module_location": "/path/to/auth_module" + }, + "chrono_visor": { + }, + "chrono_client": { + }, + "chrono_keeper": { + } +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e6b4af57..1c10fdcb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ add_subdirectory(integration) -add_subdirectory(communication) -add_subdirectory(overhead) +#add_subdirectory(communication) +#add_subdirectory(overhead) diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index 8fae76a2..f95766ea 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(ChronoVisor) +#add_subdirectory(ChronoVisor) add_subdirectory(Client) diff --git a/test/integration/ChronoVisor/CMakeLists.txt b/test/integration/ChronoVisor/CMakeLists.txt index c7221563..645cf847 100644 --- a/test/integration/ChronoVisor/CMakeLists.txt +++ b/test/integration/ChronoVisor/CMakeLists.txt @@ -2,11 +2,6 @@ find_package(mercury REQUIRED) find_package(thallium REQUIRED) find_package(Threads REQUIRED) -add_executable(chronolog_client_test chronolog_client.cpp) -target_link_libraries(chronolog_client_test Serde socketpp pthread) -add_dependencies(chronolog_client_test Serde socketpp) - -add_test(NAME chronolog_client_test COMMAND chronolog_client_test) add_executable(chronovisor_server_test chronovisor_server.cpp ../../../ChronoVisor/src/ChronoVisorServer2.cpp diff --git a/test/integration/Client/CMakeLists.txt b/test/integration/Client/CMakeLists.txt index 91e9a9ea..fae91a46 100644 --- a/test/integration/Client/CMakeLists.txt +++ b/test/integration/Client/CMakeLists.txt @@ -13,17 +13,18 @@ foreach(client ${client_examples}) add_executable(${client} ${client}.cpp) add_dependencies(${client} copyserverlist) target_include_directories(${client} PRIVATE ../Client/include) - target_link_libraries(${client} ChronoLogClient_lib -lpthread -lrt) + target_link_libraries(${client} chronolog_client -lpthread -lrt) #add_test(NAME ${client} COMMAND ${client}) endforeach() set(client_openmp client_lib_multi_openmp_test) +find_package(OpenMP) foreach(client ${client_openmp}) add_executable(${client} ${client}.cpp) add_dependencies(${client} copyserverlist) target_include_directories(${client} PRIVATE ../Client/include) - target_link_libraries(${client} ChronoLogClient_lib OpenMP::OpenMP_CXX) + target_link_libraries(${client} chronolog_client OpenMP::OpenMP_CXX) endforeach() set(client_mpi client_lib_hybrid_argobots_test) @@ -32,8 +33,8 @@ foreach(client ${client_mpi}) add_executable(${client} ${client}.cpp) add_dependencies(${client} copyserverlist) target_include_directories(${client} PRIVATE ../Client/include ${MPI_CXX_INCLUDE_DIRS}) - target_link_libraries(${client} ChronoLogClient_lib ${MPI_CXX_LIBRARIES} -lpthread -lrt) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../default_conf.json.in + target_link_libraries(${client} chronolog_client ${MPI_CXX_LIBRARIES} -lpthread -lrt) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../default_conf.json.in ${CMAKE_CURRENT_BINARY_DIR}/default_conf.json COPYONLY) endforeach() diff --git a/test/integration/Client/client_lib_connect_rpc_test.cpp b/test/integration/Client/client_lib_connect_rpc_test.cpp index 73db4bff..096c12a1 100644 --- a/test/integration/Client/client_lib_connect_rpc_test.cpp +++ b/test/integration/Client/client_lib_connect_rpc_test.cpp @@ -2,7 +2,10 @@ // Created by kfeng on 7/11/22. // -#include "client.h" +#include + +#include "ConfigurationManager.h" +#include "chronolog_client.h" #include "common.h" #include @@ -10,11 +13,11 @@ int main() { ChronoLogRPCImplementation protocol = CHRONOLOG_THALLIUM_SOCKETS; - std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; ChronoLog::ConfigurationManager confManager("./default_conf.json"); - ChronoLogClient client(confManager); - int num_ports = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_PORTS; + std::string server_ip = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); + int base_port = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; + int num_ports = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_PORTS; + chronolog::Client client(confManager); std::string server_uri; std::vector client_ids; int flags = 0; @@ -27,16 +30,19 @@ int main() { client_ids.reserve(NUM_CONNECTION); for (int i = 0; i < NUM_CONNECTION; i++) client_ids.emplace_back(gen_random(8)); for (int i = 0; i < NUM_CONNECTION; i++) { - switch (CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.RPC_IMPLEMENTATION) { + switch (confManager.RPC_CONF.CLIENT_VISOR_CONF.RPC_IMPLEMENTATION) { case CHRONOLOG_THALLIUM_SOCKETS: case CHRONOLOG_THALLIUM_TCP: case CHRONOLOG_THALLIUM_ROCE: - server_uri = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); + server_uri = confManager.RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); break; + default: + server_uri="ofi+sockets"; } + server_uri += "://" + server_ip + ":" + std::to_string(base_port + i); t1 = std::chrono::steady_clock::now(); - ret = client.Connect(server_uri, client_ids[i], flags, offset); + ret = client.Connect(server_uri, client_ids[i], flags); //, offset); assert(ret == CL_SUCCESS); t2 = std::chrono::steady_clock::now(); duration_connect += (t2 - t1); @@ -44,7 +50,7 @@ int main() { for (int i = 0; i < NUM_CONNECTION; i++) { t1 = std::chrono::steady_clock::now(); - ret = client.Disconnect(client_ids[i], flags); + ret = client.Disconnect(); //client_ids[i], flags); assert(ret == CL_SUCCESS); t2 = std::chrono::steady_clock::now(); duration_disconnect += (t2 - t1); @@ -54,4 +60,4 @@ int main() { LOGI("Disconnect takes %lf ns", duration_disconnect.count() / NUM_CONNECTION); return 0; -} \ No newline at end of file +} diff --git a/test/integration/Client/client_lib_hybrid_argobots_test.cpp b/test/integration/Client/client_lib_hybrid_argobots_test.cpp index ee31ba6a..d92ed8bf 100644 --- a/test/integration/Client/client_lib_hybrid_argobots_test.cpp +++ b/test/integration/Client/client_lib_hybrid_argobots_test.cpp @@ -1,93 +1,87 @@ -// -// Created by kfeng on 7/18/22. -// -#include +#include #include #include #include #include -ChronoLogClient *client; - -struct thread_arg -{ - int tid; +chronolog::Client *client; +struct thread_arg { + int tid; }; -void thread_function(void *t) -{ +void thread_function(void *t) { - std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; - std::string client_id = gen_random(8); - std::string server_uri = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); - server_uri += "://"+server_ip+":"+std::to_string(base_port); + auto CHRONOLOG_CONF = ChronoLog::Singleton::GetInstance() + + std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); + int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; + std::string client_id = gen_random(8); + std::string server_uri = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); + server_uri += "://" + server_ip + ":" + std::to_string(base_port); int flags = 0; - uint64_t offset; - int ret = client->Connect(server_uri,client_id,flags,offset); - ret = client->Disconnect(client_id,flags); + uint64_t offset; + int ret = client->Connect(server_uri, client_id, flags);//, offset); + ret = client->Disconnect();//client_id, flags); } -int main(int argc,char **argv) { +int main(int argc, char **argv) { std::vector client_ids; std::atomic duration_connect{}, duration_disconnect{}; std::vector thread_vec; uint64_t offset; int provided; - MPI_Init_thread(&argc,&argv,MPI_THREAD_MULTIPLE,&provided); + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); ChronoLogRPCImplementation protocol = CHRONOLOG_THALLIUM_SOCKETS; - std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; - client = new ChronoLogClient(protocol, server_ip, base_port); + ChronoLog::ConfigurationManager confManager; + + std::string server_ip = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); + int base_port = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; + client = new chronolog::Client(confManager); // protocol, server_ip, base_port); int num_xstreams = 8; int num_threads = 8; - ABT_xstream *xstreams = (ABT_xstream *)malloc(sizeof(ABT_xstream) * num_xstreams); - ABT_pool *pools = (ABT_pool *)malloc(sizeof(ABT_pool) * num_xstreams); - ABT_thread *threads = (ABT_thread*)malloc(sizeof(ABT_thread)*num_threads); - struct thread_arg *t_args = (struct thread_arg*)malloc(num_threads*sizeof(struct thread_arg)); + ABT_xstream *xstreams = (ABT_xstream *) malloc(sizeof(ABT_xstream) * num_xstreams); + ABT_pool *pools = (ABT_pool *) malloc(sizeof(ABT_pool) * num_xstreams); + ABT_thread *threads = (ABT_thread *) malloc(sizeof(ABT_thread) * num_threads); + struct thread_arg *t_args = (struct thread_arg *) malloc(num_threads * sizeof(struct thread_arg)); ABT_init(argc, argv); ABT_xstream_self(&xstreams[0]); - for (int i = 1; i < num_xstreams; i++) - { + for (int i = 1; i < num_xstreams; i++) { ABT_xstream_create(ABT_SCHED_NULL, &xstreams[i]); } - for (int i = 0; i < num_xstreams; i++) - { + for (int i = 0; i < num_xstreams; i++) { ABT_xstream_get_main_pools(xstreams[i], 1, &pools[i]); } - for(int i=0;i @@ -14,7 +14,7 @@ int main() { ChronoLog::ConfigurationManager confManager("./default_conf.json"); - ChronoLogClient client(confManager); + chronolog::Client client(confManager); std::vector chronicle_names; std::chrono::steady_clock::time_point t1, t2; std::chrono::duration duration_create_chronicle{}, @@ -29,12 +29,12 @@ int main() { int flags; int ret; uint64_t offset = 0; - std::string server_uri = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string() + "://" + - CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string() + - std::to_string(CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT); + std::string server_uri = confManager.RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string() + "://" + + confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string() + + std::to_string(confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT); std::string client_id = gen_random(8); - client.Connect(server_uri, client_id, flags, offset); + client.Connect(server_uri, client_id, flags);//, offset); chronicle_names.reserve(NUM_CHRONICLE); for (int i = 0; i < NUM_CHRONICLE; i++) { std::string chronicle_name(gen_random(CHRONICLE_NAME_LEN)); @@ -50,25 +50,28 @@ int main() { t1 = std::chrono::steady_clock::now(); ret = client.CreateChronicle(chronicle_names[i], chronicle_attrs, flags); t2 = std::chrono::steady_clock::now(); - ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); duration_create_chronicle += (t2 - t1); } + t1 = std::chrono::steady_clock::now(); - std::vector chronicle_names_retrieved = client.ShowChronicles(client_id); + std::vector chronicle_names_retrieved; + chronicle_names_retrieved= client.ShowChronicles(chronicle_names_retrieved); t2 = std::chrono::steady_clock::now(); duration_show_chronicles += (t2 - t1); - std::sort(chronicle_names_retrieved.begin(), chronicle_names_retrieved.end()); + //std::sort(chronicle_names_retrieved.begin(), chronicle_names_retrieved.end()); std::vector chronicle_names_sorted = chronicle_names; - std::sort(chronicle_names_sorted.begin(), chronicle_names_sorted.end()); - assert(chronicle_names_retrieved == chronicle_names_sorted); + //std::sort(chronicle_names_sorted.begin(), chronicle_names_sorted.end()); + //assert(chronicle_names_retrieved == chronicle_names_sorted); + for (int i = 0; i < NUM_CHRONICLE; i++) { std::string key("Date"); t1 = std::chrono::steady_clock::now(); ret = client.EditChronicleAttr(chronicle_names[i], key, "2023-01-15"); t2 = std::chrono::steady_clock::now(); - //ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); duration_edit_chronicle_attr += (t2 - t1); std::vector story_names; @@ -82,36 +85,39 @@ int main() { story_attrs.emplace("IndexGranularity", "Millisecond"); story_attrs.emplace("TieringPolicy", "Hot"); t1 = std::chrono::steady_clock::now(); - ret = client.AcquireStory(chronicle_names[i], story_names[j], story_attrs, flags); + ret = client.AcquireStory(chronicle_names[i], story_names[j], story_attrs, flags).first; t2 = std::chrono::steady_clock::now(); - ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); duration_acquire_story += (t2 - t1); } - t1 = std::chrono::steady_clock::now(); - std::vector stories_names_retrieved = client.ShowStories(client_id, chronicle_names[i]); + ret = client.Disconnect(); //client_id, flags); + assert(ret == CL_ERR_ACQUIRED); + + /* t1 = std::chrono::steady_clock::now(); + std::vector stories_names_retrieved = client.ShowStories( chronicle_names[i]); t2 = std::chrono::steady_clock::now(); duration_show_stories += (t2 - t1); std::sort(stories_names_retrieved.begin(), stories_names_retrieved.end()); std::vector story_names_sorted = story_names; std::sort(story_names_sorted.begin(), story_names_sorted.end()); assert(stories_names_retrieved == story_names_sorted); - +*/ for (int j = 0; j < NUM_STORY; j++) { flags = 4; t1 = std::chrono::steady_clock::now(); - ret = client.ReleaseStory(chronicle_names[i], story_names[j], flags); + ret = client.ReleaseStory(chronicle_names[i], story_names[j]); //, flags); t2 = std::chrono::steady_clock::now(); - ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); duration_release_story += (t2 - t1); } flags = 8; for (int j = 0; j < NUM_STORY; j++) { t1 = std::chrono::steady_clock::now(); - ret = client.DestroyStory(chronicle_names[i], story_names[j], flags); + ret = client.DestroyStory(chronicle_names[i], story_names[j]); // flags); t2 = std::chrono::steady_clock::now(); - ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); duration_destroy_story += (t2 - t1); } @@ -119,7 +125,7 @@ int main() { t1 = std::chrono::steady_clock::now(); ret = client.GetChronicleAttr(chronicle_names[i], key, value); t2 = std::chrono::steady_clock::now(); - //ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); //FIXME: returning data using parameter is not working, the following assert will fail //ASSERT(value, ==, "2023-01-15"); duration_get_chronicle_attr += (t2 - t1); @@ -128,12 +134,19 @@ int main() { flags = 32; for (int i = 0; i < NUM_CHRONICLE; i++) { t1 = std::chrono::steady_clock::now(); - bool ret = client.DestroyChronicle(chronicle_names[i], flags); + bool ret = client.DestroyChronicle(chronicle_names[i]); // flags); t2 = std::chrono::steady_clock::now(); - ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); duration_destroy_chronicle += (t2 - t1); }; + for (int i = 0; i < NUM_STORY; i++) { + std::unordered_map story_attrs; + std::string temp_str = gen_random(STORY_NAME_LEN); + ret = client.AcquireStory(chronicle_names[i].append(temp_str), temp_str, story_attrs, flags).first; + assert(ret == CL_ERR_NOT_EXIST); + } + LOGI("CreateChronicle takes %lf ns", duration_create_chronicle.count() / NUM_CHRONICLE); LOGI("EditChronicleAttr takes %lf ns", duration_edit_chronicle_attr.count() / NUM_CHRONICLE); LOGI("AcquireStory takes %lf ns", duration_acquire_story.count() / (NUM_CHRONICLE * NUM_STORY)); @@ -159,7 +172,7 @@ int main() { t1 = std::chrono::steady_clock::now(); ret = client.CreateChronicle(chronicle_name, chronicle_attrs, flags); t2 = std::chrono::steady_clock::now(); - ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); duration_create_chronicle += (t2 - t1); } @@ -167,12 +180,12 @@ int main() { duration_destroy_chronicle = std::chrono::duration(); for (int i = 0; i < NUM_CHRONICLE; i++) { t1 = std::chrono::steady_clock::now(); - int ret = client.DestroyChronicle(chronicle_names[i], flags); + int ret = client.DestroyChronicle(chronicle_names[i]);//, flags); t2 = std::chrono::steady_clock::now(); - ASSERT(ret, ==, CL_SUCCESS); + assert(ret == CL_SUCCESS); duration_destroy_chronicle += (t2 - t1); } - client.Disconnect(client_id, flags); + client.Disconnect();//client_id, flags); LOGI("CreateChronicle2 takes %lf ns", duration_create_chronicle.count() / NUM_CHRONICLE); LOGI("DestroyChronicle2 takes %lf ns", duration_destroy_chronicle.count() / NUM_CHRONICLE); diff --git a/test/integration/Client/client_lib_multi_argobots_test.cpp b/test/integration/Client/client_lib_multi_argobots_test.cpp index be7bb7e6..3fb6da69 100644 --- a/test/integration/Client/client_lib_multi_argobots_test.cpp +++ b/test/integration/Client/client_lib_multi_argobots_test.cpp @@ -1,124 +1,131 @@ // // Created by kfeng on 7/18/22. // -#include +#include #include #include #include +#include #define CHRONICLE_NAME_LEN 32 #define STORY_NAME_LEN 32 -ChronoLogClient *client; - -struct thread_arg -{ - int tid; +chronolog::Client *client; +struct thread_arg { + int tid; + std::string client_id; }; -void thread_function(void *tt) -{ - struct thread_arg *t = (struct thread_arg*)tt; +void thread_function(void *tt) { + struct thread_arg *t = (struct thread_arg *) tt; - std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; - /*std::string client_id = gen_random(8); - std::string server_uri = CHRONOLOG_CONF->SOCKETS_CONF.string(); - server_uri += "://"+server_ip+":"+std::to_string(base_port);*/ + //std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); + //int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; + /*std::string client_id = gen_random(8); + std::string server_uri = CHRONOLOG_CONF->SOCKETS_CONF.string(); + server_uri += "://"+server_ip+":"+std::to_string(base_port);*/ int flags = 0; - uint64_t offset; - int ret; - std::string chronicle_name; - if(t->tid%2==0) chronicle_name = "gscs5er9TcdJ9mOgUDteDVBcI0oQjozK"; - else chronicle_name = "6RPkwqX2IOpR41dVCqmWauX9RfXIuTAp"; - std::unordered_map chronicle_attrs; - chronicle_attrs.emplace("Priority", "High"); - chronicle_attrs.emplace("IndexGranularity", "Millisecond"); - chronicle_attrs.emplace("TieringPolicy", "Hot"); - ret = client->CreateChronicle(chronicle_name, chronicle_attrs, flags); - flags = 1; - std::string story_name = gen_random(STORY_NAME_LEN); - std::unordered_map story_attrs; - story_attrs.emplace("Priority", "High"); - story_attrs.emplace("IndexGranularity", "Millisecond"); - story_attrs.emplace("TieringPolicy", "Hot"); - flags = 2; - ret = client->AcquireStory(chronicle_name, story_name, story_attrs, flags); - ret = client->ReleaseStory(chronicle_name,story_name,flags); - ret = client->DestroyStory(chronicle_name,story_name,flags); - ret = client->DestroyChronicle(chronicle_name,flags); + uint64_t offset; + int ret; + std::string chronicle_name; + if (t->tid % 2 == 0) chronicle_name = "gscs5er9TcdJ9mOgUDteDVBcI0oQjozK"; + else chronicle_name = "6RPkwqX2IOpR41dVCqmWauX9RfXIuTAp"; + std::unordered_map chronicle_attrs; + chronicle_attrs.emplace("Priority", "High"); + chronicle_attrs.emplace("IndexGranularity", "Millisecond"); + chronicle_attrs.emplace("TieringPolicy", "Hot"); + ret = client->CreateChronicle(chronicle_name, chronicle_attrs, flags); + flags = 1; + std::string story_name = gen_random(STORY_NAME_LEN); + std::unordered_map story_attrs; + story_attrs.emplace("Priority", "High"); + story_attrs.emplace("IndexGranularity", "Millisecond"); + story_attrs.emplace("TieringPolicy", "Hot"); + flags = 2; + auto acquire_ret= client->AcquireStory(chronicle_name, story_name, story_attrs, flags); + assert(acquire_ret.first == CL_SUCCESS); + ret = client->DestroyStory(chronicle_name, story_name);//, flags); + assert(ret == CL_ERR_ACQUIRED); + ret = client->Disconnect();//t->client_id, flags); + assert(ret == CL_ERR_ACQUIRED); + ret = client->ReleaseStory(chronicle_name, story_name);//, flags); + assert(ret == CL_SUCCESS); + ret = client->DestroyStory(chronicle_name, story_name);//, flags); + assert(ret == CL_SUCCESS || ret == CL_ERR_NOT_EXIST || ret == CL_ERR_ACQUIRED); + ret = client->DestroyChronicle(chronicle_name);//, flags); + assert(ret == CL_SUCCESS || ret == CL_ERR_NOT_EXIST || ret == CL_ERR_ACQUIRED); } -int main(int argc,char **argv) { +int main(int argc, char **argv) { std::atomic duration_connect{}, duration_disconnect{}; std::vector thread_vec; uint64_t offset; - + ChronoLogRPCImplementation protocol = CHRONOLOG_THALLIUM_SOCKETS; - std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; - client = new ChronoLogClient(protocol, server_ip, base_port); + ChronoLog::ConfigurationManager confManager("./default_conf.json"); + std::string server_ip = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); + int base_port = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; + client = new chronolog::Client(confManager); //protocol, server_ip, base_port); int num_xstreams = 8; int num_threads = 8; - ABT_xstream *xstreams = (ABT_xstream *)malloc(sizeof(ABT_xstream) * num_xstreams); - ABT_pool *pools = (ABT_pool *)malloc(sizeof(ABT_pool) * num_xstreams); - ABT_thread *threads = (ABT_thread*)malloc(sizeof(ABT_thread)*num_threads); - struct thread_arg *t_args = (struct thread_arg*)malloc(num_threads*sizeof(struct thread_arg)); + ABT_xstream *xstreams = (ABT_xstream *) malloc(sizeof(ABT_xstream) * num_xstreams); + ABT_pool *pools = (ABT_pool *) malloc(sizeof(ABT_pool) * num_xstreams); + ABT_thread *threads = (ABT_thread *) malloc(sizeof(ABT_thread) * num_threads); + std::vector t_args(num_threads);; std::string client_id = gen_random(8);; - std::string server_uri = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); - server_uri += "://"+server_ip+":"+std::to_string(base_port); + std::string server_uri = confManager.RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); + server_uri += "://" + server_ip + ":" + std::to_string(base_port); int flags = 0; - int ret = client->Connect(server_uri,client_id,flags,offset); + int ret = client->Connect(server_uri, client_id, flags);//, offset); + assert(ret == CL_SUCCESS); - for(int i=0;iDisconnect(client_id,flags); + ret = client->Disconnect();//client_id, flags); + assert(ret == CL_SUCCESS); - delete client; + delete client; return 0; } diff --git a/test/integration/Client/client_lib_multi_openmp_test.cpp b/test/integration/Client/client_lib_multi_openmp_test.cpp index a4cf874c..5f4fad05 100644 --- a/test/integration/Client/client_lib_multi_openmp_test.cpp +++ b/test/integration/Client/client_lib_multi_openmp_test.cpp @@ -1,7 +1,4 @@ -// -// Created by kfeng on 7/18/22. -// -#include +#include #include #include #include @@ -12,45 +9,53 @@ int main() { ChronoLogRPCImplementation protocol = CHRONOLOG_THALLIUM_SOCKETS; - std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; - ChronoLogClient *client = new ChronoLogClient(protocol, server_ip, base_port); + ChronoLog::ConfigurationManager confManager("./default_conf.json"); + std::string server_ip = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); + int base_port = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; + chronolog::Client *client = new chronolog::Client(confManager);//protocol, server_ip, base_port); int num_threads = 8; omp_set_num_threads(num_threads); - std::string server_uri = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); - server_uri += "://"+server_ip+":"+std::to_string(base_port); + std::string server_uri = confManager.RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); + server_uri += "://" + server_ip + ":" + std::to_string(base_port); int flags = 0; uint64_t offset; - std::string client_id = gen_random(8); - int ret = client->Connect(server_uri,client_id,flags,offset); - #pragma omp for - for(int i=0;i chronicle_attrs; - chronicle_attrs.emplace("Priority", "High"); - chronicle_attrs.emplace("IndexGranularity", "Millisecond"); - chronicle_attrs.emplace("TieringPolicy", "Hot"); - ret = client->CreateChronicle(chronicle_name, chronicle_attrs, flags); - flags = 1; - std::string story_name = gen_random(STORY_NAME_LEN); - std::unordered_map story_attrs; - story_attrs.emplace("Priority", "High"); - story_attrs.emplace("IndexGranularity", "Millisecond"); - story_attrs.emplace("TieringPolicy", "Hot"); - flags = 2; - ret = client->AcquireStory(chronicle_name, story_name, story_attrs, flags); - ret = client->ReleaseStory(chronicle_name,story_name,flags); - ret = client->DestroyStory(chronicle_name,story_name,flags); - ret = client->DestroyChronicle(chronicle_name,flags); + std::string client_id = gen_random(8); + int ret = client->Connect(server_uri, client_id, flags);//, offset); +#pragma omp for + for (int i = 0; i < num_threads; i++) { + std::string chronicle_name; + if (i % 2 == 0) chronicle_name = "gscs5er9TcdJ9mOgUDteDVBcI0oQjozK"; + else chronicle_name = "6RPkwqX2IOpR41dVCqmWauX9RfXIuTAp"; + std::unordered_map chronicle_attrs; + chronicle_attrs.emplace("Priority", "High"); + chronicle_attrs.emplace("IndexGranularity", "Millisecond"); + chronicle_attrs.emplace("TieringPolicy", "Hot"); + ret = client->CreateChronicle(chronicle_name, chronicle_attrs, flags); + flags = 1; + std::string story_name = gen_random(STORY_NAME_LEN); + std::unordered_map story_attrs; + story_attrs.emplace("Priority", "High"); + story_attrs.emplace("IndexGranularity", "Millisecond"); + story_attrs.emplace("TieringPolicy", "Hot"); + flags = 2; + auto acquire_ret = client->AcquireStory(chronicle_name, story_name, story_attrs, flags); + assert(acquire_ret.first == CL_SUCCESS); + ret = client->DestroyStory(chronicle_name, story_name);//, flags); + assert(ret == CL_ERR_ACQUIRED); + ret = client->Disconnect();//client_id, flags); + assert(ret == CL_ERR_ACQUIRED); + ret = client->ReleaseStory(chronicle_name, story_name);//, flags); + assert(ret == CL_SUCCESS); + ret = client->DestroyStory(chronicle_name, story_name);//, flags); + assert(ret == CL_SUCCESS || ret == CL_ERR_NOT_EXIST || ret == CL_ERR_ACQUIRED); + ret = client->DestroyChronicle(chronicle_name);//, flags); + assert(ret == CL_SUCCESS || ret == CL_ERR_NOT_EXIST || ret == CL_ERR_ACQUIRED); } - ret = client->Disconnect(client_id,flags); + ret = client->Disconnect();//client_id, flags); delete client; diff --git a/test/integration/Client/client_lib_multi_pthread_test.cpp b/test/integration/Client/client_lib_multi_pthread_test.cpp index 817bd0d3..7e1e5580 100644 --- a/test/integration/Client/client_lib_multi_pthread_test.cpp +++ b/test/integration/Client/client_lib_multi_pthread_test.cpp @@ -1,29 +1,27 @@ -// -// Created by kfeng on 7/18/22. -// -#include + +#include #include #include #include + #define STORY_NAME_LEN 32 -struct thread_arg -{ - int tid; +struct thread_arg { + int tid; + std::string client_id; }; -ChronoLogClient *client; +chronolog::Client *client; -void thread_body(struct thread_arg *t) -{ +void thread_body(struct thread_arg *t) { - std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; + //std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); + //int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; int flags = 0; uint64_t offset; int ret; std::string chronicle_name; - if(t->tid%2==0) chronicle_name = "gscs5er9TcdJ9mOgUDteDVBcI0oQjozK"; + if (t->tid % 2 == 0) chronicle_name = "gscs5er9TcdJ9mOgUDteDVBcI0oQjozK"; else chronicle_name = "6RPkwqX2IOpR41dVCqmWauX9RfXIuTAp"; std::unordered_map chronicle_attrs; chronicle_attrs.emplace("Priority", "High"); @@ -37,13 +35,21 @@ void thread_body(struct thread_arg *t) story_attrs.emplace("IndexGranularity", "Millisecond"); story_attrs.emplace("TieringPolicy", "Hot"); flags = 2; - ret = client->AcquireStory(chronicle_name, story_name, story_attrs, flags); - ret = client->ReleaseStory(chronicle_name,story_name,flags); - ret = client->DestroyStory(chronicle_name,story_name,flags); - ret = client->DestroyChronicle(chronicle_name,flags); + auto acquire_ret = client->AcquireStory(chronicle_name, story_name, story_attrs, flags); + assert(acquire_ret.first == CL_SUCCESS); + ret = client->DestroyStory(chronicle_name, story_name);//, flags); + assert(ret == CL_ERR_ACQUIRED); + ret = client->Disconnect(); //t->client_id, flags); + assert(ret == CL_ERR_ACQUIRED); + ret = client->ReleaseStory(chronicle_name, story_name);//, flags); + assert(ret == CL_SUCCESS); + ret = client->DestroyStory(chronicle_name, story_name);//, flags); + assert(ret == CL_SUCCESS || ret == CL_ERR_NOT_EXIST || ret == CL_ERR_ACQUIRED); + ret = client->DestroyChronicle(chronicle_name);//, flags); + assert(ret == CL_SUCCESS || ret == CL_ERR_NOT_EXIST || ret == CL_ERR_ACQUIRED); } -int main(int argc,char **argv) { +int main(int argc, char **argv) { int provided; @@ -55,28 +61,29 @@ int main(int argc,char **argv) { std::vector workers(num_threads); ChronoLogRPCImplementation protocol = CHRONOLOG_THALLIUM_SOCKETS; - std::string server_ip = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); - int base_port = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; - client = new ChronoLogClient(protocol, server_ip, base_port); + ChronoLog::ConfigurationManager confManager("./default_conf.json"); + std::string server_ip = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_IP.string(); + int base_port = confManager.RPC_CONF.CLIENT_VISOR_CONF.VISOR_END_CONF.VISOR_BASE_PORT; + client = new chronolog::Client(confManager);//protocol, server_ip, base_port); - std::string server_uri = CHRONOLOG_CONF->RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); - server_uri += "://"+server_ip+":"+std::to_string(base_port); + std::string server_uri = confManager.RPC_CONF.CLIENT_VISOR_CONF.PROTO_CONF.string(); + server_uri += "://" + server_ip + ":" + std::to_string(base_port); int flags = 0; uint64_t offset; - int ret = client->Connect(server_uri,client_id,flags,offset); + int ret = client->Connect(server_uri, client_id, flags);//, offset); - for(int i=0;iDisconnect(client_id,flags); + ret = client->Disconnect();//client_id, flags); delete client; return 0;