Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/ci-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ jobs:
--env LD_PRELOAD=libcapio_posix.so \
--name capio-docker \
alphaunito/capio:latest \
capio_server_unit_tests \
jq -n --arg pwd $(pwd) \
'{name: "CAPIO", IO_Graph: [], exclude: [$pwd + "/aNonExistingFile", $pwd, $pwd + "/"]}' \
> test_config.json && \
capio_syscall_unit_tests \
--gtest_break_on_failure \
--gtest_print_time=1

Expand Down
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ IF (CAPIO_LOG AND CMAKE_BUILD_TYPE STREQUAL "Debug")
include_directories("${PROJECT_BINARY_DIR}/include/syscall")
ENDIF (CAPIO_LOG AND CMAKE_BUILD_TYPE STREQUAL "Debug")


#####################################
# Global required dependencies
#####################################
FetchContent_Declare(
capio_cl
GIT_REPOSITORY https://github.com/High-Performance-IO/CAPIO-CL.git
GIT_TAG v1.3.4
)

#####################################
# Targets
#####################################
Expand Down
6 changes: 0 additions & 6 deletions capio/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ FetchContent_Declare(
set(ARGS_BUILD_EXAMPLE OFF CACHE INTERNAL "")
set(ARGS_BUILD_UNITTESTS OFF CACHE INTERNAL "")

FetchContent_Declare(
capio_cl
GIT_REPOSITORY https://github.com/High-Performance-IO/CAPIO-CL.git
GIT_TAG v1.3.4
)

FetchContent_MakeAvailable(args capio_cl)

#####################################
Expand Down
12 changes: 10 additions & 2 deletions capio/server/include/client-manager/client_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,20 @@ class ClientManager {
CircularBuffer<char> requests;
std::unordered_map<int, CircularBuffer<off64_t>> responses;

/// @brief default app name
const std::string default_app_name = CAPIO_DEFAULT_APP_NAME;

/**
* Data buffers variables
*/
struct ClientDataBuffers {
SPSCQueue *ClientToServer;
SPSCQueue *ServerToClient;
SPSCQueue ClientToServer;
SPSCQueue ServerToClient;

/// @brief Constructor for struct so that try_emplace can be called with no explicit call to
/// new()
ClientDataBuffers(const std::string &clientToServerName,
const std::string &serverToClientName, const std::string &workflow_name);
};

std::unordered_map<long, ClientDataBuffers> data_buffers;
Expand Down
1 change: 1 addition & 0 deletions capio/server/include/utils/capio_file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <set>
#include <string_view>
#include <utility>
#include <vector>

#include <fcntl.h>
#include <sys/stat.h>
Expand Down
28 changes: 14 additions & 14 deletions capio/server/src/client_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
#include "utils/capiocl_adapter.hpp"
#include "utils/common.hpp"

ClientManager::ClientDataBuffers::ClientDataBuffers(const std::string &clientToServerName,
const std::string &serverToClientName,
const std::string &wf_name)
: ClientToServer(clientToServerName, get_cache_lines(), get_cache_line_size(), wf_name),
ServerToClient(serverToClientName, get_cache_lines(), get_cache_line_size(), wf_name) {}

ClientManager::ClientManager()
: requests{SHM_COMM_CHAN_NAME, CAPIO_REQ_BUFF_CNT, CAPIO_REQ_MAX_SIZE,
CapioCLEngine::get().getWorkflowName()} {
Expand All @@ -21,13 +27,9 @@ ClientManager::~ClientManager() {
void ClientManager::registerClient(pid_t tid, const std::string &app_name, const bool wait) {
START_LOG(gettid(), "call(tid=%ld, app_name=%s)", tid, app_name.c_str());

ClientDataBuffers buffers{
new SPSCQueue(SHM_SPSC_PREFIX_WRITE + std::to_string(tid), get_cache_lines(),
get_cache_line_size(), CapioCLEngine::get().getWorkflowName()),
new SPSCQueue(SHM_SPSC_PREFIX_READ + std::to_string(tid), get_cache_lines(),
get_cache_line_size(), CapioCLEngine::get().getWorkflowName())};

data_buffers.emplace(tid, buffers);
data_buffers.try_emplace(tid, SHM_SPSC_PREFIX_WRITE + std::to_string(tid),
SHM_SPSC_PREFIX_READ + std::to_string(tid),
CapioCLEngine::get().getWorkflowName());
app_names.emplace(tid, app_name);
files_created_by_producer.emplace(tid, std::initializer_list<std::string>{});
files_created_by_app_name.emplace(app_name, std::initializer_list<std::string>{});
Expand Down Expand Up @@ -63,8 +65,6 @@ void ClientManager::unlockClonedChild(const pid_t tid) {
void ClientManager::removeClient(const pid_t tid) {
START_LOG(gettid(), "call(tid=%ld)", tid);
if (const auto it_resp = data_buffers.find(tid); it_resp != data_buffers.end()) {
delete it_resp->second.ClientToServer;
delete it_resp->second.ServerToClient;
data_buffers.erase(it_resp);
}
const std::string &app_name = this->getAppName(tid);
Expand All @@ -87,10 +87,10 @@ void ClientManager::replyToClient(const int tid, const off64_t offset, char *buf

if (const auto out = data_buffers.find(tid); out != data_buffers.end()) {
this->replyToClient(tid, offset + count);
out->second.ServerToClient->write(buf + offset, count);
out->second.ServerToClient.write(buf + offset, count);
return;
}
LOG("Err: no such buffer for provided tid");
throw std::runtime_error("Err: no such buffer for provided tid");
}

// NOTE: do not use const reference for path here as the emplace method leaves the original in an
Expand Down Expand Up @@ -153,15 +153,15 @@ const std::vector<std::string> &ClientManager::getProducedFiles(const pid_t tid)

const std::string &ClientManager::getAppName(const pid_t tid) const {
START_LOG(gettid(), "call(tid=%ld)", tid);
static std::string default_app_name = CAPIO_DEFAULT_APP_NAME;
if (const auto itm = app_names.find(tid); itm != app_names.end()) {
return itm->second;
} else {
return default_app_name;
}
return default_app_name;
}

SPSCQueue &ClientManager::getClientToServerDataBuffers(const pid_t tid) {
return *data_buffers.at(tid).ClientToServer;
return data_buffers.at(tid).ClientToServer;
}

size_t ClientManager::getConnectedPosixClients() const { return data_buffers.size(); }
Expand Down
5 changes: 3 additions & 2 deletions capio/server/src/storage_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ CapioFile &StorageManager::add(const std::filesystem::path &path, bool is_dir, s
auto n_close_count = CapioCLEngine::get().getCommitCloseCount(path);

if (n_file > 1) {
// NODE: This is probably because it needs to be filled even when dealing with directories
// NOTE: This is probably because it needs to be filled even when dealing with directories
init_size = CAPIO_DEFAULT_DIR_INITIAL_SIZE;
}

Expand Down Expand Up @@ -228,7 +228,8 @@ void StorageManager::clone(const pid_t parent_tid, const pid_t child_tid) {

std::vector<std::filesystem::path> StorageManager::getPaths() const {
const shared_lock_guard slg(_mutex_storage);
std::vector<std::filesystem::path> paths(_storage.size());
std::vector<std::filesystem::path> paths;
Comment thread
marcoSanti marked this conversation as resolved.
paths.reserve(_storage.size());
for (const auto &[file_path, _] : _storage) {
paths.emplace_back(file_path);
}
Expand Down
37 changes: 32 additions & 5 deletions capio/tests/unit/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@
# Target information
#####################################
set(TARGET_NAME capio_server_unit_tests)

FetchContent_MakeAvailable(capio_cl)

set(TARGET_INCLUDE_FOLDER "${PROJECT_SOURCE_DIR}/capio/server")
set(TARGET_SOURCES
src/capio_file.cpp

file(GLOB_RECURSE SERVER_SOURCES
"${CMAKE_SOURCE_DIR}/capio/server/**/*.cpp"
)

file(GLOB_RECURSE TARGET_TEST_SOURCE
"${CMAKE_CURRENT_SOURCE_DIR}/**/*.cpp"
)

#####################################
# Target definition
#####################################
add_executable(${TARGET_NAME} ${TARGET_SOURCES})
add_executable(${TARGET_NAME} ${TARGET_TEST_SOURCE} ${SERVER_SOURCES} )

#####################################
# Include files and directories
Expand All @@ -20,12 +28,15 @@ target_sources(${TARGET_NAME} PRIVATE
"${CAPIO_COMMON_HEADERS}"
"${CAPIO_SERVER_HEADERS}"
)
target_include_directories(${TARGET_NAME} PRIVATE "${TARGET_INCLUDE_FOLDER}/include")
target_include_directories(${TARGET_NAME} PRIVATE
"${TARGET_INCLUDE_FOLDER}/include"
${capio_cl_SOURCE_DIR}
)

#####################################
# Link libraries
#####################################
target_link_libraries(${TARGET_NAME} PRIVATE GTest::gtest_main rt)
target_link_libraries(${TARGET_NAME} PRIVATE GTest::gtest_main rt libcapio_cl)

#####################################
# Configure tests
Expand All @@ -34,6 +45,22 @@ gtest_discover_tests(${TARGET_NAME}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)

#####################################
# Code coverage
#####################################
IF (ENABLE_COVERAGE)
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(${TARGET_NAME} PRIVATE CAPIO_COVERAGE)
target_compile_options(${TARGET_NAME} PRIVATE --coverage -fprofile-arcs -ftest-coverage)
target_link_options(${TARGET_NAME} PRIVATE --coverage -fprofile-arcs -ftest-coverage)
IF (CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
target_link_libraries(${TARGET_NAME} PRIVATE gcov)
ENDIF (CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
ELSE (CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Code coverage is disabled in release mode.")
ENDIF (CMAKE_BUILD_TYPE STREQUAL "Debug")
ENDIF (ENABLE_COVERAGE)

#####################################
# Install rules
#####################################
Expand Down
12 changes: 6 additions & 6 deletions capio/tests/unit/server/src/capio_file.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#include <gtest/gtest.h>

#include <iostream>

#include "common/env.hpp"
#ifndef CAPIO_CAPIO_FILE_HPP
#define CAPIO_CAPIO_FILE_HPP
#include "utils/capio_file.hpp"
#include "common/env.hpp"
#include <gtest/gtest.h>

TEST(ServerTest, TestInsertSingleSector) {
CapioFile c_file;
Expand Down Expand Up @@ -59,4 +58,5 @@ TEST(ServerTest, TestInsertTwoOverlappingSectorsNested) {
auto &sectors = c_file.get_sectors();
EXPECT_EQ(sectors.size(), 1);
EXPECT_NE(sectors.find({1L, 4L}), sectors.end());
}
}
#endif // CAPIO_CAPIO_FILE_HPP
62 changes: 62 additions & 0 deletions capio/tests/unit/server/src/client_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#ifndef CAPIO_CLIENT_MANAGER_HPP
#define CAPIO_CLIENT_MANAGER_HPP
#include <gtest/gtest.h>

#include <client-manager/client_manager.hpp>

extern ClientManager *client_manager;

TEST(ClientManagerTestEnvironment, testReplyToNonClient) {
char buffer[1024];
EXPECT_THROW(client_manager->replyToClient(-1, 0, buffer, 0), std::runtime_error);
}

TEST(ClientManagerTestEnvironment, testGetNumberOfConnectedClients) {

EXPECT_EQ(client_manager->getConnectedPosixClients(), 0);

client_manager->registerClient(1234);
EXPECT_EQ(client_manager->getConnectedPosixClients(), 1);

client_manager->removeClient(1234);
EXPECT_EQ(client_manager->getConnectedPosixClients(), 0);
}

TEST(ClientManagerTestEnvironment, testFailedRequestCode) {

// NOTE: there is no need to delete this object as it is only attaching to the shm allocated by
// client_manager. Also calling delete on this raises std::terminate as an exception is thrown
// in the destructor
// TODO: change behaviour of ERR_EXIT to not throw exceptions but only print error and continue
const auto request_queue =
new CircularBuffer<char>(SHM_COMM_CHAN_NAME, CAPIO_REQ_BUFF_CNT, CAPIO_REQ_MAX_SIZE);

char req[CAPIO_REQ_MAX_SIZE], new_req[CAPIO_REQ_MAX_SIZE];
constexpr int TEST_REQ_CODE = 123;
sprintf(req, "%04d aaaa bbbb cccc", TEST_REQ_CODE);
request_queue->write(req, CAPIO_REQ_MAX_SIZE);
const auto return_code = client_manager->readNextRequest(new_req);
std::cout << new_req << std::endl;
EXPECT_EQ(return_code, TEST_REQ_CODE);

sprintf(req, "abc aaaa bbbb cccc");
request_queue->write(req, CAPIO_REQ_MAX_SIZE);

EXPECT_EQ(client_manager->readNextRequest(new_req), -1);
}

TEST(ClientManagerTestEnvironment, testAddAndRemoveProducedFiles) {

client_manager->registerClient(1234, "test_app");
client_manager->registerProducedFile(1234, "test.txt");

EXPECT_TRUE(client_manager->isProducer(1234, "test.txt"));

client_manager->removeProducedFile(1234, "test.txt");
EXPECT_FALSE(client_manager->isProducer(1234, "test.txt"));

client_manager->registerProducedFile(1111, "test1.txt");
EXPECT_FALSE(client_manager->isProducer(1111, "test1.txt"));
}

#endif // CAPIO_CLIENT_MANAGER_HPP
45 changes: 45 additions & 0 deletions capio/tests/unit/server/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <gtest/gtest.h>

char *node_name;

#include "capiocl.hpp"
#include "capiocl/engine.h"
#include "client-manager/client_manager.hpp"
#include "common/constants.hpp"
#include "storage/manager.hpp"
#include "utils/capiocl_adapter.hpp"
#include "utils/location.hpp"

capiocl::engine::Engine *capio_cl_engine = nullptr;
StorageManager *storage_manager = nullptr;
ClientManager *client_manager = nullptr;

const capiocl::engine::Engine &CapioCLEngine::get() { return *capio_cl_engine; }

class ServerUnitTestEnvironment : public testing::Environment {
public:
explicit ServerUnitTestEnvironment() = default;

void SetUp() override {
capio_cl_engine = new capiocl::engine::Engine(false);
node_name = new char[HOST_NAME_MAX];
gethostname(node_name, HOST_NAME_MAX);
open_files_location();

client_manager = new ClientManager();
storage_manager = new StorageManager();
}

void TearDown() override {
delete storage_manager;
delete client_manager;
delete capio_cl_engine;
}
};

int main(int argc, char **argv, char **envp) {
testing::InitGoogleTest(&argc, argv);

testing::AddGlobalTestEnvironment(new ServerUnitTestEnvironment());
return RUN_ALL_TESTS();
}
Loading