Skip to content

Commit

Permalink
mxqkill: Add cancel_job
Browse files Browse the repository at this point in the history
To cancel a single job:

- Verify the owner uid in advance, so that we don't need a join with
  mxq_group during a later update statement. The join during update
  doesn't work well with the triggers, which want to modify mxq_group.
  By avoiding this, we can later dispose the CANCELLING state which is
  also just a workaround.

- Set job_cancelled to true for the job (don't mind job_status)

job_status transitions will be done by following commits.
  • Loading branch information
donald committed Dec 28, 2023
1 parent 4743e02 commit 57c2214
Showing 1 changed file with 69 additions and 0 deletions.
69 changes: 69 additions & 0 deletions mxqkill.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
#define UINT64_SPECIAL_MIN (uint64_t)(-2)
#define UINT64_HASVALUE(x) ((x) < UINT64_SPECIAL_MIN)

__attribute__ ((noreturn))
__attribute__ ((format (printf, 1, 2)))
static void die(const char *restrict fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
_exit(1);
}

static void print_usage(void)
{
mxq_print_generic_version();
Expand Down Expand Up @@ -148,6 +158,65 @@ static int update_job_status_cancelled_by_group(struct mx_mysql *mysql, struct m
return (int)num_rows;
}

static void verify_job_owner(struct mx_mysql *mysql, uint64_t job_id, uint64_t user_uid) {
struct mx_mysql_stmt *stmt = mx_mysql_statement_prepare(mysql,
"SELECT user_uid FROM mxq_job, mxq_group"
" WHERE mxq_job.group_id = mxq_group.group_id"
" AND job_id = ?"
);
if (!stmt)
die("mx_mysql_statement_prepare(): %s\n", mx_mysql_error());

mx_mysql_statement_param_bind(stmt, 0, uint64, &job_id);

unsigned long long num_rows;
int res = mx_mysql_statement_execute(stmt, &num_rows);
if (res < 0)
die("mx_mysql_statement_execute(): %s\n", mx_mysql_error());

if (num_rows == 0)
die("no such job_id %lu\n", job_id);

uint64_t uid;
mx_mysql_statement_result_bind(stmt, 0, uint64, &uid);

res = mx_mysql_statement_fetch(stmt);
if (res < 0)
die("mx_mysql_statement_fetch: %s\n", mx_mysql_error());

if (uid != user_uid)
die("job %lu: permission denied\n", job_id);

mx_mysql_statement_close(&stmt);
}

static void set_job_cancelled(struct mx_mysql *mysql, uint64_t job_id) {
struct mx_mysql_stmt *stmt = mx_mysql_statement_prepare(mysql,
"UPDATE mxq_job SET job_cancelled = TRUE"
" WHERE job_id = ?"
);
if (!stmt)
die("mx_mysql_statement_prepare(): %s\n", mx_mysql_error());

mx_mysql_statement_param_bind(stmt, 0, uint64, &job_id);

unsigned long long num_rows;
int res = mx_mysql_statement_execute(stmt, &num_rows);
if (res < 0)
die("mx_mysql_statement_execute(): %s\n", mx_mysql_error());
if (num_rows == 0)
die("no such job_id %lu\n", job_id);

mx_mysql_statement_close(&stmt);
}

__attribute__ ((unused))
static void cancel_job(struct mx_mysql *mysql, uint64_t job_id, uint64_t user_uid) {

verify_job_owner(mysql, job_id, user_uid);
set_job_cancelled(mysql, job_id);
}

static int update_job_status_cancelling_by_job_id_for_user(struct mx_mysql *mysql, uint64_t job_id, uint64_t user_uid)
{
struct mx_mysql_stmt *stmt = NULL;
Expand Down

0 comments on commit 57c2214

Please sign in to comment.