Commit cef7980f authored by Matthieu Dorier's avatar Matthieu Dorier
Browse files

finished API, started CppUnit testing

parent 5ff11a14
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
cmake_minimum_required (VERSION 3.0) cmake_minimum_required (VERSION 3.0)
project (hepnos CXX) project (hepnos CXX)
enable_testing ()
add_definitions (-g) add_definitions (-g)
...@@ -46,6 +45,19 @@ xpkg_import_module (bake-server REQUIRED bake-server) ...@@ -46,6 +45,19 @@ xpkg_import_module (bake-server REQUIRED bake-server)
xpkg_import_module (ch-placement REQUIRED ch-placement) xpkg_import_module (ch-placement REQUIRED ch-placement)
find_package (yaml-cpp REQUIRED) find_package (yaml-cpp REQUIRED)
find_package (CppUnit)
if (CPPUNIT_FOUND)
message(STATUS "CppUnit found, unit tests will be compiled")
include_directories(${CPPUNIT_INCLUDE_DIR})
enable_testing()
else (CPPUNIT_FOUND)
message(STATUS "CppUnit not found, unit tests will not be compiled")
endif (CPPUNIT_FOUND)
add_subdirectory (src) add_subdirectory (src)
add_subdirectory (test)
add_subdirectory (bin) add_subdirectory (bin)
if(CPPUNIT_FOUND AND ENABLE_TESTS)
message(STATUS "Unit tests are enabled, will be built")
add_subdirectory (test)
endif(CPPUNIT_FOUND AND ENABLE_TESTS)
add_executable(hepnos-service hepnos-service.cpp hepnos-service-util.cpp) add_executable(hepnos-daemon hepnos-daemon.cpp)
target_link_libraries(hepnos-service sdskv-server bake-server yaml-cpp) target_link_libraries(hepnos-daemon hepnos-service yaml-cpp margo bake-server sdskv-server)
/*
* (C) 2018 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <unistd.h>
#include <mpi.h>
#include <margo.h>
#include <bake-server.h>
#include <sdskv-server.h>
#include <yaml-cpp/yaml.h>
#include "hepnos-service.h"
#define ASSERT(__cond, __msg, ...) { if(!(__cond)) { fprintf(stderr, "[%s:%d] " __msg, __FILE__, __LINE__, __VA_ARGS__); exit(-1); } }
void usage(void)
{
fprintf(stderr, "Usage: hepnos-service <addr> <config>\n");
fprintf(stderr, " <addr> the Mercury address to listen on (e.g. tcp://)\n");
fprintf(stderr, " <config> path to the YAML file to generate for clients\n");
exit(-1);
}
int main(int argc, char *argv[])
{
char* listen_addr;
char* config_file;
int rank;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(argc != 3) {
if(rank == 0) {
usage();
}
MPI_Finalize();
exit(0);
}
listen_addr = argv[1];
config_file = argv[2];
hepnos_run_service(MPI_COMM_WORLD, listen_addr, config_file);
MPI_Finalize();
}
#include "hepnos-service-util.hpp"
int hepnos_sdskv_provider_setup(sdskv_provider_t sdskv_provider) {
}
#ifndef __HEPNOS_SERVICE_UTIL_H
#define __HEPNOS_SERVICE_UTIL_H
#include <sdskv-server.h>
int hepnos_sdskv_provider_setup(sdskv_provider_t sdskv_provider);
#endif
#
# Find the CppUnit includes and library
#
# This module defines
# CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc.
# CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit.
# CPPUNIT_FOUND, If false, do not try to use CppUnit.
# also defined, but not for general use are
# CPPUNIT_LIBRARY, where to find the CppUnit library.
# CPPUNIT_DEBUG_LIBRARY, where to find the CppUnit library in debug mode.
FIND_PATH(CPPUNIT_INCLUDE_DIR cppunit/TestCase.h HINTS
/usr/local/include
/usr/include
ENV CppUnit_ROOT
)
# With Win32, important to have both
IF(WIN32)
FIND_LIBRARY(CPPUNIT_LIBRARY cppunit
${CPPUNIT_INCLUDE_DIR}/../lib
/usr/local/lib
/usr/lib)
FIND_LIBRARY(CPPUNIT_DEBUG_LIBRARY cppunitd
${CPPUNIT_INCLUDE_DIR}/../lib
/usr/local/lib
/usr/lib)
ELSE(WIN32)
# On unix system, debug and release have the same name
FIND_LIBRARY(CPPUNIT_LIBRARY cppunit
${CPPUNIT_INCLUDE_DIR}/../lib
/usr/local/lib
/usr/lib)
FIND_LIBRARY(CPPUNIT_DEBUG_LIBRARY cppunit
${CPPUNIT_INCLUDE_DIR}/../lib
/usr/local/lib
/usr/lib)
ENDIF(WIN32)
IF(CPPUNIT_INCLUDE_DIR)
IF(CPPUNIT_LIBRARY)
SET(CPPUNIT_FOUND "YES")
SET(CPPUNIT_LIBRARIES ${CPPUNIT_LIBRARY} ${CMAKE_DL_LIBS})
SET(CPPUNIT_DEBUG_LIBRARIES ${CPPUNIT_DEBUG_LIBRARY}
${CMAKE_DL_LIBS})
ENDIF(CPPUNIT_LIBRARY)
ENDIF(CPPUNIT_INCLUDE_DIR)
#ifndef __HEPNOS_SERVICE_H
#define __HEPNOS_SERVICE_H
#include <mpi.h>
#ifdef __cplusplus
extern "C" {
#endif
void hepnos_run_service(MPI_Comm comm, const char* listen_addr, const char* config_file);
#ifdef __cplusplus
}
#endif
#endif
#ifndef __HEPNOS_H
#define __HEPNOS_H
#include <hepnos/DataStore.hpp>
#include <hepnos/DataSet.hpp>
#include <hepnos/Demangle.hpp>
#include <hepnos/Event.hpp>
#include <hepnos/EventNumber.hpp>
#include <hepnos/Exception.hpp>
#include <hepnos/KeyValueContainer.hpp>
#include <hepnos/Run.hpp>
#include <hepnos/RunNumber.hpp>
#include <hepnos/RunSet.hpp>
#include <hepnos/SubRun.hpp>
#include <hepnos/SubRunNumber.hpp>
#endif
...@@ -237,6 +237,11 @@ class DataStore { ...@@ -237,6 +237,11 @@ class DataStore {
*/ */
DataSet createDataSet(const std::string& name); DataSet createDataSet(const std::string& name);
/**
* @brief Shuts down the HEPnOS service.
*/
void shutdown();
private: private:
/** /**
......
...@@ -7,11 +7,14 @@ ...@@ -7,11 +7,14 @@
#define __HEPNOS_EVENT_NUMBER_H #define __HEPNOS_EVENT_NUMBER_H
#include <cstdint> #include <cstdint>
#include <limits>
namespace hepnos { namespace hepnos {
typedef std::uint64_t EventNumber; typedef std::uint64_t EventNumber;
const EventNumber InvalidEventNumber = std::numeric_limits<EventNumber>::max();
} }
#endif #endif
...@@ -7,11 +7,14 @@ ...@@ -7,11 +7,14 @@
#define __HEPNOS_RUN_NUMBER_H #define __HEPNOS_RUN_NUMBER_H
#include <cstdint> #include <cstdint>
#include <limits>
namespace hepnos { namespace hepnos {
typedef std::uint64_t RunNumber; typedef std::uint64_t RunNumber;
const RunNumber InvalidRunNumber = std::numeric_limits<RunNumber>::max();
} }
#endif #endif
...@@ -22,6 +22,7 @@ namespace hepnos { ...@@ -22,6 +22,7 @@ namespace hepnos {
class RunSet { class RunSet {
friend class DataSet::Impl; friend class DataSet::Impl;
friend class DataSet;
private: private:
...@@ -81,6 +82,18 @@ class RunSet { ...@@ -81,6 +82,18 @@ class RunSet {
class const_iterator; class const_iterator;
class iterator; class iterator;
/**
* @brief Accesses an existing Run using the ()
* operator. If no Run correspond to the provided number,
* the function returns a Run instance r such that
* r.valid() is false.
*
* @param runNumber run number of the Run to retrieve.
*
* @return a Run corresponding to the provided number.
*/
Run operator()(const RunNumber& runNumber);
/** /**
* @brief Searches this RunSet for a Run with * @brief Searches this RunSet for a Run with
* the provided run number and returns an iterator to * the provided run number and returns an iterator to
......
...@@ -7,11 +7,14 @@ ...@@ -7,11 +7,14 @@
#define __HEPNOS_SUB_RUN_NUMBER_H #define __HEPNOS_SUB_RUN_NUMBER_H
#include <cstdint> #include <cstdint>
#include <limits>
namespace hepnos { namespace hepnos {
typedef std::uint64_t SubRunNumber; typedef std::uint64_t SubRunNumber;
const SubRunNumber InvalidSubRunNumber = std::numeric_limits<SubRunNumber>::max();
} }
#endif #endif
...@@ -6,6 +6,8 @@ set(hepnos-src DataStore.cpp ...@@ -6,6 +6,8 @@ set(hepnos-src DataStore.cpp
SubRun.cpp SubRun.cpp
Event.cpp) Event.cpp)
set(hepnos-service-src service/HEPnOSService.cpp)
# load package helper for generating cmake CONFIG packages # load package helper for generating cmake CONFIG packages
include (CMakePackageConfigHelpers) include (CMakePackageConfigHelpers)
...@@ -15,8 +17,8 @@ set (hepnos-pkg "share/cmake/hepnos") ...@@ -15,8 +17,8 @@ set (hepnos-pkg "share/cmake/hepnos")
# #
# library version set here (e.g. for shared libs). # library version set here (e.g. for shared libs).
# #
set (HEPNOS_VERSION_MAJOR 1) set (HEPNOS_VERSION_MAJOR 0)
set (HEPNOS_VERSION_MINOR 0) set (HEPNOS_VERSION_MINOR 1)
set (HEPNOS_VERSION_PATCH 0) set (HEPNOS_VERSION_PATCH 0)
set (hepnos-vers "${HEPNOS_VERSION_MAJOR}.${HEPNOS_VERSION_MINOR}") set (hepnos-vers "${HEPNOS_VERSION_MAJOR}.${HEPNOS_VERSION_MINOR}")
set (HEPNOS_VERSION "${hepnos-vers}.${HEPNOS_VERSION_PATCH}") set (HEPNOS_VERSION "${hepnos-vers}.${HEPNOS_VERSION_PATCH}")
...@@ -35,6 +37,18 @@ set_target_properties (hepnos ...@@ -35,6 +37,18 @@ set_target_properties (hepnos
PROPERTIES VERSION ${HEPNOS_VERSION} PROPERTIES VERSION ${HEPNOS_VERSION}
SOVERSION ${HEPNOS_VERSION_MAJOR}) SOVERSION ${HEPNOS_VERSION_MAJOR})
add_library(hepnos-service ${hepnos-service-src})
target_link_libraries (hepnos mercury margo yaml-cpp sdskv-client sdskv-server bake-client bake-server ch-placement)
target_include_directories (hepnos-service PUBLIC $<INSTALL_INTERFACE:include>)
# local include's BEFORE, in case old incompatable .h files in prefix/include
target_include_directories (hepnos-service BEFORE PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>)
# for shared libs, establish the lib version
set_target_properties (hepnos-service
PROPERTIES VERSION ${HEPNOS_VERSION}
SOVERSION ${HEPNOS_VERSION_MAJOR})
# #
# installation stuff (packaging and install commands) # installation stuff (packaging and install commands)
# #
...@@ -49,12 +63,13 @@ configure_file (hepnos-config.cmake.in hepnos-config.cmake @ONLY) ...@@ -49,12 +63,13 @@ configure_file (hepnos-config.cmake.in hepnos-config.cmake @ONLY)
# #
# "make install" rules # "make install" rules
# #
#install (TARGETS hepnos EXPORT hepnos-targets install (TARGETS hepnos EXPORT hepnos-targets
# ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
# LIBRARY DESTINATION lib) LIBRARY DESTINATION lib)
#install (EXPORT hepnos-targets install (TARGETS hepnos-service ARCHIVE DESTINATION lib LIBRARY DESTINATION lib)
# DESTINATION ${hepnos-pkg} install (EXPORT hepnos-targets
# FILE "hepnos-targets.cmake") DESTINATION ${hepnos-pkg}
FILE "hepnos-targets.cmake")
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/hepnos-config.cmake" install (FILES "${CMAKE_CURRENT_BINARY_DIR}/hepnos-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/hepnos-config-version.cmake" "${CMAKE_CURRENT_BINARY_DIR}/hepnos-config-version.cmake"
"../cmake/xpkg-import.cmake" "../cmake/xpkg-import.cmake"
...@@ -62,3 +77,6 @@ install (FILES "${CMAKE_CURRENT_BINARY_DIR}/hepnos-config.cmake" ...@@ -62,3 +77,6 @@ install (FILES "${CMAKE_CURRENT_BINARY_DIR}/hepnos-config.cmake"
install (DIRECTORY ../include/hepnos install (DIRECTORY ../include/hepnos
DESTINATION include DESTINATION include
FILES_MATCHING PATTERN "*.hpp") FILES_MATCHING PATTERN "*.hpp")
install (DIRECTORY ../include/hepnos
DESTINATION include
FILES_MATCHING PATTERN "*.h")
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "hepnos/DataSet.hpp" #include "hepnos/DataSet.hpp"
#include "hepnos/Run.hpp" #include "hepnos/Run.hpp"
#include "hepnos/RunSet.hpp" #include "hepnos/RunSet.hpp"
#include "private/RunSetImpl.hpp"
#include "private/RunImpl.hpp" #include "private/RunImpl.hpp"
#include "private/DataSetImpl.hpp" #include "private/DataSetImpl.hpp"
#include "private/DataStoreImpl.hpp" #include "private/DataStoreImpl.hpp"
...@@ -36,7 +37,10 @@ DataSet::DataSet(const DataSet& other) ...@@ -36,7 +37,10 @@ DataSet::DataSet(const DataSet& other)
other.m_impl->m_container, other.m_impl->m_container,
other.m_impl->m_name)) {} other.m_impl->m_name)) {}
DataSet::DataSet(DataSet&&) = default; DataSet::DataSet(DataSet&& other)
: m_impl(std::move(other.m_impl)) {
m_impl->m_runset.m_impl->m_dataset = this;
}
DataSet& DataSet::operator=(const DataSet& other) { DataSet& DataSet::operator=(const DataSet& other) {
if(this == &other) return *this; if(this == &other) return *this;
...@@ -48,7 +52,12 @@ DataSet& DataSet::operator=(const DataSet& other) { ...@@ -48,7 +52,12 @@ DataSet& DataSet::operator=(const DataSet& other) {
return *this; return *this;
} }
DataSet& DataSet::operator=(DataSet&&) = default; DataSet& DataSet::operator=(DataSet&& other) {
if(this == &other) return *this;
m_impl = std::move(other.m_impl);
m_impl->m_runset.m_impl->m_dataset = this;
return *this;
}
DataSet::~DataSet() {} DataSet::~DataSet() {}
...@@ -59,7 +68,7 @@ DataSet DataSet::next() const { ...@@ -59,7 +68,7 @@ DataSet DataSet::next() const {
size_t s = m_impl->m_datastore->m_impl->nextKeys( size_t s = m_impl->m_datastore->m_impl->nextKeys(
m_impl->m_level, m_impl->m_container, m_impl->m_name, keys, 1); m_impl->m_level, m_impl->m_container, m_impl->m_name, keys, 1);
if(s == 0) return DataSet(); if(s == 0) return DataSet();
return DataSet(m_impl->m_datastore, m_impl->m_level, m_impl->m_container, keys[0]); return DataSet(m_impl->m_datastore, m_impl->m_level, keys[0]);
} }
bool DataSet::valid() const { bool DataSet::valid() const {
...@@ -111,8 +120,9 @@ std::string DataSet::fullname() const { ...@@ -111,8 +120,9 @@ std::string DataSet::fullname() const {
} }
DataSet DataSet::createDataSet(const std::string& name) { DataSet DataSet::createDataSet(const std::string& name) {
if(name.find('/') != std::string::npos) { if(name.find('/') != std::string::npos
throw Exception("Invalid character '/' in dataset name"); || name.find('%') != std::string::npos) {
throw Exception("Invalid character '/' or '%' in dataset name");
} }
std::string parent = fullname(); std::string parent = fullname();
m_impl->m_datastore->m_impl->store(m_impl->m_level+1, parent, name, std::vector<char>()); m_impl->m_datastore->m_impl->store(m_impl->m_level+1, parent, name, std::vector<char>());
...@@ -120,6 +130,9 @@ DataSet DataSet::createDataSet(const std::string& name) { ...@@ -120,6 +130,9 @@ DataSet DataSet::createDataSet(const std::string& name) {
} }
Run DataSet::createRun(const RunNumber& runNumber) { Run DataSet::createRun(const RunNumber& runNumber) {
if(InvalidRunNumber == runNumber) {
throw Exception("Trying to create a Run with InvalidRunNumber");
}
std::string parent = fullname(); std::string parent = fullname();
std::string runStr = Run::Impl::makeKeyStringFromRunNumber(runNumber); std::string runStr = Run::Impl::makeKeyStringFromRunNumber(runNumber);
m_impl->m_datastore->m_impl->store(m_impl->m_level+1, parent, runStr, std::vector<char>()); m_impl->m_datastore->m_impl->store(m_impl->m_level+1, parent, runStr, std::vector<char>());
...@@ -138,8 +151,9 @@ Run DataSet::operator()(const RunNumber& runNumber) const { ...@@ -138,8 +151,9 @@ Run DataSet::operator()(const RunNumber& runNumber) const {
DataSet::iterator DataSet::find(const std::string& datasetName) { DataSet::iterator DataSet::find(const std::string& datasetName) {
int ret; int ret;
if(datasetName.find('/') != std::string::npos) { if(datasetName.find('/') != std::string::npos
throw Exception("Invalid character '/' in dataset name"); || datasetName.find('%') != std::string::npos) {
throw Exception("Invalid character '/' or '%' in dataset name");
} }
std::vector<char> data; std::vector<char> data;
std::string parent = fullname(); std::string parent = fullname();
......
...@@ -54,7 +54,7 @@ DataStore::iterator DataStore::find(const std::string& datasetName) { ...@@ -54,7 +54,7 @@ DataStore::iterator DataStore::find(const std::string& datasetName) {
if(!b) { if(!b) {
return m_impl->m_end; return m_impl->m_end;
} }
return iterator(DataSet(this, 1, datasetName)); return iterator(DataSet(this, 1, "", datasetName));
} }
DataSet DataStore::operator[](const std::string& datasetName) const { DataSet DataStore::operator[](const std::string& datasetName) const {
...@@ -137,6 +137,12 @@ DataSet DataStore::createDataSet(const std::string& name) { ...@@ -137,6 +137,12 @@ DataSet DataStore::createDataSet(const std::string& name) {
return DataSet(this, 1, "", name); return DataSet(this, 1, "", name);
} }
void DataStore::shutdown() {
for(auto addr : m_impl->m_addrs) {
margo_shutdown_remote_instance(m_impl->m_mid, addr);
}
}
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// DataStore::const_iterator::Impl implementation // DataStore::const_iterator::Impl implementation
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
namespace hepnos { namespace hepnos {
Run::Run() Run::Run()
: m_impl(std::make_unique<Run::Impl>(nullptr, 0, "", 0)) {} : m_impl(std::make_unique<Run::Impl>(nullptr, 0, "", InvalidRunNumber)) {}
Run::Run(DataStore* ds, uint8_t level, const std::string& container, const RunNumber& rn) Run::Run(DataStore* ds, uint8_t level, const std::string& container, const RunNumber& rn)
: m_impl(std::make_unique<Run::Impl>(ds, level, container, rn)) { } : m_impl(std::make_unique<Run::Impl>(ds, level, container, rn)) { }
......
...@@ -20,10 +20,16 @@ namespace hepnos { ...@@ -20,10 +20,16 @@ namespace hepnos {
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
RunSet::RunSet(DataSet* ds) RunSet::RunSet(DataSet* ds)
: m_impl(std::make_unique<RunSet::Impl>(ds)) {} : m_impl(std::make_unique<RunSet::Impl>(ds)) {
}
RunSet::~RunSet() {} RunSet::~RunSet() {}
Run RunSet::operator()(const RunNumber& runNumber) {
auto it = find(runNumber);
return std::move(*it);
}
RunSet::iterator RunSet::find(const RunNumber& runNumber) { RunSet::iterator RunSet::find(const RunNumber& runNumber) {
int ret; int ret;
std::vector<char> data; std::vector<char> data;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
namespace hepnos { namespace hepnos {
SubRun::SubRun() SubRun::SubRun()
: m_impl(std::make_unique<Impl>(nullptr, 0, "", 0)) {} : m_impl(std::make_unique<Impl>(nullptr, 0, "", InvalidSubRunNumber)) {}
SubRun::SubRun(DataStore* ds, uint8_t level, const std::string& container, const SubRunNumber& rn) SubRun::SubRun(DataStore* ds, uint8_t level, const std::string& container, const SubRunNumber& rn)
: m_impl(std::make_unique<Impl>(ds, level, container, rn)) { } : m_impl(std::make_unique<Impl>(ds, level, container, rn)) { }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define __HEPNOS_PRIVATE_DATASTORE_IMPL #define __HEPNOS_PRIVATE_DATASTORE_IMPL
#include <vector> #include <vector>
#include <unordered_set>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
...@@ -28,6 +29,7 @@ class DataStore::Impl { ...@@ -28,6 +29,7 @@ class DataStore::Impl {
public: public:
margo_instance_id m_mid; // Margo instance margo_instance_id m_mid; // Margo instance
std::unordered_set<hg_addr_t> m_addrs; // Addresses used by the service
sdskv_client_t m_sdskv_client; // SDSKV client