From 4d1aea03c9c36e9d338ad4add6af4aca0a56821f Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Thu, 15 Aug 2024 10:55:43 +0200 Subject: [PATCH] mxqkill: Add function cancel_group Refactor group cancellation and move the code from main() into functions analogous to the jobs cancellation functions. Add function cancel_group and its helpers. We have omitted some constraints from the old code: The group to be cancelled is no longer required to have groups_status OK and is no longer required to have pending or running jobs. So it is now accepted to cancel an inactive group and it is not an error to cancel a group multiple times. The old code will be removed in the next commit to get cleaner diffs. --- mxqkill.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/mxqkill.c b/mxqkill.c index 05890a3..1dc48d5 100644 --- a/mxqkill.c +++ b/mxqkill.c @@ -207,6 +207,86 @@ static void cancel_job(struct mx_mysql *mysql, uint64_t job_id, uint64_t user_ui set_job_cancelled(mysql, job_id); } +static void verify_group_owner(struct mx_mysql *mysql, uint64_t group_id, uint64_t user_uid) { + struct mx_mysql_stmt *stmt = mx_mysql_statement_prepare(mysql, + "SELECT user_uid FROM mxq_group" + " WHERE group_id = ?" + ); + if (!stmt) + mx_die("mx_mysql_statement_prepare(): %s\n", mx_mysql_error()); + + mx_mysql_statement_param_bind(stmt, 0, uint64, &group_id); + + unsigned long long num_rows; + int res = mx_mysql_statement_execute(stmt, &num_rows); + if (res < 0) + mx_die("mx_mysql_statement_execute(): %s\n", mx_mysql_error()); + + if (num_rows == 0) + mx_die("no such group_id %lu\n", group_id); + + uint64_t uid; + mx_mysql_statement_result_bind(stmt, 0, uint64, &uid); + + res = mx_mysql_statement_fetch(stmt); + if (res < 0) + mx_die("mx_mysql_statement_fetch: %s\n", mx_mysql_error()); + + if (uid != user_uid) + mx_die("group %lu: permission denied\n", group_id); + + mx_mysql_statement_close(&stmt); +} + +static void set_group_cancelled(struct mx_mysql *mysql, uint64_t group_id) { + struct mx_mysql_stmt *stmt = mx_mysql_statement_prepare(mysql, + "UPDATE mxq_group SET group_status = " status_str(MXQ_GROUP_STATUS_CANCELLED) + " WHERE group_id = ?" + ); + if (!stmt) + mx_die("mx_mysql_statement_prepare(): %s\n", mx_mysql_error()); + + mx_mysql_statement_param_bind(stmt, 0, uint64, &group_id); + + unsigned long long num_rows; + int res = mx_mysql_statement_execute(stmt, &num_rows); + if (res < 0) + mx_die("mx_mysql_statement_execute(): %s\n", mx_mysql_error()); + if (num_rows == 0) + mx_die("no such group_id %lu\n", group_id); + + mx_mysql_statement_close(&stmt); +} + +static void cancel_pending_jobs(struct mx_mysql *mysql, uint64_t group_id) { + struct mx_mysql_stmt *stmt = mx_mysql_statement_prepare(mysql, + "UPDATE mxq_job SET job_cancelled = TRUE" + " WHERE group_id = ?" + " AND job_status = " status_str(MXQ_JOB_STATUS_INQ) + ); + if (!stmt) + mx_die("mx_mysql_statement_prepare(): %s\n", mx_mysql_error()); + + mx_mysql_statement_param_bind(stmt, 0, uint64, &group_id); + + unsigned long long num_rows; + int res = mx_mysql_statement_execute(stmt, &num_rows); + if (res < 0) + mx_die("mx_mysql_statement_execute(): %s\n", mx_mysql_error()); + if (num_rows) + mx_log_notice("cancelled %llu jobs in group with group_id=%lu", num_rows, group_id); + mx_mysql_statement_close(&stmt); +} + +void cancel_group(struct mx_mysql *mysql, uint64_t group_id, uint64_t user_uid) { + + verify_group_owner(mysql, group_id, user_uid); + set_group_cancelled(mysql, group_id); + cancel_pending_jobs(mysql, group_id); + mx_log_notice("marked all running jobs in group with group_id=%lu to be killed by executing servers.", group_id); + mx_log_notice("deactivated group with group_id=%lu", group_id); +} + int main(int argc, char *argv[]) { struct mx_mysql *mysql = NULL;