add DB library code
This commit is contained in:
parent
3c42545dfb
commit
92cf285b72
9 changed files with 1309 additions and 0 deletions
101
CMakeLists.txt
Normal file
101
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
#
|
||||||
|
# This file is part of the ACT library
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023 Fabian Posch
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
project(
|
||||||
|
actsim-cluster-agent
|
||||||
|
VERSION 0.0.2
|
||||||
|
DESCRIPTION "A cluster agent for the actsim simulator."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set the program version
|
||||||
|
add_compile_definitions(PROG_VERSION="0.0.1")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
|
||||||
|
add_compile_options(-Wall
|
||||||
|
-Wextra
|
||||||
|
-Wconversion-null
|
||||||
|
-Wmissing-declarations
|
||||||
|
-Woverlength-strings)
|
||||||
|
add_compile_options(
|
||||||
|
-Wpointer-arith
|
||||||
|
-Wunused-local-typedefs
|
||||||
|
-Wunused-result
|
||||||
|
-Wvarargs
|
||||||
|
-Wvla
|
||||||
|
-Wwrite-strings
|
||||||
|
-Wformat-security
|
||||||
|
-Wundef)
|
||||||
|
add_compile_options(-O2)
|
||||||
|
|
||||||
|
include_directories(./)
|
||||||
|
|
||||||
|
# Include shared act libraries
|
||||||
|
# We need this mostly for file elaboration ahead of cluster deployment
|
||||||
|
#add_library(ActLib SHARED IMPORTED)
|
||||||
|
#set_target_properties(ActLib PROPERTIES IMPORTED_LOCATION $ENV{ACT_HOME}/lib/libact.a)
|
||||||
|
|
||||||
|
#add_library(ActCommon SHARED IMPORTED)
|
||||||
|
#set_target_properties(ActCommon PROPERTIES IMPORTED_LOCATION $ENV{ACT_HOME}/lib/libvlsilib.a)
|
||||||
|
|
||||||
|
|
||||||
|
# ATTENTION
|
||||||
|
# The main executable is defined in the CMakeLists.txt in the ./src folder.
|
||||||
|
|
||||||
|
|
||||||
|
# Set the output directory of static libraries (we don't need that)
|
||||||
|
#set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)
|
||||||
|
|
||||||
|
# Set the output directory of executables
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
||||||
|
|
||||||
|
set(CMAKE_INSTALL_PREFIX $ENV{ACT_HOME} CACHE PATH "installation path" FORCE)
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
# Link the needed libraries into it
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
# act-deploy-commands
|
||||||
|
act-deploy-db-lib
|
||||||
|
# act-deploy-pipeline-modules-lib
|
||||||
|
# act-deploy-test-gen-modules-lib
|
||||||
|
# yaml-cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the Postgresql library
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
-lpqxx -lpq
|
||||||
|
)
|
||||||
|
|
||||||
|
# specify install targets
|
||||||
|
install(
|
||||||
|
TARGETS actsim-cluster-agent
|
||||||
|
DESTINATION bin
|
||||||
|
)
|
||||||
|
|
||||||
|
# We don't provide a library
|
||||||
|
#install(
|
||||||
|
# TARGETS dflowchp
|
||||||
|
# DESTINATION lib
|
||||||
|
#)
|
||||||
143
include/db_lib/db_client.hpp
Normal file
143
include/db_lib/db_client.hpp
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Fabian Posch
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __DB_CLIENT_H__
|
||||||
|
#define __DB_CLIENT_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <pqxx/pqxx>
|
||||||
|
#include "db_types.hpp"
|
||||||
|
#include "task.hpp"
|
||||||
|
|
||||||
|
namespace db {
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// some database constants
|
||||||
|
#define MAX_CON_RETRIES 5
|
||||||
|
|
||||||
|
class Connection {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Connection(
|
||||||
|
db_credentials_t credentials,
|
||||||
|
std::function<void(pqxx::connection *c)> setup_function
|
||||||
|
);
|
||||||
|
|
||||||
|
Connection(
|
||||||
|
db_credentials_t credentials
|
||||||
|
);
|
||||||
|
|
||||||
|
~Connection();
|
||||||
|
|
||||||
|
pqxx::connection* get_connection() { return c; };
|
||||||
|
void setup() {
|
||||||
|
setup_function(this->c);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connect();
|
||||||
|
void disconnect();
|
||||||
|
bool ensure_connected();
|
||||||
|
int find_job(std::string p_name, std::string *f_name);
|
||||||
|
JobStatusType get_job_status(std::string job);
|
||||||
|
|
||||||
|
bool prepare_statements(vector<pair<string, string>> statements);
|
||||||
|
bool prepare_statement(std::string name, std::string statement);
|
||||||
|
bool unprepare_statement(std::string name);
|
||||||
|
|
||||||
|
// Send request takes an arbitrary request method to the database and wraps error handling
|
||||||
|
// around it. It takes a function with an arbitrary set of arguments and the arguments to give
|
||||||
|
// that function and returns whatever the function returns.
|
||||||
|
// Careful with typing here! C++ doesn't quite do the strictest typing once you go deep like this!
|
||||||
|
// The function is defined here as it can be accessed from outside this library and is templated.
|
||||||
|
// This means it must be accessible to the compiler at all times. Failing this will cause a linker error.
|
||||||
|
template<typename... Args>
|
||||||
|
bool send_request(std::function<void(pqxx::work*, Args...)> *db_function, Args... args) {
|
||||||
|
|
||||||
|
retry_send:
|
||||||
|
|
||||||
|
if (!ensure_connected()) {
|
||||||
|
cerr << "Could contact database. Broken database connection." << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
pqxx::work txn(*c);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// we assume the lambda takes a pointer to a transaction object as first argument
|
||||||
|
// and whatever else was given to us as the rest
|
||||||
|
(*db_function)(&txn, args...);
|
||||||
|
|
||||||
|
// commit the task to the database
|
||||||
|
txn.commit();
|
||||||
|
} catch (const exception& e) {
|
||||||
|
|
||||||
|
// if something happened during the transaction, we roll it back
|
||||||
|
txn.abort();
|
||||||
|
|
||||||
|
cerr << "Could not complete database operation. Error in execution." << endl;
|
||||||
|
cerr << e.what() << endl;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (const pqxx::broken_connection& e) {
|
||||||
|
cerr << "Pipe broke during database operation... Retrying..." << endl;
|
||||||
|
cerr << e.what() << endl;
|
||||||
|
|
||||||
|
// using a goto here since it'll gracefully retry connection
|
||||||
|
goto retry_send;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
db_credentials_t db_credentials;
|
||||||
|
pqxx::connection *c;
|
||||||
|
std::function<void(pqxx::connection *c)> setup_function;
|
||||||
|
bool connected;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool upload_task(shared_ptr<Task> task);
|
||||||
|
|
||||||
|
const vector<pair<string, string>> uplink_statements = {
|
||||||
|
{"commit_task", "UPDATE tasks SET t_status = DONE, error = $2, sim_log = $3, sim_trace = $4 WHERE id = $1"}
|
||||||
|
};
|
||||||
|
|
||||||
|
const vector<pair<string, string>> downlink_statements = {
|
||||||
|
{"check_open_tasks", "SELECT id FROM tasks WHERE t_status=OPEN LIMIT 1"},
|
||||||
|
// TODO add inner join to grab pipeline depth
|
||||||
|
{"fetch_task", "SELECT id, job, t_status, t_type, is_reference, reference, max_plf, error, sim_log FROM tasks WHERE id = $1 LIMIT 1"}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
303
include/db_lib/db_types.hpp
Normal file
303
include/db_lib/db_types.hpp
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Fabian Posch
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DB_TYPES_HPP__
|
||||||
|
#define __DB_TYPES_HPP__
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <pqxx/pqxx>
|
||||||
|
|
||||||
|
namespace db {
|
||||||
|
|
||||||
|
// credentials for database access
|
||||||
|
struct db_credentials_t {
|
||||||
|
std::string server;
|
||||||
|
bool server_override;
|
||||||
|
int port;
|
||||||
|
bool port_override;
|
||||||
|
std::string uname;
|
||||||
|
bool uname_override;
|
||||||
|
std::string pwd;
|
||||||
|
bool pwd_override;
|
||||||
|
std::string dbase;
|
||||||
|
bool dbase_override;
|
||||||
|
int version;
|
||||||
|
};
|
||||||
|
|
||||||
|
// create UUID type to store database 128 UUID type
|
||||||
|
struct uuid_t {
|
||||||
|
uint64_t uuid_upper, uuid_lower;
|
||||||
|
|
||||||
|
uuid_t& operator=(uint64_t other) {
|
||||||
|
this->uuid_lower = other;
|
||||||
|
this->uuid_upper = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// override comparison operator to make our life easier
|
||||||
|
inline bool operator==(uuid_t const & lhs, uuid_t const & rhs) {
|
||||||
|
return lhs.uuid_upper == rhs.uuid_upper && lhs.uuid_lower == rhs.uuid_lower;
|
||||||
|
}
|
||||||
|
inline bool operator==(uuid_t const & lhs, int const & rhs) {
|
||||||
|
return rhs >= 0 && lhs.uuid_lower == (uint64_t)rhs;
|
||||||
|
}
|
||||||
|
inline bool operator==(int const & lhs, uuid_t const & rhs) {
|
||||||
|
return lhs >= 0 && (uint64_t)lhs == rhs.uuid_lower;
|
||||||
|
}
|
||||||
|
inline bool operator!=(uuid_t const & lhs, uuid_t const & rhs) {
|
||||||
|
return lhs.uuid_upper != rhs.uuid_upper || lhs.uuid_lower != rhs.uuid_lower;
|
||||||
|
}
|
||||||
|
inline bool operator!=(uuid_t const & lhs, int const & rhs) {
|
||||||
|
return rhs < 0 || lhs.uuid_lower != (uint64_t)rhs;
|
||||||
|
}
|
||||||
|
inline bool operator!=(int const & lhs, uuid_t const & rhs) {
|
||||||
|
return lhs < 0 || (uint64_t)lhs != rhs.uuid_lower;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// easier conversion to string
|
||||||
|
inline std::string to_string(uuid_t const &value) {
|
||||||
|
std::ostringstream uuid_s;
|
||||||
|
uuid_s << std::hex;
|
||||||
|
uuid_s << std::setfill('0') << std::setw(16) << value.uuid_upper;
|
||||||
|
uuid_s << std::setfill('0') << std::setw(16) << value.uuid_lower;
|
||||||
|
return uuid_s.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// stream operations
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, uuid_t& value) {
|
||||||
|
os << to_string(value);
|
||||||
|
return os;
|
||||||
|
};
|
||||||
|
|
||||||
|
// macro for registering enum classes for PQXX
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_enum_class {
|
||||||
|
static constexpr bool value = std::is_enum_v<T> && !std::is_convertible_v<T, int>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_unordered_map_string {
|
||||||
|
static constexpr bool value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_unordered_map_string<std::unordered_map<std::string, T>> {
|
||||||
|
static constexpr bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Map, typename Enum>
|
||||||
|
struct is_map_key_type_same_as_enum {
|
||||||
|
static constexpr bool value = std::is_same_v<typename Map::key_type, std::string> &&
|
||||||
|
std::is_same_v<typename Map::mapped_type, Enum>;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate type conversion for enum class macros in the libpqxx library
|
||||||
|
*
|
||||||
|
* Calling this macro will generate the code necessary for converting enum class types in yaml-cpp internally.
|
||||||
|
* For this you additionally need a std::unordered_map<std::string, Type)>, mapping string values to your
|
||||||
|
* custom enum class type.
|
||||||
|
*
|
||||||
|
* For more information see https://libpqxx.readthedocs.io/en/7.4.1/a01360.html
|
||||||
|
*
|
||||||
|
* @param T The type you want to generate the translation for
|
||||||
|
* @param lookup_table the unordered map, mapping string values of your type to the internal representation
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define DB_REGISTER_ENUM_CLASS(T, lookup_table, name) \
|
||||||
|
namespace pqxx { \
|
||||||
|
\
|
||||||
|
static_assert(db::is_enum_class<T>::value, "DB_REGISTER_ENUM_TYPE: 'T' must be an enum class"); \
|
||||||
|
static_assert(db::is_unordered_map_string<decltype(lookup_table)>::value, "DB_REGISTER_ENUM_TYPE: 'lookup_table' must be std::unordered_map<std::string, T>"); \
|
||||||
|
static_assert(db::is_map_key_type_same_as_enum<decltype(lookup_table), T>::value, "DB_REGISTER_ENUM_TYPE: 'lookup_table' content must be of type T"); \
|
||||||
|
\
|
||||||
|
\
|
||||||
|
template<> \
|
||||||
|
std::string const type_name<T>{name}; \
|
||||||
|
\
|
||||||
|
template<> \
|
||||||
|
struct nullness<T> : pqxx::no_null<T> {}; \
|
||||||
|
\
|
||||||
|
template<> \
|
||||||
|
struct string_traits<T> { \
|
||||||
|
\
|
||||||
|
static T from_string(std::string_view text) { \
|
||||||
|
\
|
||||||
|
/* turn the string_view into a string */ \
|
||||||
|
std::string str(text); \
|
||||||
|
\
|
||||||
|
/* make sure the enum value exists */ \
|
||||||
|
if (lookup_table.find(str) == lookup_table.end()) throw pqxx::conversion_error("Could not convert " + str + " to " + name); \
|
||||||
|
\
|
||||||
|
return lookup_table[str]; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static zview to_buf(char *begin, char *end, T const &value) { \
|
||||||
|
std::string str = ""; \
|
||||||
|
\
|
||||||
|
for (auto& it : lookup_table) { \
|
||||||
|
if (it.second == value) { \
|
||||||
|
str = it.first; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* make sure we actually have enough space for the enum */ \
|
||||||
|
if (std::distance(begin, end) < static_cast<signed long>(str.size() + 1)) { \
|
||||||
|
std::ostringstream str_str; \
|
||||||
|
str_str << "Buffer for "; \
|
||||||
|
str_str << name; \
|
||||||
|
str_str << " to small"; \
|
||||||
|
throw conversion_overrun(str_str.str()); \
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
const char* c_str = str.c_str(); \
|
||||||
|
\
|
||||||
|
std::memcpy(begin, c_str, sizeof(char) * str.length()); \
|
||||||
|
\
|
||||||
|
return zview(begin, str.length()); \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static char *into_buf(char *begin, char *end, T const &value) { \
|
||||||
|
std::string str = ""; \
|
||||||
|
\
|
||||||
|
for (auto& it : lookup_table) { \
|
||||||
|
if (it.second == value) { \
|
||||||
|
str = it.first; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* make sure we actually have enough space for the enum */ \
|
||||||
|
if (std::distance(begin, end) < static_cast<signed long>(str.size() + 1)) { \
|
||||||
|
std::ostringstream str_str; \
|
||||||
|
str_str << "Buffer for "; \
|
||||||
|
str_str << name; \
|
||||||
|
str_str << " to small"; \
|
||||||
|
throw conversion_overrun(str_str.str()); \
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
const char* c_str = str.c_str(); \
|
||||||
|
\
|
||||||
|
std::memcpy(begin, c_str, sizeof(char) * str.length()); \
|
||||||
|
\
|
||||||
|
return begin; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static std::size_t size_buffer(T const &value) noexcept { \
|
||||||
|
\
|
||||||
|
std::string str; \
|
||||||
|
str = ""; \
|
||||||
|
\
|
||||||
|
for (auto& it : lookup_table) { \
|
||||||
|
if (it.second == value) { \
|
||||||
|
str = it.first; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return str.size() + 1; \
|
||||||
|
}; \
|
||||||
|
}; \
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Conversion extension for uuid_t for the pqxx library
|
||||||
|
*
|
||||||
|
* For more information see https://libpqxx.readthedocs.io/en/7.4.1/a01360.html
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace pqxx {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::string const type_name<db::uuid_t>{"uuid_t"};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct nullness<db::uuid_t> : pqxx::no_null<db::uuid_t> {};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct string_traits<db::uuid_t> {
|
||||||
|
|
||||||
|
static db::uuid_t from_string(std::string_view text) {
|
||||||
|
|
||||||
|
if (text.size() != 36) {
|
||||||
|
throw pqxx::conversion_error("Invalid binary string size for uuid_t. Expected: 36; Actual: " + std::to_string(text.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn the string_view into a string and remove the '-'
|
||||||
|
std::string form(text);
|
||||||
|
form.erase(std::remove(form.begin(), form.end(), '-'), form.end());
|
||||||
|
|
||||||
|
// then parse into numbers
|
||||||
|
std::istringstream high_stream(form.substr(0, 16));
|
||||||
|
std::istringstream low_stream(form.substr(16, 16));
|
||||||
|
|
||||||
|
uint64_t low, high;
|
||||||
|
|
||||||
|
high_stream >> std::hex >> high;
|
||||||
|
low_stream >> std::hex >> low;
|
||||||
|
|
||||||
|
return {high, low};
|
||||||
|
};
|
||||||
|
|
||||||
|
static zview to_buf(char *begin, char *end, db::uuid_t const &value) {
|
||||||
|
std::string str = db::to_string(value);
|
||||||
|
|
||||||
|
// make sure we actually have enough space for the UUID
|
||||||
|
if (std::distance(begin, end) < static_cast<signed long>(str.size() + 1)) throw conversion_overrun("Buffer for UUID to small");
|
||||||
|
|
||||||
|
const char* c_str = str.c_str();
|
||||||
|
|
||||||
|
std::memcpy(begin, c_str, sizeof(char) * str.length());
|
||||||
|
|
||||||
|
return zview(begin, str.length());
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *into_buf(char *begin, char *end, db::uuid_t const &value) {
|
||||||
|
std::string str = db::to_string(value);
|
||||||
|
|
||||||
|
// make sure we actually have enough space for the UUID
|
||||||
|
if (std::distance(begin, end) < static_cast<signed long>(str.size() + 1)) throw conversion_overrun("Buffer for UUID to small");
|
||||||
|
|
||||||
|
const char* c_str = str.c_str();
|
||||||
|
|
||||||
|
std::memcpy(begin, c_str, sizeof(char) * str.length());
|
||||||
|
|
||||||
|
return begin;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr static std::size_t size_buffer([[maybe_unused]] db::uuid_t const &value) noexcept { return sizeof(char) * 33; };
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
296
include/db_lib/task.hpp
Normal file
296
include/db_lib/task.hpp
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Fabian Posch
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __TASK_H__
|
||||||
|
#define __TASK_H__
|
||||||
|
|
||||||
|
#include <pqxx/pqxx>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdint>
|
||||||
|
#include "db_types.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Representation of the current status of a job.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum class JobStatusType {NOT_STARTED, IN_PROGRESS, FINISHED, HALTED, UNKNOWN};
|
||||||
|
|
||||||
|
// string mapping for job status type enum
|
||||||
|
static std::unordered_map<JobStatusType, std::string> job_status_type_st {
|
||||||
|
{JobStatusType::NOT_STARTED, "not_started"},
|
||||||
|
{JobStatusType::IN_PROGRESS, "in_progress"},
|
||||||
|
{JobStatusType::FINISHED, "finished"},
|
||||||
|
{JobStatusType::HALTED, "halted"},
|
||||||
|
{JobStatusType::UNKNOWN, "unknown"}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::string to_string(JobStatusType const &value) {
|
||||||
|
return job_status_type_st[value];
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, JobStatusType& value) {
|
||||||
|
os << to_string(value);
|
||||||
|
return os;
|
||||||
|
};
|
||||||
|
|
||||||
|
JobStatusType convert_to_job_status(std::string status_string);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defines if a simulation task should be executed a single time or
|
||||||
|
* dependent on a central coverage model. The latter task type can also be
|
||||||
|
* executed by more than just a single node to hasten progress.
|
||||||
|
*/
|
||||||
|
enum class TaskTypeType {UNKNOWN, SINGLE, MULTI_COV};
|
||||||
|
|
||||||
|
// string mapping for task type enum
|
||||||
|
static std::unordered_map<TaskTypeType, std::string> task_type_type_st {
|
||||||
|
{TaskTypeType::UNKNOWN, "unknown"},
|
||||||
|
{TaskTypeType::SINGLE, "single"},
|
||||||
|
{TaskTypeType::MULTI_COV, "multi_cov"}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::string to_string(TaskTypeType const &value) {
|
||||||
|
return task_type_type_st[value];
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, TaskTypeType& value) {
|
||||||
|
os << to_string(value);
|
||||||
|
return os;
|
||||||
|
};
|
||||||
|
|
||||||
|
TaskTypeType convert_to_task_type(std::string type_string);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO check if this is complete
|
||||||
|
/**
|
||||||
|
* @brief If a task simulation was aborted or completed with an error,
|
||||||
|
* this type represents the types of error encountered.
|
||||||
|
*/
|
||||||
|
enum class TaskErrorType {UNKNOWN, NONE, SYNTAX, VALUE, CODE, METASTABLE, TIMING, DEADLOCK};
|
||||||
|
|
||||||
|
// string mapping for task error type enum
|
||||||
|
static std::unordered_map<TaskErrorType, std::string> task_error_type_st {
|
||||||
|
{TaskErrorType::UNKNOWN, "unknown"},
|
||||||
|
{TaskErrorType::NONE, "none"},
|
||||||
|
{TaskErrorType::SYNTAX, "syntax"},
|
||||||
|
{TaskErrorType::VALUE, "value"},
|
||||||
|
{TaskErrorType::CODE, "code"},
|
||||||
|
{TaskErrorType::METASTABLE, "metastable"},
|
||||||
|
{TaskErrorType::TIMING, "timing"},
|
||||||
|
{TaskErrorType::DEADLOCK, "deadlock"}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::string to_string(TaskErrorType const &value) {
|
||||||
|
return task_error_type_st[value];
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, TaskErrorType& value) {
|
||||||
|
os << to_string(value);
|
||||||
|
return os;
|
||||||
|
};
|
||||||
|
|
||||||
|
TaskErrorType convert_to_task_error(std::string error_string);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Representation of teh current status of a task.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum class TaskStatusType {UNKNOWN, OPEN, IN_PROGRESS, DONE};
|
||||||
|
|
||||||
|
// string mapping for task status enum
|
||||||
|
static std::unordered_map<TaskStatusType, std::string> task_status_type_st {
|
||||||
|
{TaskStatusType::UNKNOWN, "unknown"},
|
||||||
|
{TaskStatusType::OPEN, "open"},
|
||||||
|
{TaskStatusType::IN_PROGRESS, "in_progress"},
|
||||||
|
{TaskStatusType::DONE, "done"}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::string to_string(TaskStatusType const &value) {
|
||||||
|
return task_status_type_st[value];
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, TaskStatusType& value) {
|
||||||
|
os << to_string(value);
|
||||||
|
return os;
|
||||||
|
};
|
||||||
|
|
||||||
|
TaskStatusType convert_to_task_status(std::string status_string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Task class represents one simulation task and its settings.
|
||||||
|
*/
|
||||||
|
class Task {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Task( db::uuid_t task_uuid,
|
||||||
|
std::string job_id,
|
||||||
|
TaskStatusType status,
|
||||||
|
TaskTypeType type,
|
||||||
|
bool is_reference,
|
||||||
|
db::uuid_t reference_uuid,
|
||||||
|
float max_plf,
|
||||||
|
TaskErrorType error,
|
||||||
|
std::string sim_log
|
||||||
|
);
|
||||||
|
|
||||||
|
Task( db::uuid_t task_uuid,
|
||||||
|
std::string job_id,
|
||||||
|
TaskTypeType type,
|
||||||
|
bool is_reference,
|
||||||
|
db::uuid_t reference_uuid,
|
||||||
|
float max_plf
|
||||||
|
);
|
||||||
|
|
||||||
|
~Task();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the UUID of this task
|
||||||
|
*
|
||||||
|
* @return db::uuid_t Task UUID
|
||||||
|
*/
|
||||||
|
db::uuid_t get_uuid() { return task_uuid; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the ID of the job this task belongs to
|
||||||
|
*
|
||||||
|
* @return const char* Job ID
|
||||||
|
*/
|
||||||
|
std::string get_job_id() { return job_id; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get information whether this task is a one shot simulation or contributes
|
||||||
|
* to a central coverage model.
|
||||||
|
*
|
||||||
|
* @return TaskType
|
||||||
|
*/
|
||||||
|
TaskTypeType get_task_type() { return task_type; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Does this simulation task have a reference task to compare to?
|
||||||
|
*
|
||||||
|
* @return true It does
|
||||||
|
* @return false It does not
|
||||||
|
*/
|
||||||
|
bool is_reference_run() { return is_reference; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the reference object UUID
|
||||||
|
*
|
||||||
|
* @return The UUID of the reference simulation task
|
||||||
|
*/
|
||||||
|
db::uuid_t get_reference() { return reference_uuid; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the status of this task
|
||||||
|
*
|
||||||
|
* @return TaskStatusType The task status
|
||||||
|
*/
|
||||||
|
TaskStatusType get_status() { return status; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the status of the task
|
||||||
|
*
|
||||||
|
* @param new_status The new status this task should be set to
|
||||||
|
*/
|
||||||
|
void set_status(TaskStatusType new_status) { this->status = new_status; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the value of the maximum allowed pipeline load factor
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
float get_max_plf() { return max_plf; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the error with which this simulation task was completed
|
||||||
|
*
|
||||||
|
* @return TaskErrorType
|
||||||
|
*/
|
||||||
|
TaskErrorType get_error() { return error; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the error with which this task was completed
|
||||||
|
*
|
||||||
|
* @param error
|
||||||
|
*/
|
||||||
|
void set_error(TaskErrorType error) { this->error = error; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the simulation log of this task. Empty if not yet simulated.
|
||||||
|
*
|
||||||
|
* @return std::string The simulation log in JSON format
|
||||||
|
*/
|
||||||
|
std::string get_log() { return sim_log; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the simulation log
|
||||||
|
*
|
||||||
|
* @param log
|
||||||
|
*/
|
||||||
|
void set_log(std::string log) { this->sim_log = log; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the simulation trace of this task. Empty if not yet simulated.
|
||||||
|
*
|
||||||
|
* @return std::string The simulation log in TODO format
|
||||||
|
*/
|
||||||
|
std::string get_trace() { return trace; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the simulation trace
|
||||||
|
*
|
||||||
|
* @param trace
|
||||||
|
*/
|
||||||
|
void set_trace(std::string trace) { this->trace = trace; };
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
private:
|
||||||
|
|
||||||
|
// UUID of this task in the database
|
||||||
|
db::uuid_t task_uuid;
|
||||||
|
|
||||||
|
// ID of the job this task belongs to
|
||||||
|
std::string job_id;
|
||||||
|
|
||||||
|
// Is this task a single shot or does it depend on central coverage metrics?
|
||||||
|
TaskTypeType task_type;
|
||||||
|
|
||||||
|
// Does this task have a reference run which we should compare the trace to?
|
||||||
|
bool is_reference;
|
||||||
|
TaskStatusType status;
|
||||||
|
db::uuid_t reference_uuid;
|
||||||
|
|
||||||
|
// maximum pipeline load factor
|
||||||
|
float max_plf;
|
||||||
|
// error with which this task was completed
|
||||||
|
TaskErrorType error;
|
||||||
|
|
||||||
|
// simulation output
|
||||||
|
std::string sim_log;
|
||||||
|
std::string trace;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
58
include/util.h
Normal file
58
include/util.h
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Fabian Posch
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __UTIL_H__
|
||||||
|
#define __UTIL_H__
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// debugging util print functions
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DEBUG_PRINT(msg) std::cerr << "Info: " << msg << std::endl;
|
||||||
|
#else
|
||||||
|
#define DEBUG_PRINT(msg) do {} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ENUM_CLASS_OPS(T, lookup_table) \
|
||||||
|
\
|
||||||
|
inline std::string to_string(T const &value) { \
|
||||||
|
std::string str = "unknown"; \
|
||||||
|
\
|
||||||
|
for (auto& it : lookup_table) { \
|
||||||
|
if (it.second == value) { \
|
||||||
|
str = it.first; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return str; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, T const &rhs) { \
|
||||||
|
os << to_string(rhs); \
|
||||||
|
return os; \
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
24
src/CMakeLists.txt
Normal file
24
src/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
# Grab necessary libraries from ACT_HOME
|
||||||
|
#include_directories($ENV{ACT_HOME}/include)
|
||||||
|
include_directories(../include)
|
||||||
|
#include_directories(../include/commands)
|
||||||
|
#include_directories(../include/db_lib)
|
||||||
|
|
||||||
|
add_subdirectory(db_lib)
|
||||||
|
#add_subdirectory(pipeline_lib)
|
||||||
|
#add_subdirectory(pipeline_modules)
|
||||||
|
#add_subdirectory(testcase_generators)
|
||||||
|
#add_subdirectory(commands)
|
||||||
|
|
||||||
|
file(
|
||||||
|
GLOB proj_SRC
|
||||||
|
"*.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Add the main executable
|
||||||
|
add_executable(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
${proj_SRC}
|
||||||
|
)
|
||||||
14
src/db_lib/CMakeLists.txt
Normal file
14
src/db_lib/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
include_directories(../../include)
|
||||||
|
include_directories(../../include/db_lib)
|
||||||
|
|
||||||
|
file(
|
||||||
|
GLOB db_lib_SRC
|
||||||
|
"*.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
act-deploy-db-lib
|
||||||
|
STATIC
|
||||||
|
${db_lib_SRC}
|
||||||
|
)
|
||||||
215
src/db_lib/db_client.cpp
Normal file
215
src/db_lib/db_client.cpp
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Fabian Posch
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "util.h"
|
||||||
|
#include "task.hpp"
|
||||||
|
#include "db_client.hpp"
|
||||||
|
|
||||||
|
namespace db {
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
string hostname;
|
||||||
|
|
||||||
|
bool connected = false;
|
||||||
|
|
||||||
|
|
||||||
|
Connection::Connection(
|
||||||
|
db_credentials_t credentials,
|
||||||
|
std::function<void(pqxx::connection *c)> setup
|
||||||
|
) : setup_function(move(setup)) {
|
||||||
|
this->db_credentials = credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection::Connection(db_credentials_t credentials) {
|
||||||
|
this->db_credentials = credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection::~Connection() {
|
||||||
|
if (c != nullptr && c->is_open()) c->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Connection::connect() {
|
||||||
|
bool connection_established = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_CON_RETRIES; i++) {
|
||||||
|
try {
|
||||||
|
// create the connection object
|
||||||
|
this->c = new pqxx::connection(
|
||||||
|
"host=" + db_credentials.server + " "
|
||||||
|
"port=" + std::to_string(db_credentials.port) + " "
|
||||||
|
"user=" + db_credentials.uname + " "
|
||||||
|
"password=" + db_credentials.pwd + " "
|
||||||
|
"dbname=" + db_credentials.dbase
|
||||||
|
);
|
||||||
|
|
||||||
|
// make sure the database actually has the version we need
|
||||||
|
pqxx::work txn(*(this->c));
|
||||||
|
|
||||||
|
auto db_info = txn.exec1("SELECT * FROM info;");
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
if (db_info["db_version"].as<int>() != this->db_credentials.version) {
|
||||||
|
this->disconnect();
|
||||||
|
cerr << "Error: Unsupported database version! Command expects ";
|
||||||
|
cerr << this->db_credentials.version;
|
||||||
|
cerr << ", server provides " << db_info["db_version"].as<int>() << "!" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->setup_function != nullptr) {
|
||||||
|
// execute the initialization function
|
||||||
|
this->setup_function(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_established = true;
|
||||||
|
|
||||||
|
} catch (const exception &e) {
|
||||||
|
cerr << "Error: Could not connect to database:" << endl;
|
||||||
|
cerr << e.what() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection_established;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Connection::ensure_connected() {
|
||||||
|
if (c == nullptr || !c->is_open()) {
|
||||||
|
c->close();
|
||||||
|
return connect();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::disconnect() {
|
||||||
|
if (c != nullptr && c->is_open()) c->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Connection::prepare_statements(vector<pair<string, string>> statements) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (auto statement : statements) {
|
||||||
|
this->c->prepare(statement.first, statement.second);
|
||||||
|
}
|
||||||
|
} catch (const exception &e) {
|
||||||
|
cerr << "Error: Could not prepare statements!" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Connection::prepare_statement(std::string name, std::string statement) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
this->c->prepare(name, statement);
|
||||||
|
} catch (const exception &e) {
|
||||||
|
cerr << "Error: Could not prepare statements!" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Connection::unprepare_statement(std::string name) {
|
||||||
|
|
||||||
|
auto unprepare_statement_lambda = [] (pqxx::work* txn, std::string statement) {
|
||||||
|
txn->exec0("DEALLOCATE " + statement + ";");
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<void(pqxx::work*, std::string)> unprepare_statement_func = unprepare_statement_lambda;
|
||||||
|
|
||||||
|
return this->send_request(&unprepare_statement_func, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Connection::find_job(std::string p_name, std::string *f_name) {
|
||||||
|
auto check_job_ids_lambda = [](pqxx::work *txn, int *ret, std::string p_name, std::string *f_name) {
|
||||||
|
pqxx::result res {txn->exec("SELECT id FROM jobs;")};
|
||||||
|
|
||||||
|
*ret = 0;
|
||||||
|
|
||||||
|
for (auto row : res) {
|
||||||
|
// check if the ID starts with the partial name we've been given
|
||||||
|
if (row["id"].as<std::string>().rfind(p_name, 0) == 0) {
|
||||||
|
// make sure we haven't found it before
|
||||||
|
if (*ret == 0) {
|
||||||
|
*ret = 1;
|
||||||
|
*f_name = row["id"].as<std::string>();
|
||||||
|
} else {
|
||||||
|
// guess the partial name is ambiguous
|
||||||
|
*ret = -1;
|
||||||
|
// we've already seen two, we don't need more
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<void(pqxx::work*, int*, std::string, std::string*)> check_job_ids_func = check_job_ids_lambda;
|
||||||
|
|
||||||
|
DEBUG_PRINT("Sending request...");
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
if (!this->send_request(&check_job_ids_func, &ret, p_name, f_name)) {
|
||||||
|
std::cerr << "Error: Could not fetch job IDs from database!" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_PRINT("Request complete.");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JobStatusType Connection::get_job_status(std::string job) {
|
||||||
|
auto get_jstatus_lambda = [](pqxx::work *txn, std::string job, JobStatusType *status) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
pqxx::row res {txn->exec1("SELECT job_status FROM jobs WHERE id='" + job + "';")};
|
||||||
|
*status = convert_to_job_status(res["job_status"].as<std::string>());
|
||||||
|
} catch (pqxx::unexpected_rows& e) {
|
||||||
|
std::cerr << "Error: Fetching job returned nothing or too many rows!" << std::endl;
|
||||||
|
*status = JobStatusType::UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<void(pqxx::work*, std::string, JobStatusType*)> get_jstatus_func = get_jstatus_lambda;
|
||||||
|
|
||||||
|
DEBUG_PRINT("Sending request...");
|
||||||
|
|
||||||
|
JobStatusType status;
|
||||||
|
if (!this->send_request(&get_jstatus_func, job, &status)) {
|
||||||
|
std::cerr << "Error: Could not fetch job status from database!" << std::endl;
|
||||||
|
return JobStatusType::UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_PRINT("Request complete.");
|
||||||
|
|
||||||
|
return status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
155
src/db_lib/task.cpp
Normal file
155
src/db_lib/task.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Fabian Posch
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <pqxx/pqxx>
|
||||||
|
#include "task.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
Task::Task (db::uuid_t task_uuid,
|
||||||
|
std::string job_id,
|
||||||
|
TaskStatusType status,
|
||||||
|
TaskTypeType type,
|
||||||
|
bool is_reference,
|
||||||
|
db::uuid_t reference_uuid,
|
||||||
|
float max_plf,
|
||||||
|
TaskErrorType error,
|
||||||
|
std::string sim_log
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this->task_uuid = task_uuid;
|
||||||
|
this->job_id = job_id;
|
||||||
|
this->status = status;
|
||||||
|
this->task_type = type;
|
||||||
|
this->is_reference = is_reference;
|
||||||
|
this->reference_uuid = reference_uuid;
|
||||||
|
this->max_plf = max_plf;
|
||||||
|
this->error = error;
|
||||||
|
this->sim_log = sim_log;
|
||||||
|
}
|
||||||
|
|
||||||
|
Task::Task (db::uuid_t task_uuid,
|
||||||
|
std::string job_id,
|
||||||
|
TaskTypeType type,
|
||||||
|
bool is_reference,
|
||||||
|
db::uuid_t reference_uuid,
|
||||||
|
float max_plf
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this->task_uuid = task_uuid;
|
||||||
|
this->job_id = job_id;
|
||||||
|
this->task_type = type;
|
||||||
|
this->is_reference = is_reference;
|
||||||
|
this->reference_uuid = reference_uuid;
|
||||||
|
this->max_plf = max_plf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert from pqxx response string to JobStatusType
|
||||||
|
*
|
||||||
|
* @param type_string Type returned by pqxx in string form.
|
||||||
|
* @return JobStatusType
|
||||||
|
*/
|
||||||
|
JobStatusType convert_to_job_status(std::string status_string) {
|
||||||
|
JobStatusType status = JobStatusType::UNKNOWN;
|
||||||
|
|
||||||
|
for (auto pair : job_status_type_st) {
|
||||||
|
if (pair.second == status_string) {
|
||||||
|
status = pair.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == JobStatusType::UNKNOWN) {
|
||||||
|
std::cerr << "Warning: Job status type unknown or could not be parsed. Given status was " << status_string << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert from pqxx response string to TaskTypeType
|
||||||
|
*
|
||||||
|
* @param type_string Type returned by pqxx in string form.
|
||||||
|
* @return TaskTypeType
|
||||||
|
*/
|
||||||
|
TaskTypeType convert_to_task_type(std::string type_string) {
|
||||||
|
if (type_string == "SINGLE") {
|
||||||
|
return TaskTypeType::SINGLE;
|
||||||
|
} else if (type_string == "MULTI_COV") {
|
||||||
|
return TaskTypeType::MULTI_COV;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Error: Could not parse task type \"" << type_string << "\"" << std::endl;
|
||||||
|
return TaskTypeType::UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert from pqxx response string to TaskErrorType
|
||||||
|
*
|
||||||
|
* @param error_string Error returned by pqxx in string form.
|
||||||
|
* @return TaskErrorType
|
||||||
|
*/
|
||||||
|
TaskErrorType convert_to_task_error(std::string error_string) {
|
||||||
|
if (error_string == "NONE") {
|
||||||
|
return TaskErrorType::NONE;
|
||||||
|
} else if (error_string == "SYNTAX") {
|
||||||
|
return TaskErrorType::SYNTAX;
|
||||||
|
} else if (error_string == "VALUE") {
|
||||||
|
return TaskErrorType::VALUE;
|
||||||
|
} else if (error_string == "CODE") {
|
||||||
|
return TaskErrorType::CODE;
|
||||||
|
} else if (error_string == "METASTABLE") {
|
||||||
|
return TaskErrorType::METASTABLE;
|
||||||
|
} else if (error_string == "TIMING") {
|
||||||
|
return TaskErrorType::TIMING;
|
||||||
|
} else if (error_string == "DEADLOCK") {
|
||||||
|
return TaskErrorType::DEADLOCK;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Error: Could not parse task error \"" << error_string << "\"" << std::endl;
|
||||||
|
return TaskErrorType::UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert from pqxx response string to TaskStatusType
|
||||||
|
*
|
||||||
|
* @param status_string Status returned by pqxx in string form.
|
||||||
|
* @return TaskStatusType
|
||||||
|
*/
|
||||||
|
TaskStatusType convert_to_task_status(std::string status_string) {
|
||||||
|
if (status_string == "OPEN") {
|
||||||
|
return TaskStatusType::OPEN;
|
||||||
|
} else if (status_string == "IN_PROGRESS") {
|
||||||
|
return TaskStatusType::IN_PROGRESS;
|
||||||
|
} else if (status_string == "DONE") {
|
||||||
|
return TaskStatusType::DONE;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Error: Could not parse task status \"" << status_string << "\"" << std::endl;
|
||||||
|
return TaskStatusType::UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in a new issue