diff --git a/.gitignore b/.gitignore index 2918c579..d5cd7fc6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ mx_util.o mxq_group.o mxqdump.o mxq_job.o -mxq_job_dump.o mxq_mysql.o mxqd.o mxqsub.o @@ -20,7 +19,6 @@ mx_mysql.o mxqsub mxqdump mxqkill -mxq_job_dump mxqd test_mx_util test_mx_log diff --git a/Makefile b/Makefile index f5a54aba..99368dd7 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ MXQ_VERSION_MAJOR = 0 -MXQ_VERSION_MINOR = 3 -MXQ_VERSION_PATCH = 3 +MXQ_VERSION_MINOR = 4 +MXQ_VERSION_PATCH = 0 MXQ_VERSION_EXTRA = "beta" MXQ_VERSION = ${MXQ_VERSION_MAJOR}.${MXQ_VERSION_MINOR}.${MXQ_VERSION_PATCH} @@ -94,6 +94,7 @@ CFLAGS_MYSQL += ${CFLAGS_MXQ_MYSQL_DEFAULT_GROUP} CFLAGS += -g CFLAGS += -Wall CFLAGS += -Wno-unused-variable +CFLAGS += -Wno-unused-function CFLAGS += -DMXQ_VERSION=\"${MXQ_VERSION}\" CFLAGS += -DMXQ_VERSIONFULL=\"${MXQ_VERSIONFULL}\" CFLAGS += -DMXQ_VERSIONDATE=\"${MXQ_VERSIONDATE}\" @@ -289,14 +290,6 @@ mxqkill.o: CFLAGS += $(CFLAGS_MYSQL) clean: CLEAN += mxqkill.o -### mxq_job_dump.o ----------------------------------------------------- - -mxq_job_dump.o: $(mx_log.h) -mxq_job_dump.o: $(mxq_util.h) -mxq_job_dump.o: $(mxq_mysql.h) - -clean: CLEAN += mxq_job_dump.o - ### mxq_util.o --------------------------------------------------------- mxq_util.o: $(mx_log.h) @@ -398,6 +391,7 @@ install:: mxqsub mxqdump: mx_log.o mxqdump: mx_mysql.o mxqdump: mxq_group.o +mxqdump: mxq_job.o mxqdump: mxq_mysql.o mxqdump: mxq_util.o mxqdump: mx_util.o @@ -426,17 +420,6 @@ clean: CLEAN += mxqkill install:: mxqkill $(call quiet-installforuser,$(SUID_MODE),$(UID_CLIENT),$(GID_CLIENT),mxqkill,${DESTDIR}${BINDIR}/mxqkill) -### mxq_job_dump ------------------------------------------------------- - -mxq_job_dump: mx_log.o -mxq_job_dump: mxq_mysql.o -mxq_job_dump: mxq_util.o -mxq_job_dump: LDLIBS += $(LDLIBS_MYSQL) - -build: mxq_job_dump - -clean: CLEAN += mxq_job_dump - ######################################################################## install:: mxqdctl-hostconfig.sh diff --git a/mx_util.h b/mx_util.h index 64f100c0..e26526be 100644 --- a/mx_util.h +++ b/mx_util.h @@ -54,6 +54,12 @@ static inline void __mx_free(void *ptr) { #undef unlikely #define unlikely(x) __builtin_expect((x),0) +#undef mx_streq +#define mx_streq(a, b) (strcmp((a), (b)) == 0) + +#undef mx_streq_nocase +#define mx_streq_nocase(a, b) (strcasecmp((a), (b)) == 0) + int mx_strbeginswith(char *str, const char *start, char **endptr); int mx_stribeginswith(char *str, const char *start, char **endptr); int mx_strbeginswithany(char *str, char **starts, char **endptr); diff --git a/mxq_job.c b/mxq_job.c index 0049cd4c..f617c29f 100644 --- a/mxq_job.c +++ b/mxq_job.c @@ -90,6 +90,40 @@ enum mxq_job_columns { MXQ_JOB_COL__END }; +char *mxq_job_status_to_name(uint64_t status) +{ + switch (status) { + case MXQ_JOB_STATUS_INQ: + return "inq"; + case MXQ_JOB_STATUS_ASSIGNED: + return "assigned"; + case MXQ_JOB_STATUS_LOADED: + return "loaded"; + case MXQ_JOB_STATUS_RUNNING: + return "running"; + case MXQ_JOB_STATUS_UNKNOWN_RUN: + return "running-unknown"; + case MXQ_JOB_STATUS_EXTRUNNING: + return "running-external"; + case MXQ_JOB_STATUS_STOPPED: + return "stopped"; + case MXQ_JOB_STATUS_EXIT: + return "exited"; + case MXQ_JOB_STATUS_KILLED: + return "killed"; + case MXQ_JOB_STATUS_FAILED: + return "failed"; + case MXQ_JOB_STATUS_CANCELLED: + return "cancelled"; + case MXQ_JOB_STATUS_UNKNOWN: + return "unknown"; + case MXQ_JOB_STATUS_FINISHED: + return "finished"; + } + + return "invalid"; +} + static inline int mxq_job_bind_results(MYSQL_BIND *bind, struct mxq_job *j) { memset(bind, 0, sizeof(*bind)*MXQ_JOB_COL__END); diff --git a/mxq_job.h b/mxq_job.h index 80a5a5f0..a8e23b1a 100644 --- a/mxq_job.h +++ b/mxq_job.h @@ -88,6 +88,8 @@ struct mxq_job { #define status_str(x) _to_string(x) +char *mxq_job_status_to_name(uint64_t status); + int mxq_job_load_assigned(MYSQL *mysql, struct mxq_job *job, char *hostname, char *server_id); void mxq_job_free_content(struct mxq_job *j); int mxq_job_load(MYSQL *mysql, struct mxq_job *mxqjob, uint64_t group_id, char *hostname, char *server_id); diff --git a/mxq_job_dump.c b/mxq_job_dump.c deleted file mode 100644 index 604d077d..00000000 --- a/mxq_job_dump.c +++ /dev/null @@ -1,279 +0,0 @@ - -#define _GNU_SOURCE - -#include -#include -#include -#include - -#include - -#include "mx_log.h" -#include "mxq_util.h" -#include "mxq_mysql.h" - -#include "mxq_group.h" -#include "mxq_job.h" - - -struct result { - struct mxq_job job; - - unsigned long job_workdir_length; - unsigned long job_argv_length; - unsigned long job_stdout_length; - unsigned long job_stderr_length; - unsigned long host_submit_length; - unsigned long server_id_length; - unsigned long host_hostname_length; -}; - - -//XXX -#define COLUMNS "job_id, " \ - "job_status, " \ - "job_priority, " \ - "group_id, " \ - "job_workdir, " \ - "job_argc, " \ - "job_argv, " \ - "job_stdout, " \ - "job_stderr, " \ - "job_umask, " \ - "host_submit, " \ - "server_id, " \ - "host_hostname, " \ - "host_pid, " \ - "UNIX_TIMESTAMP(date_submit) as date_submit, " \ - "UNIX_TIMESTAMP(date_start) as date_start, " \ - "UNIX_TIMESTAMP(date_end) as date_end, " \ - "stats_status, " \ - "stats_utime_sec, " \ - "stats_utime_usec, " \ - "stats_stime_sec, " \ - "stats_stime_usec, " \ - "stats_real_sec, " \ - "stats_real_usec, " \ - "stats_maxrss, " \ - "stats_minflt, " \ - "stats_majflt, " \ - "stats_nswap, " \ - "stats_inblock, " \ - "stats_oublock, " \ - "stats_nvcsw, " \ - "stats_nivcsw" - -//XXX -enum result_columns { - COL_JOB_ID, - COL_JOB_STATUS, - COL_JOB_PRIORITY, - COL_GROUP_ID, - COL_JOB_WORKDIR, - COL_JOB_ARGC, - COL_JOB_ARGV, - COL_JOB_STDOUT, - COL_JOB_STDERR, - COL_JOB_UMASK, - COL_HOST_SUBMIT, - COL_SERVER_ID, - COL_HOST_HOSTNAME, - COL_HOST_PID, - COL_DATE_SUBMIT, - COL_DATE_START, - COL_DATE_END, - COL_STATS_STATUS, - COL_STATS_UTIME_SEC, - COL_STATS_UTIME_USEC, - COL_STATS_STIME_SEC, - COL_STATS_STIME_USEC, - COL_STATS_REAL_SEC, - COL_STATS_REAL_USEC, - COL_STATS_MAXRSS, - COL_STATS_MINFLT, - COL_STATS_MAJFLT, - COL_STATS_NSWAP, - COL_STATS_INBLOCK, - COL_STATS_OUBLOCK, - COL_STATS_NVCSW, - COL_STATS_NIVCSW, - COL__END -}; - -/* - struct timeval stats_starttime; - - int stats_status; - struct timeval stats_realtime; - struct rusage stats_rusage; -}; -*/ - -//XXX -static inline int prepare_result_bindings(MYSQL_BIND *bind, struct result *g) -{ - memset(bind, 0, sizeof(*bind)*COL__END); - - MXQ_MYSQL_BIND_UINT64(bind, COL_JOB_ID, &g->job.job_id); - MXQ_MYSQL_BIND_UINT16(bind, COL_JOB_STATUS, &g->job.job_status); - MXQ_MYSQL_BIND_UINT16(bind, COL_JOB_PRIORITY, &g->job.job_priority); - - MXQ_MYSQL_BIND_UINT64(bind, COL_GROUP_ID, &g->job.group_id); - - MXQ_MYSQL_BIND_VARSTR(bind, COL_JOB_WORKDIR, &g->job_workdir_length); - - MXQ_MYSQL_BIND_UINT16(bind, COL_JOB_ARGC, &g->job.job_argc); - MXQ_MYSQL_BIND_VARSTR(bind, COL_JOB_ARGV, &g->job_argv_length); - - MXQ_MYSQL_BIND_VARSTR(bind, COL_JOB_STDOUT, &g->job_stdout_length); - MXQ_MYSQL_BIND_VARSTR(bind, COL_JOB_STDERR, &g->job_stderr_length); - - MXQ_MYSQL_BIND_UINT32(bind, COL_JOB_UMASK, &g->job.job_umask); - - MXQ_MYSQL_BIND_VARSTR(bind, COL_HOST_SUBMIT, &g->host_submit_length); - MXQ_MYSQL_BIND_VARSTR(bind, COL_SERVER_ID, &g->server_id_length); - - MXQ_MYSQL_BIND_VARSTR(bind, COL_HOST_HOSTNAME, &g->host_hostname_length); - MXQ_MYSQL_BIND_UINT32(bind, COL_HOST_PID, &g->job.host_pid); - - MXQ_MYSQL_BIND_INT32(bind, COL_DATE_SUBMIT, &g->job.date_submit); - MXQ_MYSQL_BIND_INT32(bind, COL_DATE_START, &g->job.date_start); - MXQ_MYSQL_BIND_INT32(bind, COL_DATE_END, &g->job.date_end); - - MXQ_MYSQL_BIND_UINT32(bind, COL_STATS_UTIME_SEC, &g->job.stats_rusage.ru_utime.tv_sec); - MXQ_MYSQL_BIND_UINT32(bind, COL_STATS_UTIME_USEC, &g->job.stats_rusage.ru_utime.tv_usec); - - MXQ_MYSQL_BIND_UINT32(bind, COL_STATS_STIME_SEC, &g->job.stats_rusage.ru_stime.tv_sec); - MXQ_MYSQL_BIND_UINT32(bind, COL_STATS_STIME_USEC, &g->job.stats_rusage.ru_stime.tv_usec); - - MXQ_MYSQL_BIND_UINT32(bind, COL_STATS_REAL_SEC, &g->job.stats_realtime.tv_sec); - MXQ_MYSQL_BIND_UINT32(bind, COL_STATS_REAL_USEC, &g->job.stats_realtime.tv_usec); - - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_STATUS, &g->job.stats_status); - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_MAXRSS, &g->job.stats_rusage.ru_maxrss); - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_MINFLT, &g->job.stats_rusage.ru_minflt); - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_MAJFLT, &g->job.stats_rusage.ru_majflt); - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_NSWAP, &g->job.stats_rusage.ru_nswap); - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_INBLOCK, &g->job.stats_rusage.ru_inblock); - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_OUBLOCK, &g->job.stats_rusage.ru_oublock); - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_NVCSW, &g->job.stats_rusage.ru_nvcsw); - MXQ_MYSQL_BIND_INT32(bind, COL_STATS_NIVCSW, &g->job.stats_rusage.ru_nivcsw); - - - return 1; -} - -int fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *bind, struct result *g) -{ - int res; - - res = mxq_mysql_stmt_fetch_row(stmt); - if (!res) { - if (errno == ENOENT) - return 0; - perror("xxxx0"); - return 0; - } - - res = mxq_mysql_stmt_fetch_string(stmt, bind, COL_JOB_WORKDIR, &(g->job.job_workdir), g->job_workdir_length); - if (!res) { - return 0; - } - - res = mxq_mysql_stmt_fetch_string(stmt, bind, COL_JOB_ARGV, &(g->job.job_argv_str), g->job_argv_length); - if (!res) { - return 0; - } - - res = mxq_mysql_stmt_fetch_string(stmt, bind, COL_JOB_STDOUT, &(g->job.job_stdout), g->job_stdout_length); - if (!res) { - return 0; - } - - res = mxq_mysql_stmt_fetch_string(stmt, bind, COL_JOB_STDERR, &(g->job.job_stderr), g->job_stderr_length); - if (!res) { - return 0; - } - - res = mxq_mysql_stmt_fetch_string(stmt, bind, COL_HOST_SUBMIT, &(g->job.host_submit), g->host_submit_length); - if (!res) { - return 0; - } - - res = mxq_mysql_stmt_fetch_string(stmt, bind, COL_SERVER_ID, &(g->job.server_id), g->server_id_length); - if (!res) { - return 0; - } - - res = mxq_mysql_stmt_fetch_string(stmt, bind, COL_HOST_HOSTNAME, &(g->job.host_hostname), g->host_hostname_length); - if (!res) { - return 0; - } - - return 1; -} - -int mxq_group_load_jobs(MYSQL *mysql, struct mxq_job **mxq_job) -{ - MYSQL_STMT *stmt; - MYSQL_BIND result[COL__END]; - struct result g; - char *query; - struct mxq_job *job; - int cnt; - - *mxq_job = NULL; - - prepare_result_bindings(result, &g); - - query = "SELECT " COLUMNS " FROM mxq_job where job_status=200"; - - stmt = mxq_mysql_stmt_do_query(mysql, query, COL__END, NULL, result); - if (!stmt) { - mx_log_err("mxq_mysql_stmt_do_query(mysql=%p, stmt_str=\"%s\", field_count=%d, param=%p, result=%p)", mysql, query, COL__END, NULL, result); - return 0; - } - - //XXX - cnt = 0; - job = NULL; - while (fetch_results(stmt, result, &g)) { - job = realloc_forever(job, sizeof(*job)*(cnt+1)); - memcpy(job+cnt, &g.job, sizeof(*job)); - cnt++; - } - - *mxq_job = job; - - mysql_stmt_close(stmt); - return cnt; -} - -int main(int argc, char *argv[]) -{ - struct mxq_mysql mmysql; - MYSQL *mysql; - struct mxq_job *jobs; - int cnt; - int i; - - mmysql.default_file = NULL; - mmysql.default_group = "mxq_job_dump"; - - mysql = mxq_mysql_connect(&mmysql); - - cnt = mxq_group_load_jobs(mysql, &jobs); - -// printf("cnt=%d\n", cnt); - - for (i=0;i +#include +#include + #include #include "mx_getopt.h" @@ -18,6 +21,77 @@ #include "mx_mysql.h" #include "mxq_group.h" +#include "mxq_job.h" + +#define UINT64_UNSET (uint64_t)(-1) +#define UINT64_ALL (uint64_t)(-2) +#define UINT64_SPECIAL_MIN (uint64_t)(-2) +#define UINT64_HASVALUE(x) ((x) < UINT64_SPECIAL_MIN) + +#define GROUP_FIELDS \ + " group_id," \ + " group_name," \ + " group_status," \ + " group_priority," \ + " user_uid," \ + " user_name," \ + " user_gid," \ + " user_group," \ + " job_command," \ + " job_threads," \ + " job_memory," \ + " job_time," \ + " group_jobs," \ + " group_jobs_running," \ + " group_jobs_finished," \ + " group_jobs_failed," \ + " group_jobs_cancelled," \ + " group_jobs_unknown," \ + " group_slots_running," \ + " stats_max_maxrss," \ + " stats_max_utime_sec," \ + " stats_max_stime_sec," \ + " stats_max_real_sec" + +#define JOB_FIELDS \ + " job_id, " \ + " job_status, " \ + " job_priority, " \ + " group_id, " \ + " job_workdir, " \ + \ + " job_argc, " \ + " job_argv, " \ + " job_stdout, " \ + " job_stderr, " \ + " job_umask, " \ + \ + " host_submit, " \ + " server_id, " \ + " host_hostname, " \ + " host_pid, " \ + " UNIX_TIMESTAMP(date_submit) as date_submit, " \ + \ + " UNIX_TIMESTAMP(date_start) as date_start, " \ + " UNIX_TIMESTAMP(date_end) as date_end, " \ + " stats_status, " \ + " stats_utime_sec, " \ + " stats_utime_usec, " \ + \ + " stats_stime_sec, " \ + " stats_stime_usec, " \ + " stats_real_sec, " \ + " stats_real_usec, " \ + " stats_maxrss, " \ + \ + " stats_minflt, " \ + " stats_majflt, " \ + " stats_nswap, " \ + " stats_inblock, " \ + " stats_oublock, " \ + \ + " stats_nvcsw, " \ + " stats_nivcsw" static void print_usage(void) { @@ -25,168 +99,805 @@ static void print_usage(void) printf( "\n" "Usage:\n" - " %s [options]\n" + " %s [options] [modes]\n" "\n" + " %s [options] [--groups] [groups-options]\n" + " %s [options] --group-id \n" + " %s [options] --jobs [jobs-options]\n" + " %s [options] --job-id \n" + "\n\n" "Synopsis:\n" - " Dump status infromation of MXQ cluster.\n" + " Dump status information of MXQ cluster.\n" + "\n\n" + "available [modes]:\n" + " --groups [groups-options] dump (active) groups (default mode)\n" + " -g | --group-id dump group with \n" + " -j | --jobs [job-options] dump jobs\n" + " -J | --job-id dump job with \n" + "\n\n" + "[groups-options]:\n" + " -r | --running filter groups with running jobs (default: active groups)\n" + " -u | --user [uid] filter [uid]s/everybodys groups (default: own groups)\n" + " -a | --all no filter - dump all groups (default: active groups)\n" + "\n\n" + "[jobs-options]:\n" + " -u | --user [uid] filter [uid]s/everybodys jobs (default: own uid)\n" + " -g | --group-id filter jobs in group with \n" + " -s | --status filter jobs with (default: running)\n" + " (only available when --group-id is set)\n" "\n" - "options:\n\n" + " -q | --inq alias for '--status=inq'\n" + " -r | --running alias for '--status=running'\n" + " -f | --finished alias for '--status=finished'\n" + " -F | --failed alias for '--status=failed'\n" + " -U | --unknown alias for '--status=unknown'\n" + "\n\n" + "[options]:\n" " -V | --version\n" " -h | --help\n" "\n" - "Change how to connect to the mysql server:\n" + " Change how to connect to the mysql server:\n" "\n" " -M | --mysql-default-file [mysql-file] (default: %s)\n" " -S | --mysql-default-group [mysql-group] (default: %s)\n" "\n" + "\n" + "Option parameters:\n" + "\n" + " Parameters in [] are optional and values in <> are mandatory\n" + "\n" + " [uid] numeric user id. If not set assume 'all users'.\n" + " numeric group id\n" + " numeric job id\n" + " one of 'running', 'finished', 'failed' or 'unknown'\n" + "\n" "Environment:\n" " MXQ_MYSQL_DEFAULT_FILE change default for [mysql-file]\n" " MXQ_MYSQL_DEFAULT_GROUP change default for [mysql-group]\n" "\n", program_invocation_short_name, + program_invocation_short_name, + program_invocation_short_name, + program_invocation_short_name, + program_invocation_short_name, MXQ_MYSQL_DEFAULT_FILE_STR, MXQ_MYSQL_DEFAULT_GROUP_STR ); } -static int load_active_groups(struct mx_mysql *mysql, struct mxq_group **mxq_groups) +static int bind_result_job_fields(struct mx_mysql_bind *result, struct mxq_job *j) +{ + int res = 0; + int idx = 0; + + res = mx_mysql_bind_init_result(result, 32); + assert(res >= 0); + + res += mx_mysql_bind_var(result, idx++, uint64, &(j->job_id)); + res += mx_mysql_bind_var(result, idx++, uint16, &(j->job_status)); + res += mx_mysql_bind_var(result, idx++, uint16, &(j->job_priority)); + res += mx_mysql_bind_var(result, idx++, uint64, &(j->group_id)); + res += mx_mysql_bind_var(result, idx++, string, &(j->job_workdir)); + + res += mx_mysql_bind_var(result, idx++, uint16, &(j->job_argc)); + res += mx_mysql_bind_var(result, idx++, string, &(j->job_argv_str)); + res += mx_mysql_bind_var(result, idx++, string, &(j->job_stdout)); + res += mx_mysql_bind_var(result, idx++, string, &(j->job_stderr)); + res += mx_mysql_bind_var(result, idx++, uint32, &(j->job_umask)); + + res += mx_mysql_bind_var(result, idx++, string, &(j->host_submit)); + res += mx_mysql_bind_var(result, idx++, string, &(j->server_id)); + res += mx_mysql_bind_var(result, idx++, string, &(j->host_hostname)); + res += mx_mysql_bind_var(result, idx++, uint32, &(j->host_pid)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->date_submit)); + + res += mx_mysql_bind_var(result, idx++, int64, &(j->date_start)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->date_end)); + res += mx_mysql_bind_var(result, idx++, int32, &(j->stats_status)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_utime.tv_sec)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_utime.tv_usec)); + + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_stime.tv_sec)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_stime.tv_usec)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_realtime.tv_sec)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_realtime.tv_usec)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_maxrss)); + + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_minflt)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_majflt)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_nswap)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_inblock)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_oublock)); + + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_nvcsw)); + res += mx_mysql_bind_var(result, idx++, int64, &(j->stats_rusage.ru_nivcsw)); + + return res; +} + +static int bind_result_group_fields(struct mx_mysql_bind *result, struct mxq_group *g) +{ + int res = 0; + int idx = 0; + + res = mx_mysql_bind_init_result(result, 23); + assert(res >= 0); + + res += mx_mysql_bind_var(result, idx++, uint64, &(g->group_id)); + res += mx_mysql_bind_var(result, idx++, string, &(g->group_name)); + res += mx_mysql_bind_var(result, idx++, uint8, &(g->group_status)); + res += mx_mysql_bind_var(result, idx++, uint16, &(g->group_priority)); + + res += mx_mysql_bind_var(result, idx++, uint32, &(g->user_uid)); + res += mx_mysql_bind_var(result, idx++, string, &(g->user_name)); + res += mx_mysql_bind_var(result, idx++, uint32, &(g->user_gid)); + res += mx_mysql_bind_var(result, idx++, string, &(g->user_group)); + + res += mx_mysql_bind_var(result, idx++, string, &(g->job_command)); + + res += mx_mysql_bind_var(result, idx++, uint16, &(g->job_threads)); + res += mx_mysql_bind_var(result, idx++, uint64, &(g->job_memory)); + res += mx_mysql_bind_var(result, idx++, uint32, &(g->job_time)); + + res += mx_mysql_bind_var(result, idx++, uint64, &(g->group_jobs)); + res += mx_mysql_bind_var(result, idx++, uint64, &(g->group_jobs_running)); + res += mx_mysql_bind_var(result, idx++, uint64, &(g->group_jobs_finished)); + res += mx_mysql_bind_var(result, idx++, uint64, &(g->group_jobs_failed)); + res += mx_mysql_bind_var(result, idx++, uint64, &(g->group_jobs_cancelled)); + res += mx_mysql_bind_var(result, idx++, uint64, &(g->group_jobs_unknown)); + + res += mx_mysql_bind_var(result, idx++, uint64, &(g->group_slots_running)); + + res += mx_mysql_bind_var(result, idx++, uint32, &(g->stats_max_maxrss)); + res += mx_mysql_bind_var(result, idx++, int64, &(g->stats_max_utime.tv_sec)); + res += mx_mysql_bind_var(result, idx++, int64, &(g->stats_max_stime.tv_sec)); + res += mx_mysql_bind_var(result, idx++, int64, &(g->stats_max_real.tv_sec)); + + return res; +} + +static int load_active_groups_for_user(struct mx_mysql *mysql, struct mxq_group **mxq_groups, uint64_t user_uid) { - struct mx_mysql_stmt *stmt = NULL; - unsigned long long num_rows = 0; int res; - int cnt = 0; - struct mxq_group *groups; + struct mxq_group *groups = NULL; + struct mxq_group g = {0}; + struct mx_mysql_bind result = {0}; + struct mx_mysql_bind param = {0}; + assert(mysql); + assert(mxq_groups); + assert(!(*mxq_groups)); + + char *query = + "SELECT" + GROUP_FIELDS + " FROM mxq_group" + " WHERE ((group_jobs-group_jobs_finished-group_jobs_failed-group_jobs_cancelled-group_jobs_unknown > 0)" + " OR (NOW()-group_mtime < 604800))" + " AND user_uid = ?" + " ORDER BY user_name, group_mtime" + " LIMIT 1000"; + + res = mx_mysql_bind_init_param(¶m, 1); + assert(res == 0); + res = mx_mysql_bind_var(¶m, 0, uint64, &user_uid); + assert(res == 0); + + res = bind_result_group_fields(&result, &g); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, ¶m, &result, &g, (void **)&groups, sizeof(*groups)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; + } + + *mxq_groups = groups; + return res; +} + +static int load_running_groups(struct mx_mysql *mysql, struct mxq_group **mxq_groups) +{ + int res; + struct mxq_group *groups = NULL; + struct mxq_group g = {0}; + struct mx_mysql_bind result = {0}; + + assert(mysql); + assert(mxq_groups); + assert(!(*mxq_groups)); + + char *query = + "SELECT" + GROUP_FIELDS + " FROM mxq_group" + " WHERE (group_jobs-group_jobs_finished-group_jobs_failed-group_jobs_cancelled-group_jobs_unknown > 0)" + " ORDER BY user_name, group_mtime" + " LIMIT 1000"; + + res = bind_result_group_fields(&result, &g); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, NULL, &result, &g, (void **)&groups, sizeof(*groups)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; + } + + *mxq_groups = groups; + return res; +} + +static int load_running_groups_for_user(struct mx_mysql *mysql, struct mxq_group **mxq_groups, uint64_t user_uid) +{ + int res; + struct mxq_group *groups = NULL; + struct mxq_group g = {0}; + struct mx_mysql_bind param = {0}; + struct mx_mysql_bind result = {0}; assert(mysql); assert(mxq_groups); assert(!(*mxq_groups)); - stmt = mx_mysql_statement_prepare(mysql, + char *query = "SELECT" - " group_id," - " group_name," - " group_status," - " group_priority," - " user_uid," - " user_name," - " user_gid," - " user_group," - " job_command," - " job_threads," - " job_memory," - " job_time," - " group_jobs," - " group_jobs_running," - " group_jobs_finished," - " group_jobs_failed," - " group_jobs_cancelled," - " group_jobs_unknown," - " group_slots_running," - " stats_max_maxrss," - " stats_max_utime_sec," - " stats_max_stime_sec," - " stats_max_real_sec" + GROUP_FIELDS " FROM mxq_group" " WHERE (group_jobs-group_jobs_finished-group_jobs_failed-group_jobs_cancelled-group_jobs_unknown > 0)" - " OR (NOW()-group_mtime < 604800)" - " ORDER BY group_mtime" - " LIMIT 1000"); - if (!stmt) { - mx_log_err("mx_mysql_statement_prepare(): %m"); - return -errno; + " AND user_uid = ?" + " ORDER BY user_name, group_mtime" + " LIMIT 1000"; + + res = mx_mysql_bind_init_param(¶m, 1); + assert(res == 0); + res = mx_mysql_bind_var(¶m, 0, uint64, &user_uid); + assert(res == 0); + + res = bind_result_group_fields(&result, &g); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, ¶m, &result, &g, (void **)&groups, sizeof(*groups)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; + } + + *mxq_groups = groups; + return res; +} + +static int load_all_groups_for_user(struct mx_mysql *mysql, struct mxq_group **mxq_groups, uint64_t user_uid) +{ + int res; + struct mxq_group *groups = NULL; + struct mxq_group g = {0}; + struct mx_mysql_bind param = {0}; + struct mx_mysql_bind result = {0}; + + assert(mysql); + assert(mxq_groups); + assert(!(*mxq_groups)); + + char *query = + "SELECT" + GROUP_FIELDS + " FROM mxq_group" + " WHERE user_uid = ?" + " ORDER BY user_name, group_mtime" + " LIMIT 1000"; + + res = mx_mysql_bind_init_param(¶m, 1); + assert(res == 0); + res = mx_mysql_bind_var(¶m, 0, uint64, &user_uid); + assert(res == 0); + + res = bind_result_group_fields(&result, &g); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, ¶m, &result, &g, (void **)&groups, sizeof(*groups)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; } - res = mx_mysql_statement_execute(stmt, &num_rows); + *mxq_groups = groups; + return res; +} + +static int load_all_groups(struct mx_mysql *mysql, struct mxq_group **mxq_groups) +{ + int res; + struct mxq_group *groups = NULL; + struct mxq_group g = {0}; + struct mx_mysql_bind result = {0}; + + assert(mysql); + assert(mxq_groups); + assert(!(*mxq_groups)); + + char *query = + "SELECT" + GROUP_FIELDS + " FROM mxq_group" + " ORDER BY user_name, group_mtime" + " LIMIT 1000"; + + res = bind_result_group_fields(&result, &g); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, NULL, &result, &g, (void **)&groups, sizeof(*groups)); if (res < 0) { - mx_log_err("mx_mysql_statement_execute(): %m"); - mx_mysql_statement_close(&stmt); + mx_log_err("mx_mysql_do_statement(): %m"); return res; } - if (num_rows) { - int idx = 0; - struct mxq_group g = {0}; + *mxq_groups = groups; + return res; +} - groups = mx_calloc_forever(num_rows, sizeof(*groups)); +static int load_job(struct mx_mysql *mysql, struct mxq_job **mxq_jobs, uint64_t job_id) +{ + int res; + struct mxq_job *jobs = NULL; + struct mxq_job j = {0}; + struct mx_mysql_bind param = {0}; + struct mx_mysql_bind result = {0}; - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.group_id)); - res += mx_mysql_statement_result_bind(stmt, idx++, string, &(g.group_name)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint8, &(g.group_status)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint16, &(g.group_priority)); + assert(mysql); + assert(mxq_jobs); + assert(!(*mxq_jobs)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint32, &(g.user_uid)); - res += mx_mysql_statement_result_bind(stmt, idx++, string, &(g.user_name)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint32, &(g.user_gid)); - res += mx_mysql_statement_result_bind(stmt, idx++, string, &(g.user_group)); + char *query = + "SELECT" + JOB_FIELDS + " FROM mxq_job" + " WHERE job_id = ?" + " LIMIT 1"; - res += mx_mysql_statement_result_bind(stmt, idx++, string, &(g.job_command)); + res = mx_mysql_bind_init_param(¶m, 1); + assert(res == 0); + res = mx_mysql_bind_var(¶m, 0, uint64, &job_id); + assert(res == 0); - res += mx_mysql_statement_result_bind(stmt, idx++, uint16, &(g.job_threads)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.job_memory)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint32, &(g.job_time)); + res = bind_result_job_fields(&result, &j); + assert(res == 0); - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.group_jobs)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.group_jobs_running)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.group_jobs_finished)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.group_jobs_failed)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.group_jobs_cancelled)); - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.group_jobs_unknown)); + res = mx_mysql_do_statement(mysql, query, ¶m, &result, &j, (void **)&jobs, sizeof(*jobs)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; + } - res += mx_mysql_statement_result_bind(stmt, idx++, uint64, &(g.group_slots_running)); + *mxq_jobs = jobs; + return res; +} - res += mx_mysql_statement_result_bind(stmt, idx++, uint32, &(g.stats_max_maxrss)); - res += mx_mysql_statement_result_bind(stmt, idx++, int64, &(g.stats_max_utime.tv_sec)); - res += mx_mysql_statement_result_bind(stmt, idx++, int64, &(g.stats_max_stime.tv_sec)); - res += mx_mysql_statement_result_bind(stmt, idx++, int64, &(g.stats_max_real.tv_sec)); +static int load_jobs(struct mx_mysql *mysql, struct mxq_job **mxq_jobs, struct mxq_group *grp) +{ + int res; + struct mxq_job *jobs = NULL; + struct mxq_job j = {0}; + struct mx_mysql_bind param = {0}; + struct mx_mysql_bind result = {0}; - assert(res == 0); + assert(mysql); + assert(mxq_jobs); + assert(!(*mxq_jobs)); - for (cnt = 0; cnt < num_rows; cnt++) { - res = mx_mysql_statement_fetch(stmt); - if (res < 0) { - mx_log_err("mx_mysql_statement_fetch(): %m"); - mx_mysql_statement_close(&stmt); - return res; - } - memcpy(groups+cnt, &g, sizeof(*groups)); - } + char *query = + "SELECT" + JOB_FIELDS + " FROM mxq_job" + " WHERE group_id = ? OR 1 = 0" + " ORDER BY server_id, host_hostname, job_id"; + + res = mx_mysql_bind_init_param(¶m, 1); + assert(res == 0); + res = mx_mysql_bind_var(¶m, 0, uint64, &(grp->group_id)); + assert(res == 0); + + res = bind_result_job_fields(&result, &j); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, ¶m, &result, &j, (void **)&jobs, sizeof(*jobs)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; + } + + *mxq_jobs = jobs; + return res; +} + +static int load_jobs_with_status(struct mx_mysql *mysql, struct mxq_job **mxq_jobs, struct mxq_group *grp, uint64_t job_status) +{ + int res; + struct mxq_job *jobs = NULL; + struct mxq_job j = {0}; + struct mx_mysql_bind param = {0}; + struct mx_mysql_bind result = {0}; + + assert(mysql); + assert(mxq_jobs); + assert(!(*mxq_jobs)); + + char *query = + "SELECT" + JOB_FIELDS + " FROM mxq_job" + " WHERE group_id = ?" + " AND job_status = ?" + " ORDER BY server_id, host_hostname, job_id"; + + res = mx_mysql_bind_init_param(¶m, 2); + assert(res == 0); + res = mx_mysql_bind_var(¶m, 0, uint64, &(grp->group_id)); + res = mx_mysql_bind_var(¶m, 1, uint64, &job_status); + assert(res == 0); + + res = bind_result_job_fields(&result, &j); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, ¶m, &result, &j, (void **)&jobs, sizeof(*jobs)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; + } + + *mxq_jobs = jobs; + return res; +} + +static int load_running_jobs_by_group_id(struct mx_mysql *mysql, struct mxq_job **mxq_jobs, uint64_t group_id) +{ + int res; + struct mxq_job *jobs = NULL; + struct mxq_job j = {0}; + struct mx_mysql_bind param = {0}; + struct mx_mysql_bind result = {0}; + + assert(mysql); + assert(mxq_jobs); + assert(!(*mxq_jobs)); + + char *query = + "SELECT" + JOB_FIELDS + " FROM mxq_job" + " WHERE group_id = ?" + " AND job_status = 200" + " ORDER BY server_id, host_hostname, job_id"; + + res = mx_mysql_bind_init_param(¶m, 1); + assert(res == 0); + res = mx_mysql_bind_var(¶m, 0, uint64, &group_id); + assert(res == 0); + + res = bind_result_job_fields(&result, &j); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, ¶m, &result, &j, (void **)&jobs, sizeof(*jobs)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; } - mx_mysql_statement_close(&stmt); + *mxq_jobs = jobs; + return res; +} + + +static int load_group(struct mx_mysql *mysql, struct mxq_group **mxq_groups, uint64_t group_id) +{ + int res; + struct mxq_group *groups = NULL; + struct mxq_group g = {0}; + struct mx_mysql_bind param = {0}; + struct mx_mysql_bind result = {0}; + + assert(mysql); + assert(mxq_groups); + assert(!(*mxq_groups)); + + char *query = + "SELECT" + GROUP_FIELDS + " FROM mxq_group" + " WHERE group_id = ?" + " LIMIT 1"; + + res = mx_mysql_bind_init_param(¶m, 1); + assert(res == 0); + res = mx_mysql_bind_var(¶m, 0, uint64, &group_id); + assert(res == 0); + + res = bind_result_group_fields(&result, &g); + assert(res == 0); + + res = mx_mysql_do_statement(mysql, query, ¶m, &result, &g, (void **)&groups, sizeof(*groups)); + if (res < 0) { + mx_log_err("mx_mysql_do_statement(): %m"); + return res; + } *mxq_groups = groups; + return res; +} + +static int print_group(struct mxq_group *g) +{ + return printf("user=%s uid=%u group_id=%lu pri=%d jobs_total=%lu run_jobs=%lu run_slots=%lu failed=%lu" + " finished=%lu cancelled=%lu unknown=%lu inq=%lu" + " job_threads=%u job_memory=%lu job_time=%u" + " memory_load=%lu%% time_load=%lu%%" + " max_utime=%lu max_real=%lu max_memory=%u job_command=%s group_name=%s\n", + g->user_name, g->user_uid, g->group_id, g->group_priority, g->group_jobs, + g->group_jobs_running, g->group_slots_running, g->group_jobs_failed, + g->group_jobs_finished, g->group_jobs_cancelled, g->group_jobs_unknown, + mxq_group_jobs_inq(g), + g->job_threads, g->job_memory, g->job_time, + (100*g->stats_max_maxrss/1024/g->job_memory), + (100*g->stats_max_real.tv_sec/60/g->job_time), + g->stats_max_utime.tv_sec/60, g->stats_max_real.tv_sec/60, + g->stats_max_maxrss/1024, g->job_command, g->group_name); +} + +static int print_job(struct mxq_group *g, struct mxq_job *j) +{ + time_t now; + uint64_t run_sec; + + if (!j->date_end) { + time(&now); + + if (now == ((time_t)-1)) { + mx_log_err("time() failed: %m"); + run_sec = 0; + } else { + run_sec = (now - j->date_start); + } + } else { + run_sec = (j->date_end - j->date_start); + } + + return printf("job=%s(%u):%lu:%lu host_pid=%u server=%s::%s wait_sec=%lu run_sec=%lu utime=%lu stime=%lu time=%u time_load=%lu%% status=%s(%d) stats_status=%u command=%s" + "\n", + g->user_name, g->user_uid, g->group_id, j->job_id, + j->host_pid, + j->host_hostname, j->server_id, + (j->date_start - j->date_submit), run_sec, + j->stats_rusage.ru_utime.tv_sec,j->stats_rusage.ru_stime.tv_sec,g->job_time, + (100*(run_sec)/60/g->job_time), + mxq_job_status_to_name(j->job_status), j->job_status, j->stats_status, + j->job_argv_str); +} + +static int dump_group(struct mx_mysql *mysql, uint64_t group_id) +{ + struct mxq_group *grp, *groups = NULL; + + int grp_cnt = 0; + int total = 0; + + int g; + + assert(mysql); + assert(UINT64_HASVALUE(group_id)); + + grp_cnt = load_group(mysql, &groups, group_id); + if (!grp_cnt) + return 0; + + grp = &groups[0]; + + print_group(grp); + + mxq_group_free_content(grp); + mx_free_null(groups); + + return 1; +} + +static int dump_groups(struct mx_mysql *mysql, uint64_t status, uint64_t user_uid) +{ + struct mxq_group *grp, *groups = NULL; + + int grp_cnt = 0; + int total = 0; + + int g; + + assert(mysql); + + if (status == MXQ_JOB_STATUS_RUNNING) { + if (UINT64_HASVALUE(user_uid)) { + grp_cnt = load_running_groups_for_user(mysql, &groups, user_uid); + } else { + assert(user_uid == UINT64_ALL); + grp_cnt = load_running_groups(mysql, &groups); + } + } else if (status == UINT64_ALL && user_uid == UINT64_ALL) { + grp_cnt = load_all_groups(mysql, &groups); + } else if (status == UINT64_ALL && UINT64_HASVALUE(user_uid)) { + grp_cnt = load_all_groups_for_user(mysql, &groups, user_uid); + } else { + grp_cnt = load_active_groups_for_user(mysql, &groups, user_uid); + } + + for (g = 0; g < grp_cnt; g++) { + grp = &groups[g]; + + print_group(grp); + + mxq_group_free_content(grp); + } + + mx_free_null(groups); + + return grp_cnt; +} + +static int dump_job(struct mx_mysql *mysql, uint64_t job_id) +{ + struct mxq_group *grp, *groups = NULL; + struct mxq_job *job, *jobs = NULL; + + int grp_cnt = 0; + int job_cnt = 0; + int total = 0; + + int g, j; + + assert(mysql); + assert(UINT64_HASVALUE(job_id)); + + job_cnt = load_job(mysql, &jobs, job_id); + if (!job_cnt) { + return 0; + } + + job = &jobs[0]; + + grp_cnt = load_group(mysql, &groups, job->group_id); + if (!grp_cnt) { + mx_log_err("can'load group with group_id='%lu' for job with job_id='%lu'", job->group_id, job_id); + mxq_job_free_content(job); + mx_free_null(jobs); + return 0; + } + + grp = &groups[0]; + + print_job(grp, job); + + mxq_job_free_content(job); + mxq_group_free_content(grp); + mx_free_null(groups); + mx_free_null(jobs); - return cnt; + return 1; } +static int dump_jobs(struct mx_mysql *mysql, uint64_t group_id, uint64_t job_status, uint64_t user_uid) +{ + struct mxq_group *grp, *groups = NULL; + struct mxq_job *job, *jobs = NULL; + + int grp_cnt = 0; + int job_cnt = 0; + int total = 0; + + int g, j; + + assert(mysql); + assert(UINT64_HASVALUE(group_id) || group_id == UINT64_ALL); + assert(UINT64_HASVALUE(job_status) || job_status == UINT64_ALL); + assert(UINT64_HASVALUE(user_uid) || user_uid == UINT64_ALL); + + if (UINT64_HASVALUE(group_id)) { + assert(user_uid == UINT64_ALL); + grp_cnt = load_group(mysql, &groups, group_id); + } else { + assert(group_id == UINT64_ALL); + assert(job_status == MXQ_JOB_STATUS_RUNNING); + + if (UINT64_HASVALUE(user_uid)) + grp_cnt = load_running_groups_for_user(mysql, &groups, user_uid); + else + grp_cnt = load_running_groups(mysql, &groups); + } + + mx_debug_value("%lu", grp_cnt); + + for (g=0; g < grp_cnt; g++) { + grp = &groups[g]; + + if (UINT64_HASVALUE(job_status)) + job_cnt = load_jobs_with_status(mysql, &jobs, grp, job_status); + else + job_cnt = load_jobs(mysql, &jobs, grp); + + mx_debug_value("%lu", job_cnt); + + for (j=0; j < job_cnt; j++) { + job = &jobs[j]; + print_job(grp, job); + mxq_job_free_content(job); + } + mxq_group_free_content(grp); + mx_free_null(jobs); + + total += job_cnt; + } + mx_free_null(groups); + return total; +} int main(int argc, char *argv[]) { struct mx_mysql *mysql = NULL; - struct mxq_group *groups = NULL; - int group_cnt; int i; int res; char *arg_mysql_default_group; char *arg_mysql_default_file; + uid_t ruid, euid, suid; + char arg_debug; + char arg_all; + char arg_running; + char arg_jobs; + char arg_groups; + uint64_t arg_group_id; + uint64_t arg_job_id; + uint64_t arg_uid; + uint64_t arg_status; + + uint64_t cnt; int opt; struct mx_getopt_ctl optctl; struct mx_option opts[] = { - MX_OPTION_NO_ARG("help", 'h'), - MX_OPTION_NO_ARG("version", 'V'), + MX_OPTION_NO_ARG("help", 'h'), + MX_OPTION_NO_ARG("version", 'V'), + + MX_OPTION_NO_ARG("debug", 5), + MX_OPTION_NO_ARG("verbose", 'v'), + + MX_OPTION_NO_ARG("all", 'a'), + MX_OPTION_NO_ARG("running", 'r'), - MX_OPTION_NO_ARG("debug", 5), - MX_OPTION_NO_ARG("verbose", 'v'), + MX_OPTION_NO_ARG("inq", 'q'), + MX_OPTION_NO_ARG("finished", 'f'), + MX_OPTION_NO_ARG("failed", 'F'), + MX_OPTION_NO_ARG("unknown", 'U'), + + MX_OPTION_NO_ARG("jobs", 'j'), + + MX_OPTION_OPTIONAL_ARG("groups", 'g'), + MX_OPTION_REQUIRED_ARG("group-id", 'g'), + MX_OPTION_REQUIRED_ARG("job-id", 'J'), + + MX_OPTION_OPTIONAL_ARG("users", 'u'), + + MX_OPTION_REQUIRED_ARG("status", 's'), MX_OPTION_OPTIONAL_ARG("mysql-default-file", 'M'), MX_OPTION_OPTIONAL_ARG("mysql-default-group", 'S'), MX_OPTION_END }; - arg_debug = 0; + arg_debug = 0; + arg_all = 0; + arg_running = 0; + arg_jobs = 0; + arg_groups = 0; + arg_status = UINT64_UNSET; + arg_group_id = UINT64_UNSET; + arg_job_id = UINT64_UNSET; + arg_uid = UINT64_UNSET; + + mx_log_level_set(MX_LOG_NOTICE); arg_mysql_default_group = getenv("MXQ_MYSQL_DEFAULT_GROUP"); if (!arg_mysql_default_group) @@ -197,10 +908,11 @@ int main(int argc, char *argv[]) arg_mysql_default_file = MXQ_MYSQL_DEFAULT_FILE; mx_getopt_init(&optctl, argc-1, &argv[1], opts); - optctl.flags = MX_FLAG_STOPONUNKNOWN|MX_FLAG_STOPONNOOPT; + optctl.flags = 0; while ((opt=mx_getopt(&optctl, &i)) != MX_GETOPT_END) { if (opt == MX_GETOPT_ERROR) { + print_usage(); exit(EX_USAGE); } @@ -223,6 +935,93 @@ int main(int argc, char *argv[]) mx_log_level_set(MX_LOG_INFO); break; + case 'a': + arg_all = 1; + break; + + case 'j': + arg_jobs = 1; + break; + + case 'u': + if (!optctl.optarg) { + arg_uid = UINT64_ALL; + break; + } + if (mx_strtou64(optctl.optarg, &arg_uid) < 0 || arg_uid >= UINT64_SPECIAL_MIN) { + if (arg_uid >= UINT64_SPECIAL_MIN) + errno = ERANGE; + mx_log_err("Invalid argument for --group-id '%s': %m", optctl.optarg); + exit(EX_USAGE); + } + break; + + case 's': + if (mx_streq_nocase(optctl.optarg, "inq")) { + arg_status = MXQ_JOB_STATUS_INQ; + } else if (mx_streq_nocase(optctl.optarg, "running")) { + arg_status = MXQ_JOB_STATUS_RUNNING; + } else if (mx_streq_nocase(optctl.optarg, "failed")) { + arg_status = MXQ_JOB_STATUS_FAILED; + } else if (mx_streq_nocase(optctl.optarg, "cancelled")) { + arg_status = MXQ_JOB_STATUS_CANCELLED; + } else if (mx_streq_nocase(optctl.optarg, "unknown")) { + arg_status = MXQ_JOB_STATUS_UNKNOWN; + } else if (mx_streq_nocase(optctl.optarg, "finished")) { + arg_status = MXQ_JOB_STATUS_FINISHED; + } else if (mx_streq_nocase(optctl.optarg, "all")) { + arg_status = UINT64_ALL; + } else if (mx_streq_nocase(optctl.optarg, "any")) { + arg_status = UINT64_ALL; + } else { + mx_log_err("Invalid argument for --group-id '%s'", optctl.optarg); + exit(EX_USAGE); + } + break; + + case 'r': + arg_running = 1; + arg_status = MXQ_JOB_STATUS_RUNNING; + break; + + case 'q': + arg_status = MXQ_JOB_STATUS_INQ; + break; + + case 'f': + arg_status = MXQ_JOB_STATUS_FINISHED; + break; + + case 'F': + arg_status = MXQ_JOB_STATUS_FAILED; + break; + + case 'U': + arg_status = MXQ_JOB_STATUS_UNKNOWN; + break; + + case 'g': + if (!optctl.optarg) { + arg_groups = 1; + break; + } + if (mx_strtou64(optctl.optarg, &arg_group_id) < 0 || !arg_group_id || arg_group_id >= UINT64_SPECIAL_MIN) { + if (!arg_group_id || arg_group_id >= UINT64_SPECIAL_MIN) + errno = ERANGE; + mx_log_err("Invalid argument for --group-id '%s': %m", optctl.optarg); + exit(EX_USAGE); + } + break; + + case 'J': + if (mx_strtou64(optctl.optarg, &arg_job_id) < 0 || !arg_job_id || arg_job_id >= UINT64_SPECIAL_MIN) { + if (!arg_job_id || arg_job_id >= UINT64_SPECIAL_MIN) + errno = ERANGE; + mx_log_err("Invalid argument for --job-id '%s': %m", optctl.optarg); + exit(EX_USAGE); + } + break; + case 'M': arg_mysql_default_file = optctl.optarg; break; @@ -235,6 +1034,103 @@ int main(int argc, char *argv[]) MX_GETOPT_FINISH(optctl, argc, argv); + res = getresuid(&ruid, &euid, &suid); + assert(res != -1); + + if (UINT64_HASVALUE(arg_job_id)) { + if (UINT64_HASVALUE(arg_group_id)) + mx_log_err("options '--job-id' and '--group-id' are mutually exclusive."); + if (arg_jobs) + mx_log_err("options '--job-id' and '--jobs' are mutually exclusive."); + if (arg_groups) + mx_log_err("options '--job-id' and '--groups' are mutually exclusive."); + if (UINT64_HASVALUE(arg_group_id) || arg_jobs || arg_groups) { + mx_log_notice("usage: %s [options] --job-id ", program_invocation_short_name); + mx_log_notice("use %s --help to see full usage information.", program_invocation_short_name); + exit(EX_USAGE); + } + } + + if (UINT64_HASVALUE(arg_group_id) && !arg_jobs) { + assert(!UINT64_HASVALUE(arg_job_id)); + if (arg_groups) { + mx_log_err("options '--group-id' and '--groups' are mutually exclusive."); + mx_log_notice("usage: %s [options] --group-id ", program_invocation_short_name); + mx_log_notice("use %s --help to see full usage information.", program_invocation_short_name); + exit(EX_USAGE); + } + } + + if (arg_jobs && arg_groups) { + mx_log_err("options '--jobs' and '--groups' are mutually exclusive."); + mx_log_notice("usage: %s [options] --jobs [jobs-options]", program_invocation_short_name); + mx_log_notice("usage: %s [options] --groups [groups-options]", program_invocation_short_name); + mx_log_notice("use %s --help to see full usage information.", program_invocation_short_name); + exit(EX_USAGE); + } + + if (!UINT64_HASVALUE(arg_job_id) && !UINT64_HASVALUE(arg_group_id) && !arg_jobs) { + arg_groups = 1; // set default mode + } + + if (UINT64_HASVALUE(arg_job_id) || (UINT64_HASVALUE(arg_group_id) && !arg_jobs)) { + if (arg_running) { + mx_log_warning("ignoring option '--running'."); + if (arg_status == MXQ_JOB_STATUS_RUNNING) + arg_status = UINT64_UNSET; + arg_running = 0; + } + if (arg_all) { + mx_log_warning("ignoring option '--all'."); + arg_all = 0; + } + if (UINT64_HASVALUE(arg_status)) { + mx_log_warning("ignoring option '--status'."); + arg_status = UINT64_UNSET; + } + if (UINT64_HASVALUE(arg_uid)) { + mx_log_warning("ignoring option '--user=%lu'.", arg_uid); + arg_uid = UINT64_UNSET; + } + if (arg_uid == UINT64_ALL) { + mx_log_warning("ignoring option '--users'."); + arg_uid = UINT64_UNSET; + } + } else { + assert(arg_jobs || arg_groups); + if (arg_uid == UINT64_UNSET) + arg_uid = ruid; + } + + + if (arg_jobs && arg_running && arg_all && UINT64_HASVALUE(arg_group_id) ) { + mx_log_info("ignoring option '--all' when '--status', '--jobs' and '--group-id' are activated."); + arg_all = 0; + } + + if (!arg_jobs && arg_running && arg_status == MXQ_JOB_STATUS_RUNNING) { + arg_status = UINT64_UNSET; + } + + if (UINT64_HASVALUE(arg_status) && !arg_jobs) { + mx_log_warning("ignoring option '--status=%s' when '--jobs' is not set.", mxq_job_status_to_name(arg_status)); + arg_status = UINT64_UNSET; + } + + if (UINT64_HASVALUE(arg_status) && arg_status != MXQ_JOB_STATUS_RUNNING && !UINT64_HASVALUE(arg_group_id)) { + mx_log_warning("ignoring option '--status=%s' when '--group-id' is not set.", mxq_job_status_to_name(arg_status)); + arg_status = UINT64_UNSET; + } + + if (0 && arg_jobs && arg_running) { + mx_log_debug("ignoring option '--status=running' when '--jobs' is activated."); + arg_running = 0; + } + + // set defaults + if (arg_jobs && arg_status == UINT64_UNSET) + arg_status = MXQ_JOB_STATUS_RUNNING; + res = mx_mysql_init(&mysql); assert(res == 0); @@ -246,29 +1142,79 @@ int main(int argc, char *argv[]) mx_log_info("MySQL: Connection to database established."); + if (UINT64_HASVALUE(arg_job_id)) { + mx_log_debug("DO: print job with job_id=%lu", arg_job_id); + cnt = dump_job(mysql, arg_job_id); + if (!cnt) + mx_log_notice("No job found with job_id=%lu.", arg_job_id); + } else if (arg_jobs) { + if (UINT64_HASVALUE(arg_group_id)) { + if (arg_all) { + mx_log_debug("DO: print all jobs in group_id=%lu", arg_group_id); + cnt = dump_jobs(mysql, arg_group_id, UINT64_ALL, UINT64_ALL); + if (!cnt) + mx_log_notice("There are no jobs in group '%lu'.", arg_group_id); - group_cnt = load_active_groups(mysql, &groups); - - for (i=0; iuser_name, g->user_uid, g->group_id, g->group_priority, g->group_jobs, - g->group_jobs_running, g->group_slots_running, g->group_jobs_failed, g->group_jobs_finished, g->group_jobs_cancelled, g->group_jobs_unknown, - mxq_group_jobs_inq(g), - g->job_threads, g->job_memory, g->job_time, g->stats_max_utime.tv_sec, g->stats_max_real.tv_sec, - g->job_command, g->group_name); - - mxq_group_free_content(&groups[i]); + } else { + mx_log_debug("DO: print jobs in group_id=%lu with status='%s(%lu)'", + arg_group_id, mxq_job_status_to_name(arg_status), arg_status); + cnt = dump_jobs(mysql, arg_group_id, arg_status, UINT64_ALL); + if (!cnt) + mx_log_notice("There are no jobs with status '%s' in group '%lu'.", mxq_job_status_to_name(arg_status), arg_group_id); + } + } else { + if (arg_all) { + mx_log_debug("DO: print all running jobs"); + dump_jobs(mysql, UINT64_ALL, MXQ_JOB_STATUS_RUNNING, UINT64_ALL); + } else { + mx_log_debug("DO: print MY running jobs"); + cnt = dump_jobs(mysql, UINT64_ALL, MXQ_JOB_STATUS_RUNNING, arg_uid); + if (!cnt) { + if (arg_uid == ruid) + mx_log_notice("You do not have any jobs running on the cluster."); + else + mx_log_notice("No running jobs for user with uid '%lu'.", arg_uid); + } + } + } + } else if (UINT64_HASVALUE(arg_group_id)) { + mx_log_debug("DO: print group with group_id=%lu", arg_group_id); + cnt = dump_group(mysql, arg_group_id); + if (!cnt) + mx_log_notice("No group found with group_id=%lu.", arg_group_id); + } else { + if (UINT64_HASVALUE(arg_uid) && !arg_all && !(arg_uid == ruid && !arg_running)) { + mx_log_debug("DO: print running groups for user with uid=%d", arg_uid); + cnt = dump_groups(mysql, MXQ_JOB_STATUS_RUNNING, arg_uid); + if (!cnt) + mx_log_notice("No running groups found for user with uid=%d", arg_uid); + } else if (arg_uid == UINT64_ALL && arg_all) { + mx_log_debug("DO: print all groups"); + cnt = dump_groups(mysql, UINT64_ALL, UINT64_ALL); + if (!cnt) + mx_log_notice("No groups found."); + } else if (arg_all) { + mx_log_debug("DO: print all groups for user with uid=%lu", arg_uid); + cnt = dump_groups(mysql, UINT64_ALL, arg_uid); + if (!cnt) + mx_log_notice("No groups found for user with uid=%d.", arg_uid); + } else { + if (arg_uid == UINT64_ALL) { + mx_log_debug("DO: print all running groups"); + cnt = dump_groups(mysql, MXQ_JOB_STATUS_RUNNING, UINT64_ALL); + if (!cnt) + mx_log_notice("No running groups found."); + } else { + mx_log_debug("DO: print MY active groups (default)"); + cnt = dump_groups(mysql, UINT64_UNSET, ruid); + if (!cnt) + mx_log_notice("You do not have any active groups."); + } + } } - free(groups); - mx_mysql_finish(&mysql); mx_log_info("MySQL: Connection to database closed."); - - return 1; + return 0; }; diff --git a/mxqsub.c b/mxqsub.c index 45cf3588..975ca2eb 100644 --- a/mxqsub.c +++ b/mxqsub.c @@ -50,36 +50,37 @@ static void print_usage(void) printf( "\n" "Usage:\n" - " %s [mxqsub-options] [command options and arguments ..]\n" + " %s [options] \n" "\n" "Synopsis:\n" " queue a job to be executed on a cluster node.\n" - " [arguments] will be executed on a node that offers\n" + " will be executed on a node that offers\n" " enough resources to run the job. the following [options] can\n" " influence the job environment and the scheduling decisions made\n" " by the cluster:\n" "\n" "Job environment:\n" - " -w | --workdir set working directory (default: current workdir)\n" - " -o | --stdout set file to capture stdout (default: '/dev/null')\n" - " -e | --stderr set file to capture stderr (default: )\n" - " -u | --umask set mode to use as umask (default: current umask)\n" - " -p | --priority set priority (default: 127)\n" + " -w, --workdir=DIRECTORY set working directory (default: current workdir)\n" + " -o, --stdout=FILE set file to capture stdout (default: '/dev/null')\n" + " -e, --stderr=FILE set file to capture stderr (default: )\n" + " -u, --umask=MASK set mode to use as umask (default: current umask)\n" + " -p, --priority=PRIORITY set priority (default: 127)\n" "\n" "Job resource information:\n" " Scheduling is done based on the resources a job needs and\n" " on the priority given to the job.\n" "\n" - " -j | --threads set number of threads (default: 1)\n" - " -m | --memory set amount of memory in MiB (default: 2048)\n" - " -t | --time set runtime in minutes (default: 15)\n" + " -j, --threads=NUMBER set number of threads (default: 1)\n" + " -m, --memory=SIZE set amount of memory in MiB (default: 2048)\n" + " -t, --runtime=MINUTES set runtime in minutes (default: 15)\n" "\n" "Job handling:\n" - " Define what to do if something bad happens.\n" + " Define what to do if something bad happens:\n" "\n" - " -r | --restart [restartmode] restart job on system failure (default: 'never')\n" + " -r | --restart[=MODE] restart job on system failure (default: 'never')\n" "\n" - " available [restartmode]s:\n" + " available restart [MODE]s:\n" + " 'never' do not restart\n" " 'samehost' only restart if running on the same host.\n" " 'always' always restart or requeue. (default)\n" "\n" @@ -89,25 +90,25 @@ static void print_usage(void) " amount of resources and having the same priority\n" " are grouped and executed in parallel.\n" "\n" - " -a | --command-alias set command alias (default: )\n" - " -N | --group-name set group name (default: 'default')\n" - " -P | --group-priority set group priority (default: 127)\n" + " -a, --command-alias=NAME set command alias (default: )\n" + " -N, --group-name=NAME set group name (default: 'default')\n" + " -P, --group-priority=PRIORITY set group priority (default: 127)\n" "\n" "Other options:\n" "\n" - " -v | --verbose be more verbose\n" - " --debug set debug log level (default: warning log level)\n" - " --version print version and exit\n" - " --help print this help and exit ;)\n" + " -v, --verbose be more verbose\n" + " --debug set debug log level (default: warning log level)\n" + " -V, --version print version and exit\n" + " -h, --help print this help and exit ;)\n" "\n" "Change how to connect to the mysql server:\n" "\n" - " -M | --mysql-default-file [mysql-file] (default: %s)\n" - " -S | --mysql-default-group [mysql-group] (default: %s)\n" + " -M | --mysql-default-file[=MYSQLCNF] (default: %s)\n" + " -S | --mysql-default-group[=MYSQLGROUP] (default: %s)\n" "\n" "Environment:\n" - " MXQ_MYSQL_DEFAULT_FILE change default for [mysql-file]\n" - " MXQ_MYSQL_DEFAULT_GROUP change default for [mysql-group]\n" + " MXQ_MYSQL_DEFAULT_FILE change default for [MYSQLCNF]\n" + " MXQ_MYSQL_DEFAULT_GROUP change default for [MYSQLGROUP]\n" "\n", program_invocation_short_name, MXQ_MYSQL_DEFAULT_FILE_STR, @@ -462,7 +463,7 @@ int main(int argc, char *argv[]) arg_program_name = NULL; arg_threads = 1; arg_memory = 2048; - arg_time = 15; + arg_time = 0; arg_workdir = current_workdir; arg_stdout = "/dev/null"; arg_stderr = "stdout"; @@ -577,7 +578,7 @@ int main(int argc, char *argv[]) break; case 4: - mx_log_warning("option --time is deprecated. please use --runtime instead."); + mx_log_warning("option '--time' is deprecated. please use '--runtime' or '-t' in future calls."); case 't': if (mx_strtou32(optctl.optarg, &arg_time) < 0) { mx_log_crit("--runtime '%s': %m", optctl.optarg); @@ -640,6 +641,15 @@ int main(int argc, char *argv[]) /* from this point values in argc,argv are the ones of the cluster job */ + if (!arg_time) { + arg_time = 15; + mx_log_warning("option '--runtime' or '-t' not used. Your job will get killed if it runs longer than the default of %d minutes.", arg_time); + } + + if (arg_time > 60*24) { + mx_log_warning("option '--runtime' specifies a runtime longer than 24h. Your job may get killed. Be sure to implement some check pointing."); + } + if (!arg_program_name) arg_program_name = argv[0]; diff --git a/mysql/create_tables b/mysql/create_tables index 3c38705f..5cb8c04c 100644 --- a/mysql/create_tables +++ b/mysql/create_tables @@ -1,4 +1,22 @@ +ALTER TABLE mxq_group + ADD COLUMN group_jobs_inq INT8 UNSIGNED NOT NULL DEFAULT 0 + AFTER group_jobs; + +ALTER TABLE mxq_group + ADD COLUMN stats_total_utime_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + ADD COLUMN stats_total_stime_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + ADD COLUMN stats_total_real_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + ADD COLUMN stats_total_wait_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + ADD COLUMN stats_total_idle_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + + ADD COLUMN stats_total_utime_sec_finished INT8 UNSIGNED NOT NULL DEFAULT 0, + ADD COLUMN stats_total_stime_sec_finished INT8 UNSIGNED NOT NULL DEFAULT 0, + ADD COLUMN stats_total_real_sec_finished INT8 UNSIGNED NOT NULL DEFAULT 0; + +ALTER TABLE mxq_job + ADD INDEX (group_id); + ALTER TABLE mxq_job ADD COLUMN job_id_new INT8 UNSIGNED NULL DEFAULT NULL AFTER date_end; @@ -36,6 +54,7 @@ CREATE TABLE IF NOT EXISTS mxq_group ( job_time INT4 UNSIGNED NOT NULL DEFAULT 15, group_jobs INT8 UNSIGNED NOT NULL DEFAULT 0, + group_jobs_inq INT8 UNSIGNED NOT NULL DEFAULT 0, group_jobs_running INT8 UNSIGNED NOT NULL DEFAULT 0, group_jobs_finished INT8 UNSIGNED NOT NULL DEFAULT 0, group_jobs_failed INT8 UNSIGNED NOT NULL DEFAULT 0, @@ -52,6 +71,16 @@ CREATE TABLE IF NOT EXISTS mxq_group ( stats_max_stime_sec INT4 UNSIGNED NOT NULL DEFAULT 0, stats_max_real_sec INT4 UNSIGNED NOT NULL DEFAULT 0, + stats_total_utime_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + stats_total_stime_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + stats_total_real_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + stats_total_wait_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + stats_total_idle_sec INT8 UNSIGNED NOT NULL DEFAULT 0, + + stats_total_utime_sec_finished INT8 UNSIGNED NOT NULL DEFAULT 0, + stats_total_stime_sec_finished INT8 UNSIGNED NOT NULL DEFAULT 0, + stats_total_real_sec_finished INT8 UNSIGNED NOT NULL DEFAULT 0, + INDEX(group_id), INDEX(group_name) ); @@ -107,6 +136,7 @@ CREATE TABLE IF NOT EXISTS mxq_job ( stats_nivcsw INT4 NOT NULL DEFAULT 0, INDEX (job_id), + INDEX (group_id), INDEX (job_status), INDEX (job_priority), INDEX (host_hostname(64)), @@ -121,6 +151,7 @@ CREATE TRIGGER mxq_add_job AFTER INSERT ON mxq_job FOR EACH ROW BEGIN UPDATE mxq_group SET group_jobs=group_jobs+1, + group_jobs_inq=group_jobs_inq+1, group_mtime=NULL WHERE group_id=NEW.group_id; END; @@ -128,68 +159,71 @@ CREATE TRIGGER mxq_add_job AFTER INSERT ON mxq_job DROP TRIGGER mxq_update_job| CREATE TRIGGER mxq_update_job BEFORE UPDATE ON mxq_job FOR EACH ROW BEGIN - IF NEW.job_status = 200 AND OLD.job_status IN (0, 100, 150) THEN - UPDATE mxq_group SET - group_jobs_running=group_jobs_running+1, - group_slots_running=group_slots_running+NEW.host_slots, - group_mtime=NULL - WHERE group_id=NEW.group_id; - ELSEIF NEW.job_status IN (400, 750) AND OLD.job_status IN (200, 250, 300, 350) THEN - UPDATE mxq_group SET - group_slots_running=group_slots_running-NEW.host_slots, - group_jobs_running=group_jobs_running-1, - group_jobs_failed=group_jobs_failed+1, - stats_max_maxrss=GREATEST(stats_max_maxrss, NEW.stats_maxrss), - stats_max_utime_sec=GREATEST(stats_max_utime_sec, NEW.stats_utime_sec), - stats_max_stime_sec=GREATEST(stats_max_stime_sec, NEW.stats_stime_sec), - stats_max_real_sec=GREATEST(stats_max_real_sec, NEW.stats_real_sec), - group_mtime=NULL - WHERE group_id=NEW.group_id; - ELSEIF NEW.job_status = 990 AND OLD.job_status = 0 THEN - UPDATE mxq_group SET - group_jobs_cancelled=group_jobs_cancelled+1, - group_mtime=NULL - WHERE group_id=NEW.group_id; - ELSEIF NEW.job_status = 999 AND OLD.job_status IN (200, 250) THEN - UPDATE mxq_group SET - group_slots_running=group_slots_running-NEW.host_slots, - group_jobs_running=group_jobs_running-1, - group_jobs_unknown=group_jobs_unknown+1, - group_mtime=NULL - WHERE group_id=NEW.group_id; - ELSEIF NEW.job_status = 1000 AND OLD.job_status IN (200, 250, 300, 350) THEN - UPDATE mxq_group SET - group_slots_running=group_slots_running-NEW.host_slots, - group_jobs_running=group_jobs_running-1, - group_jobs_finished=group_jobs_finished+1, - stats_max_maxrss=GREATEST(stats_max_maxrss, NEW.stats_maxrss), - stats_max_utime_sec=GREATEST(stats_max_utime_sec, NEW.stats_utime_sec), - stats_max_stime_sec=GREATEST(stats_max_stime_sec, NEW.stats_stime_sec), - stats_max_real_sec=GREATEST(stats_max_real_sec, NEW.stats_real_sec), - group_mtime=NULL - WHERE group_id=NEW.group_id; - ELSEIF NEW.job_status != 990 THEN - UPDATE mxq_group SET - stats_max_maxrss=GREATEST(stats_max_maxrss, NEW.stats_maxrss), - stats_max_utime_sec=GREATEST(stats_max_utime_sec, NEW.stats_utime_sec), - stats_max_stime_sec=GREATEST(stats_max_stime_sec, NEW.stats_stime_sec), - stats_max_real_sec=GREATEST(stats_max_real_sec, NEW.stats_real_sec), - group_mtime=NULL - WHERE group_id=NEW.group_id; + IF NEW.job_status != OLD.job_status THEN + IF NEW.job_status = 200 AND OLD.job_status IN (0, 100, 150) THEN + UPDATE mxq_group SET + group_jobs_inq=group_jobs_inq-1, + group_jobs_running=group_jobs_running+1, + group_slots_running=group_slots_running+NEW.host_slots, + group_mtime=NULL + WHERE group_id=NEW.group_id; + ELSEIF NEW.job_status IN (400, 750) AND OLD.job_status IN (200, 250, 300, 350) THEN + UPDATE mxq_group SET + group_slots_running=group_slots_running-NEW.host_slots, + group_jobs_running=group_jobs_running-1, + group_jobs_failed=group_jobs_failed+1, + stats_max_maxrss=GREATEST(stats_max_maxrss, NEW.stats_maxrss), + stats_max_utime_sec=GREATEST(stats_max_utime_sec, NEW.stats_utime_sec), + stats_max_stime_sec=GREATEST(stats_max_stime_sec, NEW.stats_stime_sec), + stats_max_real_sec=GREATEST(stats_max_real_sec, NEW.stats_real_sec), + group_mtime=NULL + WHERE group_id=NEW.group_id; + ELSEIF NEW.job_status = 990 AND OLD.job_status = 0 THEN + UPDATE mxq_group SET + group_jobs_inq=group_jobs_inq-1, + group_jobs_cancelled=group_jobs_cancelled+1, + group_mtime=NULL + WHERE group_id=NEW.group_id; + ELSEIF NEW.job_status = 999 AND OLD.job_status IN (200, 250) THEN + UPDATE mxq_group SET + group_slots_running=group_slots_running-NEW.host_slots, + group_jobs_running=group_jobs_running-1, + group_jobs_unknown=group_jobs_unknown+1, + group_mtime=NULL + WHERE group_id=NEW.group_id; + ELSEIF NEW.job_status = 999 AND OLD.job_status IN (400, 750) THEN + UPDATE mxq_group SET + group_slots_running=group_slots_running-NEW.host_slots, + group_jobs_failed=group_jobs_failed-1, + group_jobs_unknown=group_jobs_unknown+1, + group_mtime=NULL + WHERE group_id=NEW.group_id; + ELSEIF NEW.job_status = 1000 AND OLD.job_status IN (200, 250, 300, 350) THEN + UPDATE mxq_group SET + group_slots_running=group_slots_running-NEW.host_slots, + group_jobs_running=group_jobs_running-1, + group_jobs_finished=group_jobs_finished+1, + stats_max_maxrss=GREATEST(stats_max_maxrss, NEW.stats_maxrss), + stats_max_utime_sec=GREATEST(stats_max_utime_sec, NEW.stats_utime_sec), + stats_max_stime_sec=GREATEST(stats_max_stime_sec, NEW.stats_stime_sec), + stats_max_real_sec=GREATEST(stats_max_real_sec, NEW.stats_real_sec), + group_mtime=NULL + WHERE group_id=NEW.group_id; + ELSEIF NEW.job_status != 990 THEN + UPDATE mxq_group SET + stats_max_maxrss=GREATEST(stats_max_maxrss, NEW.stats_maxrss), + stats_max_utime_sec=GREATEST(stats_max_utime_sec, NEW.stats_utime_sec), + stats_max_stime_sec=GREATEST(stats_max_stime_sec, NEW.stats_stime_sec), + stats_max_real_sec=GREATEST(stats_max_real_sec, NEW.stats_real_sec), + group_mtime=NULL + WHERE group_id=NEW.group_id; + END IF; END IF; END; | DELIMITER ; UNLOCK TABLES; - - - - - - - - DROP TABLE mxq_server; CREATE TABLE IF NOT EXISTS mxq_server ( host_id INT4 UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, @@ -208,7 +242,5 @@ CREATE TABLE IF NOT EXISTS mxq_server ( server_start TIMESTAMP DEFAULT 0, server_stop TIMESTAMP DEFAULT 0, - - );