localPackages.hpcstat: add lock only when connect to db

This commit is contained in:
2024-07-03 16:03:24 +08:00
parent a519d7426f
commit 0e4f1d06a9
7 changed files with 50 additions and 37 deletions

View File

@@ -147,7 +147,7 @@
buildInputs = [ pkgs.clang-tools_18 ];
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
};
hpcstat = pkgs.mkShell
hpcstat = pkgs.mkShell.override { stdenv = pkgs.gcc14Stdenv; }
{
inputsFrom = [ (inputs.self.packages.x86_64-linux.hpcstat.override { version = null; }) ];
packages = [ pkgs.clang-tools_18 ];

View File

@@ -69,7 +69,8 @@ inputs: rec
{ src = inputs.topInputs.kylin-virtual-keyboard; };
biu = inputs.pkgs.callPackage ./biu { inherit nameof zpp-bits; };
zxorm = inputs.pkgs.callPackage ./zxorm { src = inputs.topInputs.zxorm; };
hpcstat = inputs.pkgs.callPackage ./hpcstat { inherit nameof sqlite-orm zpp-bits date biu openxlsx; };
hpcstat = inputs.pkgs.callPackage ./hpcstat
{ inherit nameof sqlite-orm zpp-bits date biu openxlsx; stdenv = inputs.pkgs.gcc14Stdenv; };
openxlsx = inputs.pkgs.callPackage ./openxlsx { src = inputs.topInputs.openxlsx; };
sqlite-orm = inputs.pkgs.callPackage ./sqlite-orm { src = inputs.topInputs.sqlite-orm; };
mkPnpmPackage = inputs.pkgs.callPackage ./mkPnpmPackage.nix {};

View File

@@ -1,3 +1,3 @@
CompileFlags:
Add: [ -Wall, -Wextra, -std=c++23 ]
Add: [ -Wall, -Wextra, -std=c++26 ]
Compiler: g++

View File

@@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.14)
# cmake_minimum_required(VERSION 3.30)
cmake_minimum_required(VERSION 3.29)
project(hpcstat VERSION 0.0.0 LANGUAGES CXX)
enable_testing()
include(GNUInstallDirs)
@@ -25,7 +26,8 @@ find_package(OpenXLSX REQUIRED)
add_executable(hpcstat src/main.cpp src/env.cpp src/keys.cpp src/ssh.cpp src/sql.cpp src/lfs.cpp src/common.cpp
src/push.cpp src/disk.cpp)
target_compile_features(hpcstat PRIVATE cxx_std_23)
# target_compile_features(hpcstat PRIVATE cxx_std_26)
target_compile_options(hpcstat PRIVATE "-std=c++26")
target_include_directories(hpcstat PRIVATE ${PROJECT_SOURCE_DIR}/include ${ZPP_BITS_INCLUDE_DIR})
target_link_libraries(hpcstat PRIVATE Boost::headers Boost::filesystem sqlite_orm::sqlite_orm
nlohmann_json::nlohmann_json range-v3::range-v3 date::date date::date-tz httplib::httplib

View File

@@ -15,7 +15,6 @@
# include <date/date.h>
# include <date/tz.h>
# include <boost/interprocess/sync/file_lock.hpp>
# include <zpp_bits.h>
# include <biu.hpp>
namespace hpcstat

View File

@@ -7,7 +7,6 @@
# include <hpcstat/disk.hpp>
# include <range/v3/view.hpp>
# include <boost/exception/diagnostic_information.hpp>
# include <boost/filesystem.hpp>
# include <termcolor/termcolor.hpp>
int main(int argc, const char** argv)
@@ -16,10 +15,6 @@ int main(int argc, const char** argv)
using namespace std::literals;
try
{
auto lockfile = (boost::filesystem::temp_directory_path() / "hpcstat.lock").string();
std::ofstream{lockfile};
boost::interprocess::file_lock lock(lockfile.c_str());
std::vector<std::string> args(argv, argv + argc);
if (args.size() == 1)
@@ -27,11 +22,7 @@ int main(int argc, const char** argv)
std::cout << "Usage: hpcstat initdb|login|logout|submitjob|finishjob|verify|export|version|diskstat\n";
return 1;
}
else if (args[1] == "initdb")
{
lock.lock();
if (!sql::initdb()) { std::cerr << "Failed to initialize database\n"; return 1; }
}
else if (args[1] == "initdb") { if (!sql::initdb()) { std::cerr << "Failed to initialize database\n"; return 1; } }
else if (args[1] == "login")
{
if (env::interactive()) std::cout << "Communicating with the agent..." << std::flush;
@@ -50,7 +41,6 @@ int main(int argc, const char** argv)
auto signature = ssh::sign(biu::serialize<char>(data), *fp);
if (!signature) return 1;
data.Signature = *signature;
lock.lock();
sql::writedb(data);
if (env::interactive())
{
@@ -88,7 +78,7 @@ int main(int argc, const char** argv)
{
if (auto session_id = env::env("XDG_SESSION_ID", true); !session_id)
return 1;
else { lock.lock(); sql::writedb(sql::LogoutData{ .Time = now(), .SessionId = *session_id }); }
else sql::writedb(sql::LogoutData{ .Time = now(), .SessionId = *session_id });
}
else if (args[1] == "submitjob")
{
@@ -111,14 +101,12 @@ int main(int argc, const char** argv)
auto signature = ssh::sign(biu::serialize<char>(data), *fp);
if (!signature) return 1;
data.Signature = *signature;
lock.lock();
sql::writedb(data);
std::cout << "Job <{}> was submitted to <{}> by <{}>.\n"_f(bsub->first, bsub->second, Keys[*fp].Username);
}
}
else if (args[1] == "finishjob")
{
lock.lock();
if (auto fp = ssh::fingerprint(); !fp) return 1;
else if (auto session = env::env("XDG_SESSION_ID", true); !session)
return 1;
@@ -166,12 +154,10 @@ int main(int argc, const char** argv)
auto begin = sys_seconds(sys_days(month(month_n) / 1 / year_n)).time_since_epoch().count();
auto end = sys_seconds(sys_days(month(month_n) / 1 / year_n + months(1)))
.time_since_epoch().count();
lock.lock();
if (!sql::export_data(begin, end, "{}{}.xlsx"_f(year_n, month_n))) return 1;
}
else if (args[1] == "push")
{
lock.lock();
if (auto jobs = sql::check_job_status(); !jobs) return 1;
else if (!push::push(*jobs)) return 1;
}

View File

@@ -8,14 +8,16 @@
# define SQLITE_ORM_OPTIONAL_SUPPORTED
# include <sqlite_orm/sqlite_orm.h>
# include <OpenXLSX.hpp>
# include <boost/filesystem.hpp>
namespace hpcstat::sql
{
auto connect(std::optional<std::string> dbfile = std::nullopt)
auto connect(std::optional<std::string> dbfile = std::nullopt, bool need_lock = true)
{
auto conn = [&]() { return std::make_optional(sqlite_orm::make_storage
// a function to actually connecto to db
auto conn = [](std::string dbfile) { return std::make_optional(sqlite_orm::make_storage
(
*dbfile,
dbfile,
sqlite_orm::make_table
(
"login",
@@ -70,31 +72,52 @@ namespace hpcstat::sql
sqlite_orm::make_column("status", &CheckJobData::Status)
)
));};
// a class to take care of lock
struct conn_with_lock
{
// lock should be declared before conn, so that it will be destructed after conn
boost::interprocess::file_lock lock;
decltype(conn(std::declval<std::string>())) connection;
};
// set default db path
if (!dbfile)
{
if (auto datadir = env::env("HPCSTAT_DATADIR", true); !datadir)
return decltype(conn())();
return conn_with_lock{};
else dbfile = std::filesystem::path(*datadir) / "hpcstat.db";
}
auto result = conn();
if (!result) std::cerr << "Failed to connect to database.\n";
else result->busy_timeout(10000);
return result;
// set file lock
auto lockfile = (boost::filesystem::temp_directory_path() / "hpcstat.lock").string();
std::ofstream{lockfile}; // create file
boost::interprocess::file_lock lock(lockfile.c_str());
if (need_lock) lock.lock();
// try to connect
if (auto result = conn(*dbfile); !result)
{ std::cerr << "Failed to connect to database.\n"; return conn_with_lock{}; }
else
{
result->busy_timeout(10000);
return conn_with_lock{std::move(lock), std::move(result)};
}
}
bool initdb()
{
if (auto conn = connect(); !conn) return false;
if (auto [lock, conn] = connect(); !conn) return false;
else { conn->sync_schema(); return true; }
}
bool writedb(auto value)
{ if (auto conn = connect(); !conn) return false; else { conn->insert(value); return true; } }
{ if (auto [lock, conn] = connect(); !conn) return false; else { conn->insert(value); return true; } }
template bool writedb(LoginData);
template bool writedb(LogoutData);
template bool writedb(SubmitJobData);
template bool writedb(FinishJobData);
std::optional<std::set<unsigned>> finishjob_remove_existed(std::map<unsigned, std::string> jobid_submit_time)
{
if (auto conn = connect(); !conn) return std::nullopt;
if (auto [lock, conn] = connect(); !conn) return std::nullopt;
else
{
auto all_job = jobid_submit_time | ranges::views::keys | ranges::to<std::vector<unsigned>>;
@@ -110,7 +133,8 @@ namespace hpcstat::sql
std::optional<std::vector<std::tuple<std::string, std::string, std::string>>>
verify(std::string old_db, std::string new_db)
{
auto old_conn = connect(old_db), new_conn = connect(new_db);
auto [_, old_conn] = connect(old_db);
auto [_, new_conn] = connect(new_db);
if (!old_conn || !new_conn) { std::cerr << "Failed to connect to database.\n"; return std::nullopt; }
else
{
@@ -153,7 +177,8 @@ namespace hpcstat::sql
}
}
// search corresponding job in submit table
std::optional<SubmitJobData> search_job_in_submit(auto connection, unsigned job_id, std::string submit_time)
std::optional<SubmitJobData> search_job_in_submit
(auto connection, unsigned job_id, std::string submit_time)
{
std::optional<SubmitJobData> result;
long submit_date = [&]
@@ -185,7 +210,7 @@ namespace hpcstat::sql
}
bool export_data(long start_time, long end_time, std::string filename)
{
if (auto conn = connect(); !conn) return false;
if (auto [lock, conn] = connect(); !conn) return false;
else
{
// 对于一个账户的总计
@@ -312,7 +337,7 @@ namespace hpcstat::sql
std::optional<std::map<unsigned, std::tuple<std::string, std::string, std::string, std::optional<std::string>>>>
check_job_status()
{
if (auto conn = connect(); !conn) return std::nullopt;
if (auto [lock, conn] = connect(); !conn) return std::nullopt;
else if (auto jobs_current = lfs::bjobs_list(); !jobs_current) return std::nullopt;
else
{