From 35e631422306294276128c3b81c77f0d72c6ec4f Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 09:18:58 +0200 Subject: [PATCH 01/11] test_mx_util: Test mx_strvec functions used by daemon The only two functions from the mx_strvec familiy which are used by mxqd and mxqsub have no tests currently. Add test. --- test_mx_util.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test_mx_util.c b/test_mx_util.c index 54ba7e03..055b181e 100644 --- a/test_mx_util.c +++ b/test_mx_util.c @@ -406,6 +406,18 @@ static void test_mx_strvec() { assert(strcmp(str,"AxxB")==0); free(str); mx_strvec_free(strvec); + + char *test[] = { "AAA", "", "bbb", NULL}; + str = mx_strvec_to_str(test); + assert(strcmp(str,"AAA\\0\\0bbb\\0")==0); + strvec = mx_strvec_from_str(str); + assert( strcmp(strvec[0], "AAA") == 0 ); + assert( strcmp(strvec[1], "") == 0 ); + assert( strcmp(strvec[2], "bbb") == 0 ); + assert( strvec[3] == NULL); + + free(str); + free(strvec); } static void test_mx_strcat() { From d954e89a2be4108d85265521b54e69cba7f4e6f8 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 09:20:29 +0200 Subject: [PATCH 02/11] test_mx_util: Remove mx_strvec cache test Remove test for a "cache bug", as we are going to remove the mx_strvec cache feature in the next commit. --- test_mx_util.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/test_mx_util.c b/test_mx_util.c index 055b181e..2a3191a2 100644 --- a/test_mx_util.c +++ b/test_mx_util.c @@ -348,30 +348,6 @@ static void test_mx_strscan(void) mx_proc_pid_stat_free_content(pps); } -static void test_mx_strvec_cachebug() { - char **strvec; - char **strvec2; - char *str; - - strvec = mx_strvec_new(); - assert(mx_strvec_length(strvec) == 0); - - mx_strvec_push_str(&strvec, "Eins"); - assert(mx_strvec_length(strvec) == 1); - - str = mx_strvec_to_str(strvec); - assert(mx_streq(str, "Eins\\0")); - - free(strvec); /* do not set to NULL for cache bug testing */ - - strvec2 = mx_strvec_new(); - assert(mx_strvec_length(strvec2) == 0); - if (strvec != strvec2) - fprintf(stderr, "Warning: Can't test strvec cache bug. Skipping.\n"); - mx_free_null(strvec2); - mx_free_null(str); -} - static void test_mx_strvec() { char **strvec; char *str; @@ -562,7 +538,6 @@ int main(int argc, char *argv[]) test_mx_read_first_line_from_file(); test_mx_strscan(); test_mx_strvec(); - test_mx_strvec_cachebug(); test_mx_strcat(); test_mx_cpuset(); test_listsort(); From 102f936a807b1ce8781a273ce290f802eefdf08a Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 09:23:52 +0200 Subject: [PATCH 03/11] mx_util: Remove mx_strvec cache The idea of the cache was to store the address and the number of the elements of a single vector in variables each time the length was determined. However, this aliases the pointer to the string vector owned by the user. If the users free()s his pointer to the vector, the cached pointer becomes invalid. An approach would be to require the user to always use a library routine to free the vector. This library routine would need to invalidate the static alias pointer, too. However, the assumed performance win doesn't seem worth the complexity. Remove the cache code. --- mx_util.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/mx_util.c b/mx_util.c index b686ba11..ebb76007 100644 --- a/mx_util.c +++ b/mx_util.c @@ -19,8 +19,6 @@ #include "mx_log.h" #include "mx_util.h" -static inline size_t mx_strvec_length_cache(char **strvec, int32_t len); - static inline int _mx_strbeginswith(char *str, const char *start, char **endptr, short ignore_case) { size_t len; @@ -933,40 +931,14 @@ void *mx_calloc_forever_sec(size_t nmemb, size_t size, unsigned int time) char **mx_strvec_new(void) { char **strvec; - size_t len; strvec = calloc(sizeof(*strvec), 1); if (!strvec) return NULL; - len = mx_strvec_length_cache(strvec, -1); - if (len != -1) - mx_strvec_length_cache(strvec, 0); - return strvec; } -static inline size_t mx_strvec_length_cache(char **strvec, int32_t len) -{ - static char ** sv = NULL; - static size_t l = 0; - - if (likely(len == -1)) { - if (likely(sv == strvec)) { - return l; - } - return -1; - } - - if (likely(sv == strvec)) { - l = len; - } else { - sv = strvec; - l = len; - } - return l; -} - size_t mx_strvec_length(char ** strvec) { char ** sv; @@ -975,15 +947,9 @@ size_t mx_strvec_length(char ** strvec) assert(strvec); sv = strvec; - - len = mx_strvec_length_cache(sv, -1); - if (len != -1) - return len; - for (; *sv; sv++); len = sv-strvec; - mx_strvec_length_cache(sv, len); return len; } @@ -1007,8 +973,6 @@ int mx_strvec_push_str(char *** strvecp, char * str) sv[len++] = str; sv[len] = NULL; - mx_strvec_length_cache(sv, len); - *strvecp = sv; return 1; @@ -1035,8 +999,6 @@ int mx_strvec_push_strvec(char ***strvecp, char **strvec) memcpy(sv+len1, strvec, sizeof(*strvec) * (len2 + 1)); - mx_strvec_length_cache(sv, len1+len2); - *strvecp = sv; return 1; From 5a07c9e586c576a3562c2f2f18c78a2a5905265f Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 10:29:52 +0200 Subject: [PATCH 04/11] mxqd: Don't try to unmount noexisting job tmpdir Only unmount and remove job temporary directories for jobs, which actually requested on to avoid meaningless warnings in the logfile. --- mxqd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mxqd.c b/mxqd.c index 73d2eaaa..abddbc6b 100644 --- a/mxqd.c +++ b/mxqd.c @@ -1862,7 +1862,8 @@ static int job_has_finished(struct mxq_server *server, struct mxq_group *group, job=&jlist->job; - unmount_job_tmpdir(job->job_id); + if (group->job_tmpdir_size > 0) + unmount_job_tmpdir(job->job_id); mxq_set_job_status_exited(server->mysql, job); From 76ca06e60278d501be002c6b933f137c3b40136f Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 17:15:21 +0200 Subject: [PATCH 05/11] Build: Fix dependencies for mxqset --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 921d3409..a758fe43 100644 --- a/Makefile +++ b/Makefile @@ -418,10 +418,10 @@ clean: CLEAN += mxqadmin.o ### mxqset.o ---------------------------------------------------------- -mxqsset.o: $(mx_mysql.h) -mxqsset.o: $(keywordset.h) -mxqkill.o: $(mxq.h) -mxqkill.o: $(mxq_group.h) +mxqset.o: $(mx_mysql.h) +mxqset.o: $(keywordset.h) +mxqset.o: $(mxq.h) +mxqset.o: $(mxq_group.h) mxqset.o: CFLAGS += $(CFLAGS_MYSQL) clean: CLEAN += mxqsset.o From 9c895a216e7ee5c46812e0d7cbb2d4ec5a9d222e Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 16:49:39 +0200 Subject: [PATCH 06/11] sql: Add column daemon_flags We'd like to have a daemon flag, namely "exclusive". This flag should be published by the daemon into the database, so that is visible to the web interface. Although we currently need only a single boolean flag, make it a integer, so that we can add more flags at a later time without changing the database scheme. --- mysql/create_tables.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql/create_tables.sql b/mysql/create_tables.sql index 3cf4f348..ba6e800f 100644 --- a/mysql/create_tables.sql +++ b/mysql/create_tables.sql @@ -165,6 +165,8 @@ CREATE TABLE IF NOT EXISTS mxq_daemon ( daemon_start TIMESTAMP NOT NULL DEFAULT 0, daemon_stop TIMESTAMP NOT NULL DEFAULT 0, + daemon_flags INT4 NOT NULL DEFAULT 0, + INDEX (daemon_name(64)), INDEX (hostname(64)) ); From d93744f46a154fa8847fa84be441c2cf8a130f58 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 16:50:03 +0200 Subject: [PATCH 07/11] web: Add column daemon_flags --- web/pages/mxq/mxq.in | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/web/pages/mxq/mxq.in b/web/pages/mxq/mxq.in index 47e672fa..184f233e 100755 --- a/web/pages/mxq/mxq.in +++ b/web/pages/mxq/mxq.in @@ -776,7 +776,7 @@ sub server() { daemon_memory_limit_slot_soft daemon_memory_limit_slot_hard daemon_jobs_running daemon_slots_running daemon_threads_running daemon_memory_used - mtime daemon_start daemon_stop + mtime daemon_start daemon_stop daemon_flags ); my $sth=$dbh->prepare('SELECT '.join(',',@cols).' FROM mxq_daemon WHERE status<=200 ORDER BY hostname,daemon_name'); @@ -807,6 +807,7 @@ sub server() { # 'mtime', # 'start', # 'stop', + 'F' ])); my %S; @@ -817,7 +818,7 @@ sub server() { $daemon_memory_limit_slot_soft,$daemon_memory_limit_slot_hard, $daemon_jobs_running,$daemon_slots_running, $daemon_threads_running,$daemon_memory_used, - $mtime,$daemon_start,$daemon_stop + $mtime,$daemon_start,$daemon_stop,$daemon_flags ) = @$row; $hostname =~s/\.molgen\.mpg\.de$//; @@ -851,18 +852,19 @@ sub server() { # $q->td($mtime), # $q->td($daemon_start), # $q->td($daemon_stop), + $q->td($daemon_flags ? 'X' : ' ' ), ); } map { - $out.=$q->Tr( $q->td(0),$q->td('-'),$q->td('no mxqd'),$q->td($_),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),); + $out.=$q->Tr( $q->td(0),$q->td('-'),$q->td('no mxqd'),$q->td($_),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' ')); } keys %{$dead_hosts}; - $out.=$q->Tr($q->td({colspan=>14},' ')); + $out.=$q->Tr($q->td({colspan=>15},' ')); my $dist = join(', ',map {"$S{daemon_slots_dist}->{$_}x$_"} sort {$b <=> $a} keys %{$S{daemon_slots_dist}}); $out.=$q->Tr( $q->td({class=>'center', colspan=>3},$S{servers}.' servers'),$q->td($dist), $q->td({class=>'center', colspan=>3},$S{daemon_slots}.' cores'),$q->td({class=>'number'},size($S{daemon_memory_sum}*1000**2)),$q->td(' '),$q->td(' '),$q->td(' '), - $q->td({class=>'number'},$S{daemon_slots_running}),$q->td(' '),$q->td({class=>'number'},size($S{daemon_memory_used_sum}*1000**2)),); + $q->td({class=>'number'},$S{daemon_slots_running}),$q->td(' '),$q->td({class=>'number'},size($S{daemon_memory_used_sum}*1000**2)),$q->td(' ')); $out.=''; return $out; From da1f32cbd0c269db765b0ceb5c965c0d46439b0e Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 16:50:28 +0200 Subject: [PATCH 08/11] mxq_daemon.h: Add column daemon_flags --- mxq_daemon.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mxq_daemon.h b/mxq_daemon.h index 5676d7fb..8710fac0 100644 --- a/mxq_daemon.h +++ b/mxq_daemon.h @@ -46,6 +46,8 @@ struct mxq_daemon { struct timeval daemon_start; struct timeval daemon_stop; + + int daemon_flags; }; void mxq_daemon_free_content(struct mxq_daemon *daemon); From 290468e8d7616c384b92b6de6ff9b0d707b4a8e0 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 16:50:32 +0200 Subject: [PATCH 09/11] mxq_daemon.c: Add column daemon_flags --- mxq_daemon.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mxq_daemon.c b/mxq_daemon.c index 432fd532..b7afcec0 100644 --- a/mxq_daemon.c +++ b/mxq_daemon.c @@ -34,7 +34,8 @@ " daemon_memory_used," \ " UNIX_TIMESTAMP(mtime) as mtime," \ " UNIX_TIMESTAMP(daemon_start) as daemon_start," \ - " UNIX_TIMESTAMP(daemon_stop) as daemon_stop" + " UNIX_TIMESTAMP(daemon_stop) as daemon_stop," \ + " daemon_flags" #undef _to_string #undef status_str @@ -75,6 +76,8 @@ static int bind_result_daemon_fields(struct mx_mysql_bind *result, struct mxq_da res += mx_mysql_bind_var(result, idx++, int64, &(daemon->daemon_start.tv_sec)); res += mx_mysql_bind_var(result, idx++, int64, &(daemon->daemon_stop.tv_sec)); + res += mx_mysql_bind_var(result, idx++, int32, &(daemon->daemon_flags)); + return res; } @@ -136,7 +139,8 @@ int mxq_daemon_register(struct mx_mysql *mysql, struct mxq_daemon *daemon) " daemon_memory_used = 0," " mtime = NULL," " daemon_start = CURRENT_TIMESTAMP()," - " daemon_stop = 0" + " daemon_stop = 0," + " daemon_flags = ?" ); if (!stmt) { mx_log_err("mx_mysql_statement_prepare(): %m"); @@ -161,6 +165,7 @@ int mxq_daemon_register(struct mx_mysql *mysql, struct mxq_daemon *daemon) res += mx_mysql_statement_param_bind(stmt, idx++, uint64, &(daemon->daemon_memory_limit_slot_soft)); res += mx_mysql_statement_param_bind(stmt, idx++, uint64, &(daemon->daemon_memory_limit_slot_hard)); + res += mx_mysql_statement_param_bind(stmt, idx++, int32, &(daemon->daemon_flags)); assert(res ==0); From d80198d8f412b36275826d80e2bc84d44e78eef8 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 16:50:59 +0200 Subject: [PATCH 10/11] mxqd.c: Add --exclusive option When a daemon is started, with --exclusive it will set daemon_flags to 1 to indicate, that it is running in exclusive mode. In exclusive mode, the daemon should only start jobs which have an implicit whitelist (`mxqsub --whitelist`) which includes the daemons name. This is implemented in the next commit. --- mxqd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mxqd.c b/mxqd.c index abddbc6b..e64f4139 100644 --- a/mxqd.c +++ b/mxqd.c @@ -102,6 +102,7 @@ static void print_usage(void) " --debug default: info log level\n" "\n" " --recover-only (recover from crash and exit)\n" + " --exclusive run in exclusive mode\n" "\n" " --initial-path default: %s\n" " --initial-tmpdir default: %s\n" @@ -341,6 +342,7 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) char arg_daemonize = 0; char arg_nolog = 0; char arg_recoveronly = 0; + int arg_exclusive = 0; char *str_bootid; int opt; unsigned long arg_threads_total = 0; @@ -378,6 +380,7 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) MX_OPTION_OPTIONAL_ARG("mysql-default-file", 'M'), MX_OPTION_OPTIONAL_ARG("mysql-default-group", 'S'), MX_OPTION_OPTIONAL_ARG("max-time", 't'), + MX_OPTION_NO_ARG("exclusive", 11), MX_OPTION_END }; @@ -531,6 +534,10 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) return -EX_USAGE; } break; + + case 11: + arg_exclusive = 1; + break; } } @@ -712,6 +719,7 @@ int server_init(struct mxq_server *server, int argc, char *argv[]) daemon->daemon_maxtime = server->maxtime; daemon->daemon_memory_limit_slot_soft = server->memory_limit_slot_soft; daemon->daemon_memory_limit_slot_hard = server->memory_limit_slot_hard; + daemon->daemon_flags = arg_exclusive; return 0; } From 0c22c65e7188367aeec6bb803a9341a2c1f89b69 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Fri, 17 Apr 2020 17:15:51 +0200 Subject: [PATCH 11/11] mxqd.c: Require whitelist on exclusive daemon If the daemon was stared with `--exclusive`, only start jobs which have the daemon in their whitelist. --- mxqd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mxqd.c b/mxqd.c index e64f4139..627959a2 100644 --- a/mxqd.c +++ b/mxqd.c @@ -1308,6 +1308,8 @@ static int server_is_qualified(struct mxq_server *server, struct mxq_group *grou is_qualified = 1; keywordset_free(kws); } else { + if (server->daemon.daemon_flags) + return 0; // exclusive is_qualified = 1; }