move db interface to external library

This commit is contained in:
Fabian Posch 2024-01-10 18:49:52 -05:00
parent dc33b6b0d9
commit 3b645a953f
22 changed files with 80 additions and 1164 deletions

View file

@ -57,6 +57,10 @@ include_directories(./)
#add_library(ActCommon SHARED IMPORTED)
#set_target_properties(ActCommon PROPERTIES IMPORTED_LOCATION $ENV{ACT_HOME}/lib/libvlsilib.a)
# Include the cluster librar
add_library(act-cluster-lib SHARED IMPORTED)
set_target_properties(act-cluster-lib PROPERTIES IMPORTED_LOCATION $ENV{ACT_HOME}/lib/libact_cluster.so)
# ATTENTION
# The main executable is defined in the CMakeLists.txt in the ./src folder.
@ -75,7 +79,7 @@ add_subdirectory(src)
# Link the needed libraries into it
target_link_libraries(
${PROJECT_NAME}
actsim-agent-db-lib
act-cluster-lib
actsim-agent-lib
)

View file

@ -26,7 +26,7 @@
#ifndef __ACTSIM_AGENT__
#define __ACTSIM_AGENT__
#include <db_types.hpp>
#include <cluster/db_types.hpp>
#define DATABASE_VERSION 2

View file

@ -27,8 +27,8 @@
#define __DOWNLOADER_H__
#include <thread>
#include <db_types.hpp>
#include <db_client.hpp>
#include <cluster/db_types.hpp>
#include <cluster/db_client.hpp>
#include "task_interface.hpp"
class Downloader {

View file

@ -31,8 +31,8 @@
#include <thread>
#include <vector>
#include <atomic>
#include <db_types.hpp>
#include <db_client.hpp>
#include <cluster/db_types.hpp>
#include <cluster/db_client.hpp>
#include "task_interface.hpp"
#include "worker.hpp"

View file

@ -31,7 +31,7 @@
#include <atomic>
#include <condition_variable>
#include <mutex>
#include "task.hpp"
#include <cluster/task.hpp>
class TaskInterface {
@ -54,6 +54,10 @@ class TaskInterface {
std::unique_ptr<Task> pop_finished(bool& empty);
size_t get_buffer_space();
bool search_and_increment(db::uuid_t id, std::string& design);
void decrement(db::uuid_t id);
void store(db::uuid_t, std::string& design);
bool running() { return this->running_.load(std::memory_order_relaxed); };
bool is_stop_immediate() { return !this->immediate_stop.load(std::memory_order_relaxed); };
void stop() { this->running_.store(false, std::memory_order_relaxed); };

View file

@ -26,8 +26,8 @@
#ifndef __UPLOADER_H__
#define __UPLOADER_H__
#include <db_types.hpp>
#include <db_client.hpp>
#include <cluster/db_types.hpp>
#include <cluster/db_client.hpp>
#include <thread>
#include "task_interface.hpp"

View file

@ -28,7 +28,7 @@
#include <thread>
#include <atomic>
#include <db_types.hpp>
#include <cluster/db_types.hpp>
#include "task_interface.hpp"
class Worker {

View file

@ -27,7 +27,7 @@
#include <map>
#include <list>
#include "db_client.hpp"
#include <cluster/db_client.hpp>
#define POSTGRES_DEFAULT_PORT 5432

View file

@ -1,142 +0,0 @@
/*************************************************************************
*
* 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);
JobStatusType get_task_status(db::uuid_t);
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;
};
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

View file

@ -1,314 +0,0 @@
/*************************************************************************
*
* 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 = false;
int port = 0;
bool port_override = false;
std::string uname = "";
bool uname_override = false;
std::string pwd = "";
bool pwd_override = false;
std::string dbase = "";
bool dbase_override = false;
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>;
};
};
// hash operator to be able use uuid_t as a hashmap key
template<>
struct std::hash<db::uuid_t> {
std::size_t operator()(const db::uuid_t& k) const {
using std::size_t;
using std::hash;
return hash<size_t>()(hash<uint64_t>()(k.uuid_upper) ^ hash<uint64_t>()(k.uuid_lower));
}
};
/**
* @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

View file

@ -1,294 +0,0 @@
/*************************************************************************
*
* 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
);
/**
* @brief Get the UUID of this task
*
* @return db::uuid_t Task UUID
*/
const db::uuid_t& uuid = task_uuid;
/**
* @brief Get the ID of the job this task belongs to
*
* @return const char* Job ID
*/
const std::string& job_id = job_id_;
/**
* @brief Get information whether this task is a one shot simulation or contributes
* to a central coverage model.
*
* @return TaskType
*/
const TaskTypeType& task_type = task_type_;
/**
* @brief Does this simulation task have a reference task to compare to?
*
* @return true It does
* @return false It does not
*/
const bool& is_reference_run = is_reference_;
/**
* @brief Get the reference object UUID
*
* @return The UUID of the reference simulation task
*/
const db::uuid_t& reference_uuid = reference_uuid_;
/**
* @brief Get the status of this task
*
* @return TaskStatusType The task status
*/
const TaskStatusType& status = 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
*/
const float& max_plf = max_plf_;
/**
* @brief Get the error with which this simulation task was completed
*
* @return TaskErrorType
*/
const TaskErrorType& error = 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
*/
const std::string& sim_log = 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
*/
const std::string& trace = 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

View file

@ -1,11 +1,9 @@
# Grab necessary libraries from ACT_HOME
#include_directories($ENV{ACT_HOME}/include)
include_directories($ENV{ACT_HOME}/include)
include_directories(../include)
include_directories(../include/db_lib)
include_directories(../include/actsim_agent)
add_subdirectory(db_lib)
add_subdirectory(actsim_agent)
file(

View file

@ -1,6 +1,7 @@
include_directories(../../include)
include_directories(../../include/db_lib)
include_directories(../../include/actsim_agent)
include_directories($ENV{ACT_HOME}/include)
file(
GLOB actsim_agent_SRC
@ -15,6 +16,6 @@ add_library(
target_link_libraries(
actsim-agent-lib
actsim-agent-db-lib
act-cluster-lib
-lpqxx -lpq -latomic
)

View file

@ -27,8 +27,8 @@
#include <thread>
#include <csignal>
#include <atomic>
#include <db_types.hpp>
#include <db_client.hpp>
#include <cluster/db_types.hpp>
#include <cluster/db_client.hpp>
#include "task_interface.hpp"
#include "worker.hpp"
#include "uploader.hpp"

View file

@ -73,10 +73,10 @@ bool Downloader::fetch_tasks(size_t n) {
id = 1;
auto job_id = "deadbeef";
for (size_t i = 0; i < n; ++i) {
auto task = std::make_unique<Task>(id, job_id, TaskTypeType::SINGLE, false, db::uuid_t(), 2);
this->interface.push_fresh(std::move(task));
}
//for (size_t i = 0; i < n; ++i) {
// auto task = std::make_unique<Task>(id, job_id, TaskTypeType::SINGLE, false, db::uuid_t(), 2);
// this->interface.push_fresh(std::move(task));
//}
return true;
}

View file

@ -23,9 +23,9 @@
**************************************************************************
*/
#include <db_types.hpp>
#include <db_client.hpp>
#include <task.hpp>
#include <cluster/db_types.hpp>
#include <cluster/db_client.hpp>
#include <cluster/task.hpp>
#include <chrono>
#include "util.h"
#include "monitor.hpp"

View file

@ -117,6 +117,54 @@ std::unique_ptr<Task> TaskInterface::pop_finished(bool& empty) {
return task;
}
bool TaskInterface::search_and_increment(db::uuid_t id, std::string& design) {
std::lock_guard<std::mutex> lock (this->designs_mutex);
// make sure the requested design is in the list of available designs
if (this->designs.find(id) == this->designs.end()) return false;
std::pair<size_t, std::string>& design_entry = designs[id];
// if so, increment its reference counters
++design_entry.first;
// set the design parameter to the actual design information
design = design_entry.second;
return true;
}
void TaskInterface::decrement(db::uuid_t id) {
std::lock_guard<std::mutex> lock (this->designs_mutex);
// make sure the requested design is in the list of available designs
if (this->designs.find(id) == this->designs.end()) return;
std::pair<size_t, std::string>& design_entry = designs[id];
// if so, decrement its reference counters
--design_entry.first;
// if the reference counter hit 0, erase the design entry from the list
// of available designs
if (design_entry.first == 0) {
this->designs.erase(id);
}
}
void TaskInterface::store(db::uuid_t id, std::string& design) {
std::lock_guard<std::mutex> lock (this->designs_mutex);
// make sure the design isn't already in the list of design entries
// if it is, just increment its reference counter
if (this->designs.find(id) != this->designs.end()) {
++(this->designs[id]).first;
return;
}
// otherwise, create a new entry for this design
this->designs[id] = {1, design};
}
size_t TaskInterface::get_buffer_space() {
std::lock_guard<std::mutex> lock(this->fresh_queue_mutex);
return this->buffer_size - this->fresh_queue.size();

View file

@ -23,7 +23,6 @@
#include <iostream>
#include <sstream>
#include "db_client.hpp"
#include "util.h"
#include "cli_util.hpp"

View file

@ -1,14 +0,0 @@
include_directories(../../include)
include_directories(../../include/db_lib)
file(
GLOB db_lib_SRC
"*.cpp"
)
add_library(
actsim-agent-db-lib
STATIC
${db_lib_SRC}
)

View file

@ -1,219 +0,0 @@
/*************************************************************************
*
* 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 "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;
}
JobStatusType Connection::get_task_status(db::uuid_t) {
std::cout << "JOB STATUS called, implement me pls" << std::endl;
return JobStatusType::IN_PROGRESS;
}
}

View file

@ -1,155 +0,0 @@
/*************************************************************************
*
* 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;
}
}

View file

@ -26,7 +26,7 @@
#include <getopt.h>
#include <thread>
#include <actsim_agent.hpp>
#include <db_types.hpp>
#include <cluster/db_types.hpp>
#include "cli_util.hpp"
#include "util.h"
#include "main.hpp"