/* Used in job functions for getting the database index based off the * submit time, job and assoc id. 0 is returned if none is found */ static int _get_db_index(mysql_conn_t *mysql_conn, time_t submit, uint32_t jobid, uint32_t associd) { MYSQL_RES *result = NULL; MYSQL_ROW row; int db_index = 0; char *query = xstrdup_printf("select job_db_inx from \"%s_%s\" where " "time_submit=%d and id_job=%u " "and id_assoc=%u", mysql_conn->cluster_name, job_table, (int)submit, jobid, associd); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); return 0; } xfree(query); row = mysql_fetch_row(result); if (!row) { mysql_free_result(result); debug4("We can't get a db_index for this combo, " "time_submit=%d and id_job=%u and id_assoc=%u. " "We must not have heard about the start yet, " "no big deal, we will get one right after this.", (int)submit, jobid, associd); return 0; } db_index = slurm_atoul(row[0]); mysql_free_result(result); return db_index; }
static int _reset_default_wckey(mysql_conn_t *mysql_conn, slurmdb_wckey_rec_t *wckey) { time_t now = time(NULL); int rc = SLURM_SUCCESS; char *query = NULL; MYSQL_RES *result = NULL; MYSQL_ROW row; if ((wckey->is_def != 1) || !wckey->cluster || !wckey->user || !wckey->name) return SLURM_ERROR; xstrfmtcat(query, "update \"%s_%s\" set is_def=0, mod_time=%ld " "where (user='******' && wckey_name!='%s' && is_def=1);" "select id_wckey from \"%s_%s\" " "where (user='******' && wckey_name!='%s' && is_def=1);", wckey->cluster, wckey_table, (long)now, wckey->user, wckey->name, wckey->cluster, wckey_table, wckey->user, wckey->name); if (debug_flags & DEBUG_FLAG_DB_WCKEY) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret(mysql_conn, query, 1))) { xfree(query); rc = SLURM_ERROR; goto end_it; } xfree(query); while ((row = mysql_fetch_row(result))) { slurmdb_wckey_rec_t *mod_wckey = xmalloc(sizeof(slurmdb_wckey_rec_t)); slurmdb_init_wckey_rec(mod_wckey, 0); mod_wckey->id = slurm_atoul(row[0]); mod_wckey->is_def = 0; if (addto_update_list(mysql_conn->update_list, SLURMDB_MODIFY_WCKEY, mod_wckey) != SLURM_SUCCESS) { slurmdb_destroy_wckey_rec(mod_wckey); error("couldn't add to the update list"); rc = SLURM_ERROR; break; } } mysql_free_result(result); end_it: return rc; }
static void *_cluster_rollup_usage(void *arg) { local_rollup_t *local_rollup = (local_rollup_t *)arg; int rc = SLURM_SUCCESS; char timer_str[128]; mysql_conn_t mysql_conn; MYSQL_RES *result = NULL; MYSQL_ROW row; char *query = NULL; struct tm start_tm; struct tm end_tm; time_t my_time = local_rollup->sent_end; time_t last_hour = local_rollup->sent_start; time_t last_day = local_rollup->sent_start; time_t last_month = local_rollup->sent_start; time_t hour_start; time_t hour_end; time_t day_start; time_t day_end; time_t month_start; time_t month_end; DEF_TIMERS; char *update_req_inx[] = { "hourly_rollup", "daily_rollup", "monthly_rollup" }; enum { UPDATE_HOUR, UPDATE_DAY, UPDATE_MONTH, UPDATE_COUNT }; memset(&mysql_conn, 0, sizeof(mysql_conn_t)); mysql_conn.rollback = 1; mysql_conn.conn = local_rollup->mysql_conn->conn; slurm_mutex_init(&mysql_conn.lock); /* Each thread needs it's own connection we can't use the one * sent from the parent thread. */ rc = check_connection(&mysql_conn); if (rc != SLURM_SUCCESS) goto end_it; if (!local_rollup->sent_start) { char *tmp = NULL; int i=0; xstrfmtcat(tmp, "%s", update_req_inx[i]); for(i=1; i<UPDATE_COUNT; i++) { xstrfmtcat(tmp, ", %s", update_req_inx[i]); } query = xstrdup_printf("select %s from \"%s_%s\"", tmp, local_rollup->cluster_name, last_ran_table); xfree(tmp); debug4("%d(%s:%d) query\n%s", mysql_conn.conn, THIS_FILE, __LINE__, query); if (!(result = mysql_db_query_ret(&mysql_conn, query, 0))) { xfree(query); rc = SLURM_ERROR; goto end_it; } xfree(query); row = mysql_fetch_row(result); if (row) { last_hour = slurm_atoul(row[UPDATE_HOUR]); last_day = slurm_atoul(row[UPDATE_DAY]); last_month = slurm_atoul(row[UPDATE_MONTH]); mysql_free_result(result); } else { time_t now = time(NULL); time_t lowest = now; mysql_free_result(result); query = xstrdup_printf( "select time_start from \"%s_%s\" " "where node_name='' order by " "time_start asc limit 1;", local_rollup->cluster_name, event_table); debug3("%d(%s:%d) query\n%s", mysql_conn.conn, THIS_FILE, __LINE__, query); if (!(result = mysql_db_query_ret( &mysql_conn, query, 0))) { xfree(query); rc = SLURM_ERROR; goto end_it; } xfree(query); if ((row = mysql_fetch_row(result))) { time_t check = slurm_atoul(row[0]); if (check < lowest) lowest = check; } mysql_free_result(result); /* If we don't have any events like adding a * cluster this will not work correctly, so we * will insert now as a starting point. */ query = xstrdup_printf( "insert into \"%s_%s\" " "(hourly_rollup, daily_rollup, monthly_rollup) " "values (%ld, %ld, %ld);", local_rollup->cluster_name, last_ran_table, lowest, lowest, lowest); debug3("%d(%s:%d) query\n%s", mysql_conn.conn, THIS_FILE, __LINE__, query); rc = mysql_db_query(&mysql_conn, query); xfree(query); if (rc != SLURM_SUCCESS) { rc = SLURM_ERROR; goto end_it; } if (lowest == now) { debug("Cluster %s not registered, " "not doing rollup", local_rollup->cluster_name); rc = SLURM_SUCCESS; goto end_it; } last_hour = last_day = last_month = lowest; } } if (!my_time) my_time = time(NULL); /* test month gap */ /* last_hour = 1212299999; */ /* last_day = 1212217200; */ /* last_month = 1212217200; */ /* my_time = 1212307200; */ /* last_hour = 1211475599; */ /* last_day = 1211475599; */ /* last_month = 1211475599; */ // last_hour = 1211403599; // last_hour = 1206946800; // last_day = 1207033199; // last_day = 1197033199; // last_month = 1204358399; if (!localtime_r(&last_hour, &start_tm)) { error("Couldn't get localtime from hour start %ld", last_hour); rc = SLURM_ERROR; goto end_it; } if (!localtime_r(&my_time, &end_tm)) { error("Couldn't get localtime from hour end %ld", my_time); rc = SLURM_ERROR; goto end_it; } /* Below and anywhere in a rollup plugin when dealing with * epoch times we need to set the tm_isdst = -1 so we don't * have to worry about the time changes. Not setting it to -1 * will cause problems in the day and month with the date change. */ start_tm.tm_sec = 0; start_tm.tm_min = 0; start_tm.tm_isdst = -1; hour_start = mktime(&start_tm); end_tm.tm_sec = 0; end_tm.tm_min = 0; end_tm.tm_isdst = -1; hour_end = mktime(&end_tm); /* info("hour start %s", slurm_ctime(&hour_start)); */ /* info("hour end %s", slurm_ctime(&hour_end)); */ /* info("diff is %d", hour_end-hour_start); */ slurm_mutex_lock(&rollup_lock); global_last_rollup = hour_end; slurm_mutex_unlock(&rollup_lock); /* set up the day period */ if (!localtime_r(&last_day, &start_tm)) { error("Couldn't get localtime from day %ld", last_day); rc = SLURM_ERROR; goto end_it; } start_tm.tm_sec = 0; start_tm.tm_min = 0; start_tm.tm_hour = 0; start_tm.tm_isdst = -1; day_start = mktime(&start_tm); end_tm.tm_hour = 0; end_tm.tm_isdst = -1; day_end = mktime(&end_tm); /* info("day start %s", slurm_ctime(&day_start)); */ /* info("day end %s", slurm_ctime(&day_end)); */ /* info("diff is %d", day_end-day_start); */ /* set up the month period */ if (!localtime_r(&last_month, &start_tm)) { error("Couldn't get localtime from month %ld", last_month); rc = SLURM_ERROR; goto end_it; } start_tm.tm_sec = 0; start_tm.tm_min = 0; start_tm.tm_hour = 0; start_tm.tm_mday = 1; start_tm.tm_isdst = -1; month_start = mktime(&start_tm); end_tm.tm_sec = 0; end_tm.tm_min = 0; end_tm.tm_hour = 0; end_tm.tm_mday = 1; end_tm.tm_isdst = -1; month_end = mktime(&end_tm); /* info("month start %s", slurm_ctime(&month_start)); */ /* info("month end %s", slurm_ctime(&month_end)); */ /* info("diff is %d", month_end-month_start); */ if ((hour_end - hour_start) > 0) { START_TIMER; rc = as_mysql_hourly_rollup(&mysql_conn, local_rollup->cluster_name, hour_start, hour_end, local_rollup->archive_data); snprintf(timer_str, sizeof(timer_str), "hourly_rollup for %s", local_rollup->cluster_name); END_TIMER3(timer_str, 5000000); if (rc != SLURM_SUCCESS) goto end_it; } if ((day_end - day_start) > 0) { START_TIMER; rc = as_mysql_daily_rollup(&mysql_conn, local_rollup->cluster_name, day_start, day_end, local_rollup->archive_data); snprintf(timer_str, sizeof(timer_str), "daily_rollup for %s", local_rollup->cluster_name); END_TIMER3(timer_str, 5000000); if (rc != SLURM_SUCCESS) goto end_it; } if ((month_end - month_start) > 0) { START_TIMER; rc = as_mysql_monthly_rollup(&mysql_conn, local_rollup->cluster_name, month_start, month_end, local_rollup->archive_data); snprintf(timer_str, sizeof(timer_str), "monthly_rollup for %s", local_rollup->cluster_name); END_TIMER3(timer_str, 5000000); if (rc != SLURM_SUCCESS) goto end_it; } if ((hour_end - hour_start) > 0) { /* If we have a sent_end do not update the last_run_table */ if (!local_rollup->sent_end) query = xstrdup_printf( "update \"%s_%s\" set hourly_rollup=%ld", local_rollup->cluster_name, last_ran_table, hour_end); } else debug2("No need to roll cluster %s this hour %ld <= %ld", local_rollup->cluster_name, hour_end, hour_start); if ((day_end - day_start) > 0) { if (query && !local_rollup->sent_end) xstrfmtcat(query, ", daily_rollup=%ld", day_end); else if (!local_rollup->sent_end) query = xstrdup_printf( "update \"%s_%s\" set daily_rollup=%ld", local_rollup->cluster_name, last_ran_table, day_end); } else debug2("No need to roll cluster %s this day %ld <= %ld", local_rollup->cluster_name, day_end, day_start); if ((month_end - month_start) > 0) { if (query && !local_rollup->sent_end) xstrfmtcat(query, ", monthly_rollup=%ld", month_end); else if (!local_rollup->sent_end) query = xstrdup_printf( "update \"%s_%s\" set monthly_rollup=%ld", local_rollup->cluster_name, last_ran_table, month_end); } else debug2("No need to roll cluster %s this month %ld <= %ld", local_rollup->cluster_name, month_end, month_start); if (query) { debug3("%d(%s:%d) query\n%s", mysql_conn.conn, THIS_FILE, __LINE__, query); rc = mysql_db_query(&mysql_conn, query); xfree(query); } end_it: if (rc == SLURM_SUCCESS) { if (mysql_db_commit(&mysql_conn)) { error("Couldn't commit rollup of cluster %s", local_rollup->cluster_name); rc = SLURM_ERROR; } } else { error("Cluster %s rollup failed", local_rollup->cluster_name); if (mysql_db_rollback(&mysql_conn)) error("rollback failed"); } mysql_db_close_db_connection(&mysql_conn); slurm_mutex_destroy(&mysql_conn.lock); slurm_mutex_lock(local_rollup->rolledup_lock); (*local_rollup->rolledup)++; if ((rc != SLURM_SUCCESS) && ((*local_rollup->rc) == SLURM_SUCCESS)) (*local_rollup->rc) = rc; pthread_cond_signal(local_rollup->rolledup_cond); slurm_mutex_unlock(local_rollup->rolledup_lock); xfree(local_rollup); return NULL; }
static local_cluster_usage_t *_setup_cluster_usage(mysql_conn_t *mysql_conn, char *cluster_name, time_t curr_start, time_t curr_end, List cluster_down_list) { local_cluster_usage_t *c_usage = NULL; char *query = NULL; MYSQL_RES *result = NULL; MYSQL_ROW row; int i = 0; ListIterator c_itr = NULL; local_cluster_usage_t *loc_c_usage; char *event_req_inx[] = { "node_name", "cpu_count", "time_start", "time_end", "state", }; char *event_str = NULL; enum { EVENT_REQ_NAME, EVENT_REQ_CPU, EVENT_REQ_START, EVENT_REQ_END, EVENT_REQ_STATE, EVENT_REQ_COUNT }; xstrfmtcat(event_str, "%s", event_req_inx[i]); for(i=1; i<EVENT_REQ_COUNT; i++) { xstrfmtcat(event_str, ", %s", event_req_inx[i]); } /* first get the events during this time. All that is * except things with the maintainance flag set in the * state. We handle those later with the reservations. */ query = xstrdup_printf("select %s from \"%s_%s\" where " "!(state & %d) && (time_start < %ld " "&& (time_end >= %ld " "|| time_end = 0)) " "order by node_name, time_start", event_str, cluster_name, event_table, NODE_STATE_MAINT, curr_end, curr_start); xfree(event_str); if (debug_flags & DEBUG_FLAG_DB_USAGE) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); return NULL; } xfree(query); c_itr = list_iterator_create(cluster_down_list); while ((row = mysql_fetch_row(result))) { time_t row_start = slurm_atoul(row[EVENT_REQ_START]); time_t row_end = slurm_atoul(row[EVENT_REQ_END]); uint32_t row_cpu = slurm_atoul(row[EVENT_REQ_CPU]); uint16_t state = slurm_atoul(row[EVENT_REQ_STATE]); if (row_start < curr_start) row_start = curr_start; if (!row_end || row_end > curr_end) row_end = curr_end; /* Don't worry about it if the time is less * than 1 second. */ if ((row_end - row_start) < 1) continue; /* this means we are a cluster registration entry */ if (!row[EVENT_REQ_NAME][0]) { /* if the cpu count changes we will * only care about the last cpu count but * we will keep a total of the time for * all cpus to get the correct cpu time * for the entire period. */ if (state || !c_usage) { loc_c_usage = xmalloc( sizeof(local_cluster_usage_t)); loc_c_usage->cpu_count = row_cpu; loc_c_usage->total_time = (row_end - row_start) * row_cpu; loc_c_usage->start = row_start; loc_c_usage->end = row_end; /* If this has a state it means the slurmctld went down and we should put this on the list and remove any jobs from this time that were running later. */ if (state) list_append(cluster_down_list, loc_c_usage); else c_usage = loc_c_usage; loc_c_usage = NULL; } else { c_usage->cpu_count = row_cpu; c_usage->total_time += (row_end - row_start) * row_cpu; c_usage->end = row_end; } continue; } /* only record down time for the cluster we are looking for. If it was during this time period we would already have it. */ if (c_usage) { time_t local_start = row_start; time_t local_end = row_end; int seconds; if (c_usage->start > local_start) local_start = c_usage->start; if (c_usage->end < local_end) local_end = c_usage->end; seconds = (local_end - local_start); if (seconds > 0) { /* info("%p node %s adds " */ /* "(%d)(%ld-%ld) * %d = %"PRIu64" " */ /* "to %"PRIu64" (%s - %s)", */ /* c_usage, */ /* row[EVENT_REQ_NAME], */ /* seconds, */ /* local_end, local_start, */ /* row_cpu, */ /* seconds * (uint64_t)row_cpu, */ /* c_usage->d_cpu, */ /* slurm_ctime(&local_start), */ /* slurm_ctime(&local_end)); */ c_usage->d_cpu += seconds * (uint64_t)row_cpu; /* Now remove this time if there was a disconnected slurmctld during the down time. */ list_iterator_reset(c_itr); while ((loc_c_usage = list_next(c_itr))) { int temp_end = row_end; int temp_start = row_start; if (loc_c_usage->start > local_start) temp_start = loc_c_usage->start; if (loc_c_usage->end < temp_end) temp_end = loc_c_usage->end; seconds = (temp_end - temp_start); if (seconds < 1) continue; seconds *= row_cpu; if (seconds >= loc_c_usage->total_time) loc_c_usage->total_time = 0; else loc_c_usage->total_time -= seconds; /* info("Node %s was down for " */ /* "%d seconds while " */ /* "cluster %s's slurmctld " */ /* "wasn't responding %"PRIu64, */ /* row[EVENT_REQ_NAME], */ /* seconds, cluster_name, */ /* loc_c_usage->total_time); */ } } } } mysql_free_result(result); list_iterator_destroy(c_itr); return c_usage; }
extern List as_mysql_get_cluster_events(mysql_conn_t *mysql_conn, uint32_t uid, slurmdb_event_cond_t *event_cond) { char *query = NULL; char *extra = NULL; char *tmp = NULL; List ret_list = NULL; ListIterator itr = NULL; char *object = NULL; int set = 0; int i=0; MYSQL_RES *result = NULL; MYSQL_ROW row; time_t now = time(NULL); List use_cluster_list = as_mysql_cluster_list; /* if this changes you will need to edit the corresponding enum */ char *event_req_inx[] = { "cluster_nodes", "node_name", "state", "time_start", "time_end", "reason", "reason_uid", "tres", }; enum { EVENT_REQ_CNODES, EVENT_REQ_NODE, EVENT_REQ_STATE, EVENT_REQ_START, EVENT_REQ_END, EVENT_REQ_REASON, EVENT_REQ_REASON_UID, EVENT_REQ_TRES, EVENT_REQ_COUNT }; if (check_connection(mysql_conn) != SLURM_SUCCESS) return NULL; if (!event_cond) goto empty; if (event_cond->cpus_min) { if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); if (event_cond->cpus_max) { xstrfmtcat(extra, "count between %u and %u)", event_cond->cpus_min, event_cond->cpus_max); } else { xstrfmtcat(extra, "count='%u')", event_cond->cpus_min); } } switch(event_cond->event_type) { case SLURMDB_EVENT_ALL: break; case SLURMDB_EVENT_CLUSTER: if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); xstrcat(extra, "node_name = '')"); break; case SLURMDB_EVENT_NODE: if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); xstrcat(extra, "node_name != '')"); break; default: error("Unknown event %u doing all", event_cond->event_type); break; } if (event_cond->node_list && list_count(event_cond->node_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(event_cond->node_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "node_name='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (event_cond->period_start) { if (!event_cond->period_end) event_cond->period_end = now; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); xstrfmtcat(extra, "(time_start < %ld) " "&& (time_end >= %ld || time_end = 0))", event_cond->period_end, event_cond->period_start); } if (event_cond->reason_list && list_count(event_cond->reason_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(event_cond->reason_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "reason like '%%%s%%'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (event_cond->reason_uid_list && list_count(event_cond->reason_uid_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(event_cond->reason_uid_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "reason_uid='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (event_cond->state_list && list_count(event_cond->state_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(event_cond->state_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "state='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (event_cond->cluster_list && list_count(event_cond->cluster_list)) use_cluster_list = event_cond->cluster_list; empty: xfree(tmp); xstrfmtcat(tmp, "%s", event_req_inx[0]); for(i=1; i<EVENT_REQ_COUNT; i++) { xstrfmtcat(tmp, ", %s", event_req_inx[i]); } if (use_cluster_list == as_mysql_cluster_list) slurm_mutex_lock(&as_mysql_cluster_list_lock); ret_list = list_create(slurmdb_destroy_event_rec); itr = list_iterator_create(use_cluster_list); while ((object = list_next(itr))) { query = xstrdup_printf("select %s from \"%s_%s\"", tmp, object, event_table); if (extra) xstrfmtcat(query, " %s", extra); if (debug_flags & DEBUG_FLAG_DB_ASSOC) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); if (mysql_errno(mysql_conn->db_conn) != ER_NO_SUCH_TABLE) { FREE_NULL_LIST(ret_list); ret_list = NULL; } break; } xfree(query); while ((row = mysql_fetch_row(result))) { slurmdb_event_rec_t *event = xmalloc(sizeof(slurmdb_event_rec_t)); list_append(ret_list, event); event->cluster = xstrdup(object); if (row[EVENT_REQ_NODE] && row[EVENT_REQ_NODE][0]) { event->node_name = xstrdup(row[EVENT_REQ_NODE]); event->event_type = SLURMDB_EVENT_NODE; } else event->event_type = SLURMDB_EVENT_CLUSTER; event->state = slurm_atoul(row[EVENT_REQ_STATE]); event->period_start = slurm_atoul(row[EVENT_REQ_START]); event->period_end = slurm_atoul(row[EVENT_REQ_END]); if (row[EVENT_REQ_REASON] && row[EVENT_REQ_REASON][0]) event->reason = xstrdup(row[EVENT_REQ_REASON]); event->reason_uid = slurm_atoul(row[EVENT_REQ_REASON_UID]); if (row[EVENT_REQ_CNODES] && row[EVENT_REQ_CNODES][0]) event->cluster_nodes = xstrdup(row[EVENT_REQ_CNODES]); if (row[EVENT_REQ_TRES] && row[EVENT_REQ_TRES][0]) event->tres_str = xstrdup(row[EVENT_REQ_TRES]); } mysql_free_result(result); } list_iterator_destroy(itr); xfree(tmp); xfree(extra); if (use_cluster_list == as_mysql_cluster_list) slurm_mutex_unlock(&as_mysql_cluster_list_lock); return ret_list; }
extern int as_mysql_node_down(mysql_conn_t *mysql_conn, struct node_record *node_ptr, time_t event_time, char *reason, uint32_t reason_uid) { int rc = SLURM_SUCCESS; char *query = NULL; char *my_reason; MYSQL_RES *result = NULL; MYSQL_ROW row; if (check_connection(mysql_conn) != SLURM_SUCCESS) return ESLURM_DB_CONNECTION; if (!mysql_conn->cluster_name) { error("%s:%d no cluster name", THIS_FILE, __LINE__); return SLURM_ERROR; } if (!node_ptr) { error("No node_ptr given!"); return SLURM_ERROR; } if (!node_ptr->tres_str) { error("node ptr has no tres_list!"); return SLURM_ERROR; } query = xstrdup_printf("select state, reason from \"%s_%s\" where " "time_end=0 and node_name='%s';", mysql_conn->cluster_name, event_table, node_ptr->name); /* info("%d(%s:%d) query\n%s", */ /* mysql_conn->conn, THIS_FILE, __LINE__, query); */ result = mysql_db_query_ret(mysql_conn, query, 0); xfree(query); if (!result) return SLURM_ERROR; if (reason) my_reason = slurm_add_slash_to_quotes(reason); else my_reason = slurm_add_slash_to_quotes(node_ptr->reason); row = mysql_fetch_row(result); if (row && (node_ptr->node_state == slurm_atoul(row[0])) && my_reason && row[1] && !strcasecmp(my_reason, row[1])) { debug("as_mysql_node_down: no change needed %u == %s " "and %s == %s", node_ptr->node_state, row[0], my_reason, row[1]); xfree(my_reason); mysql_free_result(result); return SLURM_SUCCESS; } mysql_free_result(result); debug2("inserting %s(%s) with tres of '%s'", node_ptr->name, mysql_conn->cluster_name, node_ptr->tres_str); query = xstrdup_printf( "update \"%s_%s\" set time_end=%ld where " "time_end=0 and node_name='%s';", mysql_conn->cluster_name, event_table, event_time, node_ptr->name); /* If you are clean-restarting the controller over and over again you * could get records that are duplicates in the database. If * this is the case we will zero out the time_end we are * just filled in. This will cause the last time to be erased * from the last restart, but if you are restarting things * this often the pervious one didn't mean anything anyway. * This way we only get one for the last time we let it run. */ xstrfmtcat(query, "insert into \"%s_%s\" " "(node_name, state, tres, time_start, " "reason, reason_uid) " "values ('%s', %u, '%s', %ld, '%s', %u) " "on duplicate key update time_end=0;", mysql_conn->cluster_name, event_table, node_ptr->name, node_ptr->node_state, node_ptr->tres_str, event_time, my_reason, reason_uid); debug2("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); rc = mysql_db_query(mysql_conn, query); xfree(query); xfree(my_reason); return rc; }
static int _cluster_get_jobs(mysql_conn_t *mysql_conn, slurmdb_user_rec_t *user, slurmdb_job_cond_t *job_cond, char *cluster_name, char *job_fields, char *step_fields, char *sent_extra, bool is_admin, int only_pending, List sent_list) { char *query = NULL; char *extra = xstrdup(sent_extra); uint16_t private_data = slurm_get_private_data(); slurmdb_selected_step_t *selected_step = NULL; MYSQL_RES *result = NULL, *step_result = NULL; MYSQL_ROW row, step_row; slurmdb_job_rec_t *job = NULL; slurmdb_step_rec_t *step = NULL; time_t now = time(NULL); List job_list = list_create(slurmdb_destroy_job_rec); ListIterator itr = NULL, itr2 = NULL; List local_cluster_list = NULL; int set = 0; char *prefix="t2"; int rc = SLURM_SUCCESS; int last_id = -1, curr_id = -1; local_cluster_t *curr_cluster = NULL; /* This is here to make sure we are looking at only this user * if this flag is set. We also include any accounts they may be * coordinator of. */ if (!is_admin && (private_data & PRIVATE_DATA_JOBS)) { query = xstrdup_printf("select lft from \"%s_%s\" " "where user='******'", cluster_name, assoc_table, user->name); if (user->coord_accts) { slurmdb_coord_rec_t *coord = NULL; itr = list_iterator_create(user->coord_accts); while ((coord = list_next(itr))) { xstrfmtcat(query, " || acct='%s'", coord->name); } list_iterator_destroy(itr); } if (debug_flags & DEBUG_FLAG_DB_JOB) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(extra); xfree(query); rc = SLURM_ERROR; goto end_it; } xfree(query); set = 0; while ((row = mysql_fetch_row(result))) { if (set) { xstrfmtcat(extra, " || (%s between %s.lft and %s.rgt)", row[0], prefix, prefix); } else { set = 1; if (extra) xstrfmtcat(extra, " && ((%s between %s.lft " "and %s.rgt)", row[0], prefix, prefix); else xstrfmtcat(extra, " where ((%s between %s.lft " "and %s.rgt)", row[0], prefix, prefix); } } mysql_free_result(result); if (set) xstrcat(extra, ")"); else { xfree(extra); debug("User %s has no assocations, and is not admin, " "so not returning any jobs.", user->name); /* This user has no valid associations, so * they will not have any jobs. */ goto end_it; } } setup_job_cluster_cond_limits(mysql_conn, job_cond, cluster_name, &extra); query = xstrdup_printf("select %s from \"%s_%s\" as t1 " "left join \"%s_%s\" as t2 " "on t1.id_assoc=t2.id_assoc " "left join \"%s_%s\" as t3 " "on t1.id_resv=t3.id_resv && " "((t1.time_start && " "(t3.time_start < t1.time_start && " "(t3.time_end >= t1.time_start || " "t3.time_end = 0))) || " "((t3.time_start < t1.time_submit && " "(t3.time_end >= t1.time_submit || " "t3.time_end = 0)) || " "(t3.time_start > t1.time_submit)))", job_fields, cluster_name, job_table, cluster_name, assoc_table, cluster_name, resv_table); if (extra) { xstrcat(query, extra); xfree(extra); } /* Here we want to order them this way in such a way so it is easy to look for duplicates, it is also easy to sort the resized jobs. */ xstrcat(query, " group by id_job, time_submit desc"); if (debug_flags & DEBUG_FLAG_DB_JOB) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); rc = SLURM_ERROR; goto end_it; } xfree(query); /* Here we set up environment to check used nodes of jobs. Since we store the bitmap of the entire cluster we can use that to set up a hostlist and set up the bitmap to make things work. This should go before the setup of conds since we could update the start/end time. */ if (job_cond && job_cond->used_nodes) { local_cluster_list = setup_cluster_list_with_inx( mysql_conn, job_cond, (void **)&curr_cluster); if (!local_cluster_list) { rc = SLURM_ERROR; goto end_it; } } while ((row = mysql_fetch_row(result))) { char *id = row[JOB_REQ_ID]; bool job_ended = 0; int start = slurm_atoul(row[JOB_REQ_START]); curr_id = slurm_atoul(row[JOB_REQ_JOBID]); if (job_cond && !job_cond->duplicates && (curr_id == last_id) && (slurm_atoul(row[JOB_REQ_STATE]) != JOB_RESIZING)) continue; /* check the bitmap to see if this is one of the jobs we are looking for */ /* Use start time instead of submit time because node * indexes are determined at start time and not submit. */ if (!good_nodes_from_inx(local_cluster_list, (void **)&curr_cluster, row[JOB_REQ_NODE_INX], start)) { last_id = curr_id; continue; } job = slurmdb_create_job_rec(); job->state = slurm_atoul(row[JOB_REQ_STATE]); if (curr_id == last_id) /* put in reverse so we order by the submit getting larger which it is given to us in reverse order from the database */ list_prepend(job_list, job); else list_append(job_list, job); last_id = curr_id; if (row[JOB_REQ_GRES_ALLOC]) job->alloc_gres = xstrdup(row[JOB_REQ_GRES_ALLOC]); else job->alloc_gres = xstrdup(""); job->alloc_nodes = slurm_atoul(row[JOB_REQ_ALLOC_NODES]); job->associd = slurm_atoul(row[JOB_REQ_ASSOCID]); job->array_job_id = slurm_atoul(row[JOB_REQ_ARRAYJOBID]); job->array_task_id = slurm_atoul(row[JOB_REQ_ARRAYTASKID]); job->resvid = slurm_atoul(row[JOB_REQ_RESVID]); /* This shouldn't happen with new jobs, but older jobs * could of been added without a start and so the * array_task_id would be 0 instead of it's real value */ if (!job->array_job_id && !job->array_task_id) job->array_task_id = NO_VAL; if (row[JOB_REQ_RESV_NAME] && row[JOB_REQ_RESV_NAME][0]) job->resv_name = xstrdup(row[JOB_REQ_RESV_NAME]); job->cluster = xstrdup(cluster_name); /* we want a blank wckey if the name is null */ if (row[JOB_REQ_WCKEY]) job->wckey = xstrdup(row[JOB_REQ_WCKEY]); else job->wckey = xstrdup(""); job->wckeyid = slurm_atoul(row[JOB_REQ_WCKEYID]); if (row[JOB_REQ_USER_NAME]) job->user = xstrdup(row[JOB_REQ_USER_NAME]); else job->uid = slurm_atoul(row[JOB_REQ_UID]); if (row[JOB_REQ_LFT]) job->lft = slurm_atoul(row[JOB_REQ_LFT]); if (row[JOB_REQ_ACCOUNT] && row[JOB_REQ_ACCOUNT][0]) job->account = xstrdup(row[JOB_REQ_ACCOUNT]); else if (row[JOB_REQ_ACCOUNT1] && row[JOB_REQ_ACCOUNT1][0]) job->account = xstrdup(row[JOB_REQ_ACCOUNT1]); if (row[JOB_REQ_ARRAY_STR] && row[JOB_REQ_ARRAY_STR][0]) job->array_task_str = xstrdup(row[JOB_REQ_ARRAY_STR]); if (row[JOB_REQ_ARRAY_MAX]) job->array_max_tasks = slurm_atoul(row[JOB_REQ_ARRAY_MAX]); if (row[JOB_REQ_BLOCKID]) job->blockid = xstrdup(row[JOB_REQ_BLOCKID]); job->eligible = slurm_atoul(row[JOB_REQ_ELIGIBLE]); job->submit = slurm_atoul(row[JOB_REQ_SUBMIT]); job->start = start; job->end = slurm_atoul(row[JOB_REQ_END]); job->timelimit = slurm_atoul(row[JOB_REQ_TIMELIMIT]); /* since the job->end could be set later end it here */ if (job->end) { job_ended = 1; if (!job->start || (job->start > job->end)) job->start = job->end; } if (job_cond && !job_cond->without_usage_truncation && job_cond->usage_start) { if (job->start && (job->start < job_cond->usage_start)) job->start = job_cond->usage_start; if (!job->end || job->end > job_cond->usage_end) job->end = job_cond->usage_end; if (!job->start) job->start = job->end; job->elapsed = job->end - job->start; if (row[JOB_REQ_SUSPENDED]) { MYSQL_RES *result2 = NULL; MYSQL_ROW row2; /* get the suspended time for this job */ query = xstrdup_printf( "select time_start, time_end from " "\"%s_%s\" where " "(time_start < %ld && (time_end >= %ld " "|| time_end = 0)) && job_db_inx=%s " "order by time_start", cluster_name, suspend_table, job_cond->usage_end, job_cond->usage_start, id); debug4("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); if (!(result2 = mysql_db_query_ret( mysql_conn, query, 0))) { FREE_NULL_LIST(job_list); job_list = NULL; break; } xfree(query); while ((row2 = mysql_fetch_row(result2))) { time_t local_start = slurm_atoul(row2[0]); time_t local_end = slurm_atoul(row2[1]); if (!local_start) continue; if (job->start > local_start) local_start = job->start; if (job->end < local_end) local_end = job->end; if ((local_end - local_start) < 1) continue; job->elapsed -= (local_end - local_start); job->suspended += (local_end - local_start); } mysql_free_result(result2); } } else { job->suspended = slurm_atoul(row[JOB_REQ_SUSPENDED]); /* fix the suspended number to be correct */ if (job->state == JOB_SUSPENDED) job->suspended = now - job->suspended; if (!job->start) { job->elapsed = 0; } else if (!job->end) { job->elapsed = now - job->start; } else { job->elapsed = job->end - job->start; } job->elapsed -= job->suspended; } if ((int)job->elapsed < 0) job->elapsed = 0; job->jobid = curr_id; job->jobname = xstrdup(row[JOB_REQ_NAME]); job->gid = slurm_atoul(row[JOB_REQ_GID]); job->exitcode = slurm_atoul(row[JOB_REQ_EXIT_CODE]); job->derived_ec = slurm_atoul(row[JOB_REQ_DERIVED_EC]); job->derived_es = xstrdup(row[JOB_REQ_DERIVED_ES]); if (row[JOB_REQ_PARTITION]) job->partition = xstrdup(row[JOB_REQ_PARTITION]); if (row[JOB_REQ_NODELIST]) job->nodes = xstrdup(row[JOB_REQ_NODELIST]); if (!job->nodes || !xstrcmp(job->nodes, "(null)")) { xfree(job->nodes); job->nodes = xstrdup("(unknown)"); } job->track_steps = slurm_atoul(row[JOB_REQ_TRACKSTEPS]); job->priority = slurm_atoul(row[JOB_REQ_PRIORITY]); job->req_cpus = slurm_atoul(row[JOB_REQ_REQ_CPUS]); if (row[JOB_REQ_GRES_REQ]) job->req_gres = xstrdup(row[JOB_REQ_GRES_REQ]); else job->req_gres = xstrdup(""); job->req_mem = slurm_atoul(row[JOB_REQ_REQ_MEM]); job->requid = slurm_atoul(row[JOB_REQ_KILL_REQUID]); job->qosid = slurm_atoul(row[JOB_REQ_QOS]); job->show_full = 1; if (row[JOB_REQ_TRESA]) job->tres_alloc_str = xstrdup(row[JOB_REQ_TRESA]); if (row[JOB_REQ_TRESR]) job->tres_req_str = xstrdup(row[JOB_REQ_TRESR]); if (only_pending || (job_cond && job_cond->without_steps)) goto skip_steps; if (job_cond && job_cond->step_list && list_count(job_cond->step_list)) { set = 0; itr = list_iterator_create(job_cond->step_list); while ((selected_step = list_next(itr))) { if ((selected_step->jobid != job->jobid) && (selected_step->jobid != job->array_job_id)) { continue; } else if ((selected_step->array_task_id != INFINITE) && (selected_step->array_task_id != job->array_task_id)) continue; else if (selected_step->stepid == NO_VAL) { job->show_full = 1; break; } else if (selected_step->stepid == INFINITE) selected_step->stepid = SLURM_BATCH_SCRIPT; if (set) xstrcat(extra, " || "); else xstrcat(extra, " && ("); /* The stepid could be -2 so use %d not %u */ xstrfmtcat(extra, "t1.id_step=%d", selected_step->stepid); set = 1; job->show_full = 0; /* Set it back just in case we are looking at a job array. */ if (selected_step->stepid == SLURM_BATCH_SCRIPT) selected_step->stepid = INFINITE; } list_iterator_destroy(itr); if (set) xstrcat(extra, ")"); } query = xstrdup_printf("select %s from \"%s_%s\" as t1 " "where t1.job_db_inx=%s", step_fields, cluster_name, step_table, id); if (extra) { xstrcat(query, extra); xfree(extra); } if (debug_flags & DEBUG_FLAG_DB_STEP) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(step_result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); rc = SLURM_ERROR; goto end_it; } xfree(query); /* Querying the steps in the fashion was faster than doing only 1 query and then matching the steps up later with the job. */ while ((step_row = mysql_fetch_row(step_result))) { /* check the bitmap to see if this is one of the steps we are looking for */ if (!good_nodes_from_inx(local_cluster_list, (void **)&curr_cluster, step_row[STEP_REQ_NODE_INX], start)) continue; step = slurmdb_create_step_rec(); step->tot_cpu_sec = 0; step->tot_cpu_usec = 0; step->job_ptr = job; if (!job->first_step_ptr) job->first_step_ptr = step; list_append(job->steps, step); step->stepid = slurm_atoul(step_row[STEP_REQ_STEPID]); /* info("got step %u.%u", */ /* job->header.jobnum, step->stepnum); */ step->state = slurm_atoul(step_row[STEP_REQ_STATE]); step->exitcode = slurm_atoul(step_row[STEP_REQ_EXIT_CODE]); step->nnodes = slurm_atoul(step_row[STEP_REQ_NODES]); step->ntasks = slurm_atoul(step_row[STEP_REQ_TASKS]); step->task_dist = slurm_atoul(step_row[STEP_REQ_TASKDIST]); step->start = slurm_atoul(step_row[STEP_REQ_START]); step->end = slurm_atoul(step_row[STEP_REQ_END]); /* if the job has ended end the step also */ if (!step->end && job_ended) { step->end = job->end; step->state = job->state; } if (job_cond && !job_cond->without_usage_truncation && job_cond->usage_start) { if (step->start && (step->start < job_cond->usage_start)) step->start = job_cond->usage_start; if (!step->start && step->end) step->start = step->end; if (!step->end || (step->end > job_cond->usage_end)) step->end = job_cond->usage_end; } /* figure this out by start stop */ step->suspended = slurm_atoul(step_row[STEP_REQ_SUSPENDED]); if (!step->start) { step->elapsed = 0; } else if (!step->end) { step->elapsed = now - step->start; } else { step->elapsed = step->end - step->start; } step->elapsed -= step->suspended; if ((int)step->elapsed < 0) step->elapsed = 0; step->req_cpufreq_min = slurm_atoul( step_row[STEP_REQ_REQ_CPUFREQ_MIN]); step->req_cpufreq_max = slurm_atoul( step_row[STEP_REQ_REQ_CPUFREQ_MAX]); step->req_cpufreq_gov = slurm_atoul( step_row[STEP_REQ_REQ_CPUFREQ_GOV]); step->stepname = xstrdup(step_row[STEP_REQ_NAME]); step->nodes = xstrdup(step_row[STEP_REQ_NODELIST]); step->requid = slurm_atoul(step_row[STEP_REQ_KILL_REQUID]); step->stats.cpu_min = slurm_atoul( step_row[STEP_REQ_MIN_CPU]); if (step->stats.cpu_min != NO_VAL) { step->user_cpu_sec = slurm_atoul( step_row[STEP_REQ_USER_SEC]); step->user_cpu_usec = slurm_atoul( step_row[STEP_REQ_USER_USEC]); step->sys_cpu_sec = slurm_atoul(step_row[STEP_REQ_SYS_SEC]); step->sys_cpu_usec = slurm_atoul( step_row[STEP_REQ_SYS_USEC]); step->tot_cpu_sec += step->user_cpu_sec + step->sys_cpu_sec; step->tot_cpu_usec += step->user_cpu_usec + step->sys_cpu_usec; step->stats.disk_read_max = atof(step_row[STEP_REQ_MAX_DISK_READ]); step->stats.disk_read_max_taskid = slurm_atoul( step_row[STEP_REQ_MAX_DISK_READ_TASK]); step->stats.disk_read_ave = atof(step_row[STEP_REQ_AVE_DISK_READ]); step->stats.disk_write_max = atof(step_row[STEP_REQ_MAX_DISK_WRITE]); step->stats.disk_write_max_taskid = slurm_atoul( step_row[STEP_REQ_MAX_DISK_WRITE_TASK]); step->stats.disk_write_ave = atof(step_row[STEP_REQ_AVE_DISK_WRITE]); step->stats.vsize_max = slurm_atoul( step_row[STEP_REQ_MAX_VSIZE]); step->stats.vsize_max_taskid = slurm_atoul( step_row[STEP_REQ_MAX_VSIZE_TASK]); step->stats.vsize_ave = atof(step_row[STEP_REQ_AVE_VSIZE]); step->stats.rss_max = slurm_atoul(step_row[STEP_REQ_MAX_RSS]); step->stats.rss_max_taskid = slurm_atoul( step_row[STEP_REQ_MAX_RSS_TASK]); step->stats.rss_ave = atof(step_row[STEP_REQ_AVE_RSS]); step->stats.pages_max = slurm_atoul( step_row[STEP_REQ_MAX_PAGES]); step->stats.pages_max_taskid = slurm_atoul( step_row[STEP_REQ_MAX_PAGES_TASK]); step->stats.pages_ave = atof(step_row[STEP_REQ_AVE_PAGES]); step->stats.cpu_min_taskid = slurm_atoul( step_row[STEP_REQ_MIN_CPU_TASK]); step->stats.cpu_ave = atof(step_row[STEP_REQ_AVE_CPU]); step->stats.act_cpufreq = atof(step_row[STEP_REQ_ACT_CPUFREQ]); step->stats.consumed_energy = atof( step_row[STEP_REQ_CONSUMED_ENERGY]); step->stats.vsize_max_nodeid = slurm_atoul( step_row[STEP_REQ_MAX_VSIZE_NODE]); step->stats.rss_max_nodeid = slurm_atoul( step_row[STEP_REQ_MAX_RSS_NODE]); step->stats.pages_max_nodeid = slurm_atoul( step_row[STEP_REQ_MAX_PAGES_NODE]); step->stats.cpu_min_nodeid = slurm_atoul( step_row[STEP_REQ_MIN_CPU_NODE]); } if (step_row[STEP_REQ_TRES]) step->tres_alloc_str = xstrdup(step_row[STEP_REQ_TRES]); } mysql_free_result(step_result); if (!job->track_steps) { uint64_t j_cpus, s_cpus; /* If we don't have track_steps we want to see if we have multiple steps. If we only have 1 step check the job name against the step name in most all cases it will be different. If it is different print out the step separate. It could also be a single step/allocation where the job was allocated more than the step requested (eg. CR_Socket). */ if (list_count(job->steps) > 1) job->track_steps = 1; else if (step && (xstrcmp(step->stepname, job->jobname) || (((j_cpus = slurmdb_find_tres_count_in_string( job->tres_alloc_str, TRES_CPU)) != INFINITE64) && ((s_cpus = slurmdb_find_tres_count_in_string( step->tres_alloc_str, TRES_CPU)) != INFINITE64) && j_cpus != s_cpus))) job->track_steps = 1; } skip_steps: /* need to reset here to make the above test valid */ step = NULL; } mysql_free_result(result); end_it: if (itr2) list_iterator_destroy(itr2); FREE_NULL_LIST(local_cluster_list); if (rc == SLURM_SUCCESS) list_transfer(sent_list, job_list); FREE_NULL_LIST(job_list); return rc; }
extern int setup_job_cluster_cond_limits(mysql_conn_t *mysql_conn, slurmdb_job_cond_t *job_cond, char *cluster_name, char **extra) { int set = 0; ListIterator itr = NULL; char *object = NULL; if (!job_cond) return SLURM_SUCCESS; /* this must be done before resvid_list since we set resvid_list up here */ if (job_cond->resv_list && list_count(job_cond->resv_list)) { char *query = xstrdup_printf( "select distinct job_db_inx from \"%s_%s\" where (", cluster_name, job_table); int my_set = 0; MYSQL_RES *result = NULL; MYSQL_ROW row; itr = list_iterator_create(job_cond->resv_list); while ((object = list_next(itr))) { if (my_set) xstrcat(query, " || "); xstrfmtcat(query, "resv_name='%s'", object); my_set = 1; } list_iterator_destroy(itr); xstrcat(query, ")"); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); error("couldn't query the database"); goto no_resv; } xfree(query); if (!job_cond->resvid_list) job_cond->resvid_list = list_create(slurm_destroy_char); while ((row = mysql_fetch_row(result))) { list_append(job_cond->resvid_list, xstrdup(row[0])); } mysql_free_result(result); } no_resv: if (job_cond->resvid_list && list_count(job_cond->resvid_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->resvid_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.id_resv='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->state_list && list_count(job_cond->state_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->state_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); _state_time_string(extra, cluster_name, (uint32_t)slurm_atoul(object), job_cond->usage_start, job_cond->usage_end); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } return SLURM_SUCCESS; }
extern int setup_job_cond_limits(mysql_conn_t *mysql_conn, slurmdb_job_cond_t *job_cond, char **extra) { int set = 0; ListIterator itr = NULL; char *object = NULL; slurmdb_selected_step_t *selected_step = NULL; if (!job_cond) return 0; if (job_cond->acct_list && list_count(job_cond->acct_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->acct_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.account='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->associd_list && list_count(job_cond->associd_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->associd_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.id_assoc='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->userid_list && list_count(job_cond->userid_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->userid_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.id_user='******'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->groupid_list && list_count(job_cond->groupid_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->groupid_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.id_group='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->jobname_list && list_count(job_cond->jobname_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->jobname_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.job_name='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->partition_list && list_count(job_cond->partition_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->partition_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.partition='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->qos_list && list_count(job_cond->qos_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->qos_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.id_qos='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->step_list && list_count(job_cond->step_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->step_list); while ((selected_step = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.id_job=%u", selected_step->jobid); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->cpus_min) { if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); if (job_cond->cpus_max) { xstrfmtcat(*extra, "(t1.cpus_alloc between %u and %u))", job_cond->cpus_min, job_cond->cpus_max); } else { xstrfmtcat(*extra, "(t1.cpus_alloc='%u'))", job_cond->cpus_min); } } if (job_cond->nodes_min) { if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); if (job_cond->nodes_max) { xstrfmtcat(*extra, "(t1.nodes_alloc between %u and %u))", job_cond->nodes_min, job_cond->nodes_max); } else { xstrfmtcat(*extra, "(t1.nodes_alloc='%u'))", job_cond->nodes_min); } } if (job_cond->timelimit_min) { if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); if (job_cond->timelimit_max) { xstrfmtcat(*extra, "(t1.timelimit between %u and %u))", job_cond->timelimit_min, job_cond->timelimit_max); } else { xstrfmtcat(*extra, "(t1.timelimit='%u'))", job_cond->timelimit_min); } } if (job_cond->state_list && list_count(job_cond->state_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->state_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); _state_time_string(extra, (uint32_t)slurm_atoul(object), job_cond->usage_start, job_cond->usage_end); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } else { /* Only do this (default of all eligible jobs) if no state is given */ if (job_cond->usage_start) { if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); if (!job_cond->usage_end) xstrfmtcat(*extra, "(t1.time_end >= %ld " "|| t1.time_end = 0))", job_cond->usage_start); else xstrfmtcat(*extra, "(t1.time_eligible < %ld " "&& (t1.time_end >= %ld " "|| t1.time_end = 0)))", job_cond->usage_end, job_cond->usage_start); } else if (job_cond->usage_end) { if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); xstrfmtcat(*extra, "(t1.time_eligible < %ld))", job_cond->usage_end); } } if (job_cond->wckey_list && list_count(job_cond->wckey_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->wckey_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.wckey='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } return set; }
static int _cluster_get_wckeys(mysql_conn_t *mysql_conn, slurmdb_wckey_cond_t *wckey_cond, char *fields, char *extra, char *cluster_name, List sent_list) { List wckey_list = NULL; MYSQL_RES *result = NULL; MYSQL_ROW row; char *query = NULL; bool with_usage = 0; if (wckey_cond) with_usage = wckey_cond->with_usage; xstrfmtcat(query, "select distinct %s from \"%s_%s\" as t1%s " "order by wckey_name, user;", fields, cluster_name, wckey_table, extra); if (debug_flags & DEBUG_FLAG_DB_WCKEY) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); if (mysql_errno(mysql_conn->db_conn) == ER_NO_SUCH_TABLE) return SLURM_SUCCESS; else return SLURM_ERROR; } xfree(query); if (!mysql_num_rows(result)) { mysql_free_result(result); return SLURM_SUCCESS; } wckey_list = list_create(slurmdb_destroy_wckey_rec); while ((row = mysql_fetch_row(result))) { slurmdb_wckey_rec_t *wckey = xmalloc(sizeof(slurmdb_wckey_rec_t)); list_append(wckey_list, wckey); wckey->id = slurm_atoul(row[WCKEY_REQ_ID]); wckey->is_def = slurm_atoul(row[WCKEY_REQ_DEFAULT]); wckey->user = xstrdup(row[WCKEY_REQ_USER]); /* we want a blank wckey if the name is null */ if (row[WCKEY_REQ_NAME]) wckey->name = xstrdup(row[WCKEY_REQ_NAME]); else wckey->name = xstrdup(""); wckey->cluster = xstrdup(cluster_name); } mysql_free_result(result); if (with_usage && wckey_list && list_count(wckey_list)) get_usage_for_list(mysql_conn, DBD_GET_WCKEY_USAGE, wckey_list, cluster_name, wckey_cond->usage_start, wckey_cond->usage_end); list_transfer(sent_list, wckey_list); list_destroy(wckey_list); return SLURM_SUCCESS; }
static int _cluster_modify_wckeys(mysql_conn_t *mysql_conn, slurmdb_wckey_rec_t *wckey, char *cluster_name, char *extra, char *vals, char *user_name, List ret_list) { int rc = SLURM_SUCCESS; MYSQL_RES *result = NULL; MYSQL_ROW row; char *wckey_char = NULL; time_t now = time(NULL); char *query = NULL; query = xstrdup_printf("select t1.id_wckey, t1.wckey_name, t1.user " "from \"%s_%s\" as t1%s;", cluster_name, wckey_table, extra); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); return SLURM_ERROR; } /* This key doesn't exist on this cluster, that is ok. */ if (!mysql_num_rows(result)) return SLURM_SUCCESS; while ((row = mysql_fetch_row(result))) { slurmdb_wckey_rec_t *wckey_rec = NULL; char *object = xstrdup_printf( "C = %-10s W = %-20s U = %-9s", cluster_name, row[1], row[2]); list_append(ret_list, object); if (!wckey_char) xstrfmtcat(wckey_char, "id_wckey='%s'", row[0]); else xstrfmtcat(wckey_char, " || id_wckey='%s'", row[0]); wckey_rec = xmalloc(sizeof(slurmdb_wckey_rec_t)); /* we only need id and cluster when removing no real need to init */ wckey_rec->id = slurm_atoul(row[0]); wckey_rec->cluster = xstrdup(cluster_name); wckey_rec->is_def = wckey->is_def; if (addto_update_list(mysql_conn->update_list, SLURMDB_MODIFY_WCKEY, wckey_rec) != SLURM_SUCCESS) slurmdb_destroy_wckey_rec(wckey_rec); if (wckey->is_def == 1) { /* Use fresh one here so we don't have to worry about dealing with bad values. */ slurmdb_wckey_rec_t tmp_wckey; slurmdb_init_wckey_rec(&tmp_wckey, 0); tmp_wckey.is_def = 1; tmp_wckey.cluster = cluster_name; tmp_wckey.name = row[1]; tmp_wckey.user = row[2]; if ((rc = _reset_default_wckey(mysql_conn, &tmp_wckey)) != SLURM_SUCCESS) break; } } mysql_free_result(result); if (!list_count(ret_list)) { errno = SLURM_NO_CHANGE_IN_DATA; if (debug_flags & DEBUG_FLAG_DB_WCKEY) DB_DEBUG(mysql_conn->conn, "didn't effect anything\n%s", query); xfree(query); xfree(wckey_char); return SLURM_SUCCESS; } xfree(query); rc = modify_common(mysql_conn, DBD_MODIFY_WCKEYS, now, user_name, wckey_table, wckey_char, vals, cluster_name); xfree(wckey_char); return rc; }
static int _cluster_remove_wckeys(mysql_conn_t *mysql_conn, char *extra, char *cluster_name, char *user_name, List ret_list) { int rc = SLURM_SUCCESS; MYSQL_RES *result = NULL; MYSQL_ROW row; char *assoc_char = NULL; time_t now = time(NULL); char *query = xstrdup_printf("select t1.id_wckey, t1.wckey_name " "from \"%s_%s\" as t1%s;", cluster_name, wckey_table, extra); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); return SLURM_ERROR; } if (!mysql_num_rows(result)) { mysql_free_result(result); xfree(query); return SLURM_SUCCESS; } while ((row = mysql_fetch_row(result))) { slurmdb_wckey_rec_t *wckey_rec = NULL; list_append(ret_list, xstrdup(row[1])); if (!assoc_char) xstrfmtcat(assoc_char, "id_wckey='%s'", row[0]); else xstrfmtcat(assoc_char, " || id_wckey='%s'", row[0]); wckey_rec = xmalloc(sizeof(slurmdb_wckey_rec_t)); /* we only need id and cluster when removing no real need to init */ wckey_rec->id = slurm_atoul(row[0]); wckey_rec->cluster = xstrdup(cluster_name); if (addto_update_list(mysql_conn->update_list, SLURMDB_REMOVE_WCKEY, wckey_rec) != SLURM_SUCCESS) slurmdb_destroy_wckey_rec(wckey_rec); } mysql_free_result(result); if (!list_count(ret_list)) { errno = SLURM_NO_CHANGE_IN_DATA; if (debug_flags & DEBUG_FLAG_DB_WCKEY) DB_DEBUG(mysql_conn->conn, "didn't effect anything\n%s", query); xfree(query); xfree(assoc_char); return SLURM_SUCCESS; } xfree(query); rc = remove_common(mysql_conn, DBD_REMOVE_WCKEYS, now, user_name, wckey_table, assoc_char, assoc_char, cluster_name, NULL, NULL); xfree(assoc_char); if (rc == SLURM_ERROR) { list_destroy(ret_list); return SLURM_ERROR; } return SLURM_SUCCESS; }
extern List mysql_jobcomp_process_get_jobs(slurmdb_job_cond_t *job_cond) { char *query = NULL; char *extra = NULL; char *tmp = NULL; char *selected_part = NULL; slurmdb_selected_step_t *selected_step = NULL; ListIterator itr = NULL; int set = 0; MYSQL_RES *result = NULL; MYSQL_ROW row; int i; int lc = 0; jobcomp_job_rec_t *job = NULL; char time_str[32]; time_t temp_time; List job_list = list_create(jobcomp_destroy_job); if (job_cond->step_list && list_count(job_cond->step_list)) { set = 0; xstrcat(extra, " where ("); itr = list_iterator_create(job_cond->step_list); while((selected_step = list_next(itr))) { if (set) xstrcat(extra, " || "); tmp = xstrdup_printf("jobid=%d", selected_step->jobid); xstrcat(extra, tmp); set = 1; xfree(tmp); } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (job_cond->partition_list && list_count(job_cond->partition_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(job_cond->partition_list); while((selected_part = list_next(itr))) { if (set) xstrcat(extra, " || "); tmp = xstrdup_printf("`partition`='%s'", selected_part); xstrcat(extra, tmp); set = 1; xfree(tmp); } list_iterator_destroy(itr); xstrcat(extra, ")"); } i = 0; while(jobcomp_table_fields[i].name) { if (i) xstrcat(tmp, ", "); xstrcat(tmp, jobcomp_table_fields[i].name); i++; } query = xstrdup_printf("select %s from %s", tmp, jobcomp_table); xfree(tmp); if (extra) { xstrcat(query, extra); xfree(extra); } //info("query = %s", query); if (!(result = mysql_db_query_ret(jobcomp_mysql_conn, query, 0))) { xfree(query); list_destroy(job_list); return NULL; } xfree(query); while((row = mysql_fetch_row(result))) { lc++; job = xmalloc(sizeof(jobcomp_job_rec_t)); if (row[JOBCOMP_REQ_JOBID]) job->jobid = slurm_atoul(row[JOBCOMP_REQ_JOBID]); job->partition = xstrdup(row[JOBCOMP_REQ_PARTITION]); temp_time = atoi(row[JOBCOMP_REQ_STARTTIME]); slurm_make_time_str(&temp_time, time_str, sizeof(time_str)); job->start_time = xstrdup(time_str); temp_time = atoi(row[JOBCOMP_REQ_ENDTIME]); slurm_make_time_str(&temp_time, time_str, sizeof(time_str)); job->elapsed_time = atoi(row[JOBCOMP_REQ_ENDTIME]) - atoi(row[JOBCOMP_REQ_STARTTIME]); job->end_time = xstrdup(time_str); if (row[JOBCOMP_REQ_UID]) job->uid = slurm_atoul(row[JOBCOMP_REQ_UID]); job->uid_name = xstrdup(row[JOBCOMP_REQ_USER_NAME]); if (row[JOBCOMP_REQ_GID]) job->gid = slurm_atoul(row[JOBCOMP_REQ_GID]); job->gid_name = xstrdup(row[JOBCOMP_REQ_GROUP_NAME]); job->jobname = xstrdup(row[JOBCOMP_REQ_NAME]); job->nodelist = xstrdup(row[JOBCOMP_REQ_NODELIST]); if (row[JOBCOMP_REQ_NODECNT]) job->node_cnt = slurm_atoul(row[JOBCOMP_REQ_NODECNT]); if (row[JOBCOMP_REQ_STATE]) { i = atoi(row[JOBCOMP_REQ_STATE]); job->state = xstrdup(job_state_string(i)); } job->timelimit = xstrdup(row[JOBCOMP_REQ_TIMELIMIT]); if (row[JOBCOMP_REQ_MAXPROCS]) job->max_procs = slurm_atoul(row[JOBCOMP_REQ_MAXPROCS]); job->connection = xstrdup(row[JOBCOMP_REQ_CONNECTION]); job->reboot = xstrdup(row[JOBCOMP_REQ_REBOOT]); job->rotate = xstrdup(row[JOBCOMP_REQ_ROTATE]); job->geo = xstrdup(row[JOBCOMP_REQ_GEOMETRY]); job->bg_start_point = xstrdup(row[JOBCOMP_REQ_START]); job->blockid = xstrdup(row[JOBCOMP_REQ_BLOCKID]); list_append(job_list, job); } mysql_free_result(result); return job_list; }
static void _load_dbd_state(void) { char *dbd_fname; Buf buffer; int fd, recovered = 0; uint16_t rpc_version = 0; dbd_fname = slurm_get_state_save_location(); xstrcat(dbd_fname, "/dbd.messages"); fd = open(dbd_fname, O_RDONLY); if (fd < 0) { /* don't print an error message if there is no file */ if (errno == ENOENT) debug4("slurmdbd: There is no state save file to " "open by name %s", dbd_fname); else error("slurmdbd: Opening state save file %s: %m", dbd_fname); } else { char *ver_str = NULL; uint32_t ver_str_len; buffer = _load_dbd_rec(fd); if (buffer == NULL) goto end_it; /* This is set to the end of the buffer for send so we need to set it back to 0 */ set_buf_offset(buffer, 0); safe_unpackstr_xmalloc(&ver_str, &ver_str_len, buffer); debug3("Version string in dbd_state header is %s", ver_str); unpack_error: free_buf(buffer); buffer = NULL; if (ver_str) { /* get the version after VER */ rpc_version = slurm_atoul(ver_str + 3); xfree(ver_str); } while (1) { /* If the buffer was not the VER%d string it was an actual message so we don't want to skip it. */ if (!buffer) buffer = _load_dbd_rec(fd); if (buffer == NULL) break; if (rpc_version != SLURM_PROTOCOL_VERSION) { /* unpack and repack with new * PROTOCOL_VERSION just so we keep * things up to date. */ slurmdbd_msg_t msg; int rc; set_buf_offset(buffer, 0); rc = unpack_slurmdbd_msg( &msg, rpc_version, buffer); free_buf(buffer); if (rc == SLURM_SUCCESS) buffer = pack_slurmdbd_msg( &msg, SLURM_PROTOCOL_VERSION); else buffer = NULL; } if (!buffer) { error("no buffer given"); continue; } if (!list_enqueue(agent_list, buffer)) fatal("slurmdbd: list_enqueue, no memory"); recovered++; buffer = NULL; } end_it: verbose("slurmdbd: recovered %d pending RPCs", recovered); (void) close(fd); } xfree(dbd_fname); }
extern int as_mysql_get_usage(mysql_conn_t *mysql_conn, uid_t uid, void *in, slurmdbd_msg_type_t type, time_t start, time_t end) { int rc = SLURM_SUCCESS; int i=0, is_admin=1; MYSQL_RES *result = NULL; MYSQL_ROW row; char *tmp = NULL; char *my_usage_table = NULL; slurmdb_association_rec_t *slurmdb_assoc = in; slurmdb_wckey_rec_t *slurmdb_wckey = in; char *query = NULL; char *username = NULL; uint16_t private_data = 0; slurmdb_user_rec_t user; List *my_list; uint32_t id = NO_VAL; char *cluster_name = NULL; char **usage_req_inx = NULL; enum { USAGE_ID, USAGE_START, USAGE_ACPU, USAGE_COUNT, USAGE_ENERGY }; switch (type) { case DBD_GET_ASSOC_USAGE: { char *temp_usage[] = { "t3.id_assoc", "t1.time_start", "t1.alloc_cpu_secs" }; usage_req_inx = temp_usage; id = slurmdb_assoc->id; cluster_name = slurmdb_assoc->cluster; username = slurmdb_assoc->user; my_list = &slurmdb_assoc->accounting_list; my_usage_table = assoc_day_table; break; } case DBD_GET_WCKEY_USAGE: { char *temp_usage[] = { "id_wckey", "time_start", "alloc_cpu_secs" }; usage_req_inx = temp_usage; id = slurmdb_wckey->id; cluster_name = slurmdb_wckey->cluster; username = slurmdb_wckey->user; my_list = &slurmdb_wckey->accounting_list; my_usage_table = wckey_day_table; break; } case DBD_GET_CLUSTER_USAGE: { return _get_cluster_usage(mysql_conn, uid, in, type, start, end); break; } default: error("Unknown usage type %d", type); return SLURM_ERROR; break; } if (!id) { error("We need an id to set data for getting usage"); return SLURM_ERROR; } else if (!cluster_name) { error("We need a cluster_name to set data for getting usage"); return SLURM_ERROR; } if (check_connection(mysql_conn) != SLURM_SUCCESS) return ESLURM_DB_CONNECTION; memset(&user, 0, sizeof(slurmdb_user_rec_t)); user.uid = uid; private_data = slurm_get_private_data(); if (private_data & PRIVATE_DATA_USAGE) { if (!(is_admin = is_user_min_admin_level( mysql_conn, uid, SLURMDB_ADMIN_OPERATOR))) { ListIterator itr = NULL; slurmdb_coord_rec_t *coord = NULL; if (username && !strcmp(slurmdb_assoc->user, user.name)) goto is_user; if (type != DBD_GET_ASSOC_USAGE) goto bad_user; if (!slurmdb_assoc->acct) { debug("No account name given " "in association."); goto bad_user; } if (!is_user_any_coord(mysql_conn, &user)) { debug4("This user is not a coordinator."); goto bad_user; } /* Existance of user.coord_accts is checked in is_user_any_coord. */ itr = list_iterator_create(user.coord_accts); while ((coord = list_next(itr))) if (!strcasecmp(coord->name, slurmdb_assoc->acct)) break; list_iterator_destroy(itr); if (coord) goto is_user; bad_user: errno = ESLURM_ACCESS_DENIED; return SLURM_ERROR; } } is_user: if (set_usage_information(&my_usage_table, type, &start, &end) != SLURM_SUCCESS) { return SLURM_ERROR; } xfree(tmp); i=0; xstrfmtcat(tmp, "%s", usage_req_inx[i]); for(i=1; i<USAGE_COUNT; i++) { xstrfmtcat(tmp, ", %s", usage_req_inx[i]); } switch (type) { case DBD_GET_ASSOC_USAGE: query = xstrdup_printf( "select %s from \"%s_%s\" as t1, " "\"%s_%s\" as t2, \"%s_%s\" as t3 " "where (t1.time_start < %ld && t1.time_start >= %ld) " "&& t1.id_assoc=t2.id_assoc && t3.id_assoc=%d && " "t2.lft between t3.lft and t3.rgt " "order by t3.id_assoc, time_start;", tmp, cluster_name, my_usage_table, cluster_name, cluster_name, assoc_table, assoc_table, end, start, id); break; case DBD_GET_WCKEY_USAGE: query = xstrdup_printf( "select %s from \"%s_%s\" " "where (time_start < %ld && time_start >= %ld) " "&& id_wckey=%d order by id_wckey, time_start;", tmp, cluster_name, my_usage_table, end, start, id); break; default: error("Unknown usage type %d", type); return SLURM_ERROR; break; } xfree(tmp); debug4("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); return SLURM_ERROR; } xfree(query); if (!(*my_list)) (*my_list) = list_create(slurmdb_destroy_accounting_rec); while ((row = mysql_fetch_row(result))) { slurmdb_accounting_rec_t *accounting_rec = xmalloc(sizeof(slurmdb_accounting_rec_t)); accounting_rec->id = slurm_atoul(row[USAGE_ID]); accounting_rec->period_start = slurm_atoul(row[USAGE_START]); accounting_rec->alloc_secs = slurm_atoull(row[USAGE_ACPU]); accounting_rec->consumed_energy = slurm_atoull(row[USAGE_ENERGY]); list_append((*my_list), accounting_rec); } mysql_free_result(result); return rc; }
extern List as_mysql_get_resvs(mysql_conn_t *mysql_conn, uid_t uid, slurmdb_reservation_cond_t *resv_cond) { //DEF_TIMERS; char *query = NULL; char *extra = NULL; char *tmp = NULL; List resv_list = NULL; int i=0, is_admin=1; MYSQL_RES *result = NULL; MYSQL_ROW row; uint16_t private_data = 0; slurmdb_job_cond_t job_cond; void *curr_cluster = NULL; List local_cluster_list = NULL; List use_cluster_list = as_mysql_cluster_list; ListIterator itr = NULL; char *cluster_name = NULL; /* needed if we don't have an resv_cond */ uint16_t with_usage = 0; /* if this changes you will need to edit the corresponding enum */ char *resv_req_inx[] = { "id_resv", "assoclist", "flags", "nodelist", "node_inx", "resv_name", "time_start", "time_end", "tres" }; enum { RESV_REQ_ID, RESV_REQ_ASSOCS, RESV_REQ_FLAGS, RESV_REQ_NODES, RESV_REQ_NODE_INX, RESV_REQ_NAME, RESV_REQ_START, RESV_REQ_END, RESV_REQ_TRES, RESV_REQ_COUNT }; if (!resv_cond) { xstrcat(extra, " where deleted=0"); goto empty; } if (check_connection(mysql_conn) != SLURM_SUCCESS) return NULL; private_data = slurm_get_private_data(); if (private_data & PRIVATE_DATA_RESERVATIONS) { if (!(is_admin = is_user_min_admin_level( mysql_conn, uid, SLURMDB_ADMIN_OPERATOR))) { error("Only admins can look at reservations"); errno = ESLURM_ACCESS_DENIED; return NULL; } } memset(&job_cond, 0, sizeof(slurmdb_job_cond_t)); if (resv_cond->nodes) { job_cond.usage_start = resv_cond->time_start; job_cond.usage_end = resv_cond->time_end; job_cond.used_nodes = resv_cond->nodes; job_cond.cluster_list = resv_cond->cluster_list; local_cluster_list = setup_cluster_list_with_inx( mysql_conn, &job_cond, (void **)&curr_cluster); } else if (with_usage) { job_cond.usage_start = resv_cond->time_start; job_cond.usage_end = resv_cond->time_end; } (void) _setup_resv_cond_limits(resv_cond, &extra); with_usage = resv_cond->with_usage; if (resv_cond->cluster_list && list_count(resv_cond->cluster_list)) use_cluster_list = resv_cond->cluster_list; empty: xfree(tmp); xstrfmtcat(tmp, "t1.%s", resv_req_inx[i]); for(i=1; i<RESV_REQ_COUNT; i++) { xstrfmtcat(tmp, ", t1.%s", resv_req_inx[i]); } if (use_cluster_list == as_mysql_cluster_list) slurm_mutex_lock(&as_mysql_cluster_list_lock); itr = list_iterator_create(use_cluster_list); while ((cluster_name = list_next(itr))) { if (query) xstrcat(query, " union "); //START_TIMER; xstrfmtcat(query, "select distinct %s,'%s' as cluster " "from \"%s_%s\" as t1%s", tmp, cluster_name, cluster_name, resv_table, extra ? extra : ""); } list_iterator_destroy(itr); if (use_cluster_list == as_mysql_cluster_list) slurm_mutex_unlock(&as_mysql_cluster_list_lock); if (query) xstrcat(query, " order by cluster, resv_name;"); xfree(tmp); xfree(extra); if (debug_flags & DEBUG_FLAG_DB_RESV) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); FREE_NULL_LIST(local_cluster_list); return NULL; } xfree(query); resv_list = list_create(slurmdb_destroy_reservation_rec); while ((row = mysql_fetch_row(result))) { slurmdb_reservation_rec_t *resv = xmalloc(sizeof(slurmdb_reservation_rec_t)); int start = slurm_atoul(row[RESV_REQ_START]); list_append(resv_list, resv); if (!good_nodes_from_inx(local_cluster_list, &curr_cluster, row[RESV_REQ_NODE_INX], start)) continue; resv->id = slurm_atoul(row[RESV_REQ_ID]); if (with_usage) { if (!job_cond.resvid_list) job_cond.resvid_list = list_create(NULL); list_append(job_cond.resvid_list, row[RESV_REQ_ID]); } resv->name = xstrdup(row[RESV_REQ_NAME]); resv->cluster = xstrdup(row[RESV_REQ_COUNT]); resv->assocs = xstrdup(row[RESV_REQ_ASSOCS]); resv->nodes = xstrdup(row[RESV_REQ_NODES]); resv->time_start = start; resv->time_end = slurm_atoul(row[RESV_REQ_END]); resv->flags = slurm_atoul(row[RESV_REQ_FLAGS]); resv->tres_str = xstrdup(row[RESV_REQ_TRES]); } FREE_NULL_LIST(local_cluster_list); if (with_usage && resv_list && list_count(resv_list)) { List job_list = as_mysql_jobacct_process_get_jobs( mysql_conn, uid, &job_cond); ListIterator itr = NULL, itr2 = NULL; slurmdb_job_rec_t *job = NULL; slurmdb_reservation_rec_t *resv = NULL; if (!job_list || !list_count(job_list)) goto no_jobs; itr = list_iterator_create(job_list); itr2 = list_iterator_create(resv_list); while ((job = list_next(itr))) { int start = job->start; int end = job->end; int set = 0; while ((resv = list_next(itr2))) { int elapsed = 0; /* since a reservation could have changed while a job was running we have to make sure we get the time in the correct record. */ if (resv->id != job->resvid) continue; set = 1; if (start < resv->time_start) start = resv->time_start; if (!end || end > resv->time_end) end = resv->time_end; if ((elapsed = (end - start)) < 1) continue; slurmdb_transfer_tres_time( &resv->tres_list, job->tres_alloc_str, elapsed); } list_iterator_reset(itr2); if (!set) { error("we got a job %u with no reservation " "associatied with it?", job->jobid); } } list_iterator_destroy(itr2); list_iterator_destroy(itr); no_jobs: FREE_NULL_LIST(job_list); } FREE_NULL_LIST(job_cond.resvid_list); /* free result after we use the list with resv id's in it. */ mysql_free_result(result); //END_TIMER2("get_resvs"); return resv_list; }
extern int setup_job_cluster_cond_limits(mysql_conn_t *mysql_conn, slurmdb_job_cond_t *job_cond, char *cluster_name, char **extra) { int set = 0; ListIterator itr = NULL; char *object = NULL; if (!job_cond) return SLURM_SUCCESS; /* this must be done before resvid_list since we set resvid_list up here */ if (job_cond->resv_list && list_count(job_cond->resv_list)) { char *query = xstrdup_printf( "select distinct job_db_inx from \"%s_%s\" where (", cluster_name, job_table); int my_set = 0; MYSQL_RES *result = NULL; MYSQL_ROW row; itr = list_iterator_create(job_cond->resv_list); while ((object = list_next(itr))) { if (my_set) xstrcat(query, " || "); xstrfmtcat(query, "resv_name='%s'", object); my_set = 1; } list_iterator_destroy(itr); xstrcat(query, ")"); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); error("couldn't query the database"); goto no_resv; } xfree(query); if (!job_cond->resvid_list) job_cond->resvid_list = list_create(slurm_destroy_char); while ((row = mysql_fetch_row(result))) { list_append(job_cond->resvid_list, xstrdup(row[0])); } mysql_free_result(result); } no_resv: if (job_cond->resvid_list && list_count(job_cond->resvid_list)) { set = 0; if (*extra) xstrcat(*extra, " && ("); else xstrcat(*extra, " where ("); itr = list_iterator_create(job_cond->resvid_list); while ((object = list_next(itr))) { if (set) xstrcat(*extra, " || "); xstrfmtcat(*extra, "t1.id_resv='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(*extra, ")"); } if (job_cond->state_list && list_count(job_cond->state_list)) { itr = list_iterator_create(job_cond->state_list); while ((object = list_next(itr))) { uint32_t state = (uint32_t)slurm_atoul(object); state &= JOB_STATE_BASE; if (state == JOB_SUSPENDED) break; } list_iterator_destroy(itr); if (object) { MYSQL_RES *result = NULL; MYSQL_ROW row; char *query = xstrdup_printf( "select job_db_inx from \"%s_%s\"", cluster_name, suspend_table); if (job_cond->usage_start) { if (!job_cond->usage_end) { xstrfmtcat(query, " where (!time_end " "|| (%d between " "time_start and time_end))", (int)job_cond->usage_start); } else { xstrfmtcat(query, " where (!time_end " "|| (time_start && " "((%d between time_start " "and time_end) " "|| (time_start between " "%d and %d))))", (int)job_cond->usage_start, (int)job_cond->usage_start, (int)job_cond->usage_end); } } else if (job_cond->usage_end) { xstrfmtcat(query, " where (time_start && " "time_start < %d)", (int)job_cond->usage_end); } debug3("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); result = mysql_db_query_ret(mysql_conn, query, 0); xfree(query); if (!result) return SLURM_ERROR; set = 0; while ((row = mysql_fetch_row(result))) { if (set) xstrfmtcat(*extra, " || t1.job_db_inx=%s", row[0]); else { set = 1; if (*extra) xstrfmtcat( *extra, " || (t1.job_db_inx=%s", row[0]); else xstrfmtcat(*extra, " where " "(t1.job_db_inx=%s", row[0]); } } mysql_free_result(result); if (set) xstrcat(*extra, ")"); } } return SLURM_SUCCESS; }
extern List as_mysql_modify_qos(mysql_conn_t *mysql_conn, uint32_t uid, slurmdb_qos_cond_t *qos_cond, slurmdb_qos_rec_t *qos) { ListIterator itr = NULL; List ret_list = NULL; int rc = SLURM_SUCCESS; char *object = NULL; char *vals = NULL, *extra = NULL, *query = NULL, *name_char = NULL; time_t now = time(NULL); char *user_name = NULL; int set = 0; MYSQL_RES *result = NULL; MYSQL_ROW row; char *tmp_char1=NULL, *tmp_char2=NULL; bitstr_t *preempt_bitstr = NULL; char *added_preempt = NULL; if (!qos_cond || !qos) { error("we need something to change"); return NULL; } if (check_connection(mysql_conn) != SLURM_SUCCESS) return NULL; xstrcat(extra, "where deleted=0"); if (qos_cond->description_list && list_count(qos_cond->description_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->description_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "description='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (qos_cond->id_list && list_count(qos_cond->id_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->id_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "id='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (qos_cond->name_list && list_count(qos_cond->name_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->name_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "name='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } _setup_qos_limits(qos, &tmp_char1, &tmp_char2, &vals, &added_preempt, 0); if (added_preempt) { preempt_bitstr = bit_alloc(g_qos_count); bit_unfmt(preempt_bitstr, added_preempt+1); xfree(added_preempt); } xfree(tmp_char1); xfree(tmp_char2); if (!extra || !vals) { errno = SLURM_NO_CHANGE_IN_DATA; FREE_NULL_BITMAP(preempt_bitstr); error("Nothing to change"); return NULL; } query = xstrdup_printf("select name, preempt, id from %s %s;", qos_table, extra); xfree(extra); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); FREE_NULL_BITMAP(preempt_bitstr); return NULL; } rc = 0; ret_list = list_create(slurm_destroy_char); while ((row = mysql_fetch_row(result))) { slurmdb_qos_rec_t *qos_rec = NULL; uint32_t id = slurm_atoul(row[2]); if (preempt_bitstr) { if (_preemption_loop(mysql_conn, id, preempt_bitstr)) break; } object = xstrdup(row[0]); list_append(ret_list, object); if (!rc) { xstrfmtcat(name_char, "(name='%s'", object); rc = 1; } else { xstrfmtcat(name_char, " || name='%s'", object); } qos_rec = xmalloc(sizeof(slurmdb_qos_rec_t)); qos_rec->name = xstrdup(object); qos_rec->id = id; qos_rec->flags = qos->flags; qos_rec->grp_cpus = qos->grp_cpus; qos_rec->grace_time = qos->grace_time; qos_rec->grp_cpu_mins = qos->grp_cpu_mins; qos_rec->grp_cpu_run_mins = qos->grp_cpu_run_mins; qos_rec->grp_jobs = qos->grp_jobs; qos_rec->grp_nodes = qos->grp_nodes; qos_rec->grp_submit_jobs = qos->grp_submit_jobs; qos_rec->grp_wall = qos->grp_wall; qos_rec->max_cpus_pj = qos->max_cpus_pj; qos_rec->max_cpu_mins_pj = qos->max_cpu_mins_pj; qos_rec->max_cpu_run_mins_pu = qos->max_cpu_run_mins_pu; qos_rec->max_jobs_pu = qos->max_jobs_pu; qos_rec->max_nodes_pj = qos->max_nodes_pj; qos_rec->max_submit_jobs_pu = qos->max_submit_jobs_pu; qos_rec->max_wall_pj = qos->max_wall_pj; qos_rec->preempt_mode = qos->preempt_mode; qos_rec->priority = qos->priority; if (qos->preempt_list) { ListIterator new_preempt_itr = list_iterator_create(qos->preempt_list); char *new_preempt = NULL; qos_rec->preempt_bitstr = bit_alloc(g_qos_count); if (row[1] && row[1][0]) bit_unfmt(qos_rec->preempt_bitstr, row[1]+1); while ((new_preempt = list_next(new_preempt_itr))) { bool cleared = 0; if (new_preempt[0] == '-') { bit_clear(qos_rec->preempt_bitstr, atol(new_preempt+1)); } else if (new_preempt[0] == '+') { bit_set(qos_rec->preempt_bitstr, atol(new_preempt+1)); } else { if (!cleared) { cleared = 1; bit_nclear( qos_rec->preempt_bitstr, 0, g_qos_count-1); } bit_set(qos_rec->preempt_bitstr, atol(new_preempt)); } } list_iterator_destroy(new_preempt_itr); } qos_rec->usage_factor = qos->usage_factor; qos_rec->usage_thres = qos->usage_thres; if (addto_update_list(mysql_conn->update_list, SLURMDB_MODIFY_QOS, qos_rec) != SLURM_SUCCESS) slurmdb_destroy_qos_rec(qos_rec); } mysql_free_result(result); FREE_NULL_BITMAP(preempt_bitstr); if (row) { xfree(vals); xfree(name_char); xfree(query); list_destroy(ret_list); ret_list = NULL; errno = ESLURM_QOS_PREEMPTION_LOOP; return ret_list; } if (!list_count(ret_list)) { errno = SLURM_NO_CHANGE_IN_DATA; debug3("didn't effect anything\n%s", query); xfree(vals); xfree(query); return ret_list; } xfree(query); xstrcat(name_char, ")"); user_name = uid_to_string((uid_t) uid); rc = modify_common(mysql_conn, DBD_MODIFY_QOS, now, user_name, qos_table, name_char, vals, NULL); xfree(user_name); xfree(name_char); xfree(vals); if (rc == SLURM_ERROR) { error("Couldn't modify qos"); list_destroy(ret_list); ret_list = NULL; } return ret_list; }
extern List as_mysql_get_txn(mysql_conn_t *mysql_conn, uid_t uid, slurmdb_txn_cond_t *txn_cond) { char *query = NULL; char *assoc_extra = NULL; char *name_extra = NULL; char *extra = NULL; char *tmp = NULL; List txn_list = NULL; ListIterator itr = NULL; char *object = NULL; int set = 0; int i=0; MYSQL_RES *result = NULL; MYSQL_ROW row; List use_cluster_list = as_mysql_cluster_list; bool locked = 0; /* if this changes you will need to edit the corresponding enum */ char *txn_req_inx[] = { "id", "timestamp", "action", "name", "actor", "info", "cluster" }; enum { TXN_REQ_ID, TXN_REQ_TS, TXN_REQ_ACTION, TXN_REQ_NAME, TXN_REQ_ACTOR, TXN_REQ_INFO, TXN_REQ_CLUSTER, TXN_REQ_COUNT }; if (check_connection(mysql_conn) != SLURM_SUCCESS) return NULL; if (!txn_cond) goto empty; /* handle query for associations first */ if (txn_cond->acct_list && list_count(txn_cond->acct_list)) { set = 0; if (assoc_extra) xstrcat(assoc_extra, " && ("); else xstrcat(assoc_extra, " where ("); if (name_extra) xstrcat(name_extra, " && ("); else xstrcat(name_extra, " ("); itr = list_iterator_create(txn_cond->acct_list); while ((object = list_next(itr))) { if (set) { xstrcat(assoc_extra, " || "); xstrcat(name_extra, " || "); } xstrfmtcat(assoc_extra, "acct='%s'", object); xstrfmtcat(name_extra, "(name like '%%\\'%s\\'%%'" " || name='%s')" " || (info like '%%acct=\\'%s\\'%%')", object, object, object); set = 1; } list_iterator_destroy(itr); xstrcat(assoc_extra, ")"); xstrcat(name_extra, ")"); } if (txn_cond->cluster_list && list_count(txn_cond->cluster_list)) { set = 0; if (name_extra) xstrcat(name_extra, " && ("); else xstrcat(name_extra, "("); itr = list_iterator_create(txn_cond->cluster_list); while ((object = list_next(itr))) { if (set) { xstrcat(name_extra, " || "); } xstrfmtcat(name_extra, "(cluster='%s' || " "name like '%%\\'%s\\'%%' || name='%s')" " || (info like '%%cluster=\\'%s\\'%%')", object, object, object, object); set = 1; } list_iterator_destroy(itr); xstrcat(name_extra, ")"); use_cluster_list = txn_cond->cluster_list; } if (txn_cond->user_list && list_count(txn_cond->user_list)) { set = 0; if (assoc_extra) xstrcat(assoc_extra, " && ("); else xstrcat(assoc_extra, " where ("); if (name_extra) xstrcat(name_extra, " && ("); else xstrcat(name_extra, "("); itr = list_iterator_create(txn_cond->user_list); while ((object = list_next(itr))) { if (set) { xstrcat(assoc_extra, " || "); xstrcat(name_extra, " || "); } xstrfmtcat(assoc_extra, "user='******'", object); xstrfmtcat(name_extra, "(name like '%%\\'%s\\'%%'" " || name='%s')" " || (info like '%%user=\\'%s\\'%%')", object, object, object); set = 1; } list_iterator_destroy(itr); xstrcat(assoc_extra, ")"); xstrcat(name_extra, ")"); } if (assoc_extra) { if (!locked && (use_cluster_list == as_mysql_cluster_list)) { slurm_mutex_lock(&as_mysql_cluster_list_lock); locked = 1; } itr = list_iterator_create(use_cluster_list); while ((object = list_next(itr))) { xstrfmtcat(query, "select id_assoc from \"%s_%s\"%s", object, assoc_table, assoc_extra); if (debug_flags & DEBUG_FLAG_DB_QUERY) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); break; } xfree(query); if (mysql_num_rows(result)) { if (extra) xstrfmtcat(extra, " || (cluster='%s' && (", object); else xstrfmtcat(extra, " where (cluster='%s' && (", object); set = 0; while ((row = mysql_fetch_row(result))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "(name like " "'%%id_assoc=%s %%' " "|| name like " "'%%id_assoc=%s)')", row[0], row[0]); set = 1; } xstrcat(extra, "))"); } mysql_free_result(result); } list_iterator_destroy(itr); xfree(assoc_extra); } if (name_extra) { if (extra) xstrfmtcat(extra, " && (%s)", name_extra); else xstrfmtcat(extra, " where (%s)", name_extra); xfree(name_extra); } /*******************************************/ if (txn_cond->action_list && list_count(txn_cond->action_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(txn_cond->action_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "action='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (txn_cond->actor_list && list_count(txn_cond->actor_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(txn_cond->actor_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "actor='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (txn_cond->id_list && list_count(txn_cond->id_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(txn_cond->id_list); while ((object = list_next(itr))) { char *ptr = NULL; long num = strtol(object, &ptr, 10); if ((num == 0) && ptr && ptr[0]) { error("Invalid value for txn id (%s)", object); xfree(extra); list_iterator_destroy(itr); goto end_it; } if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "id=%s", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (txn_cond->info_list && list_count(txn_cond->info_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(txn_cond->info_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "info like '%%%s%%'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (txn_cond->name_list && list_count(txn_cond->name_list)) { set = 0; if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); itr = list_iterator_create(txn_cond->name_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "name like '%%%s%%'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (txn_cond->time_start && txn_cond->time_end) { if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); xstrfmtcat(extra, "timestamp < %ld && timestamp >= %ld)", txn_cond->time_end, txn_cond->time_start); } else if (txn_cond->time_start) { if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); xstrfmtcat(extra, "timestamp >= %ld)", txn_cond->time_start); } else if (txn_cond->time_end) { if (extra) xstrcat(extra, " && ("); else xstrcat(extra, " where ("); xstrfmtcat(extra, "timestamp < %ld)", txn_cond->time_end); } /* make sure we can get the max length out of the database * when grouping the names */ if (txn_cond->with_assoc_info) mysql_db_query(mysql_conn, "set session group_concat_max_len=65536;"); empty: if (!locked && (use_cluster_list == as_mysql_cluster_list)) { slurm_mutex_lock(&as_mysql_cluster_list_lock); locked = 1; } xfree(tmp); xstrfmtcat(tmp, "%s", txn_req_inx[i]); for(i=1; i<TXN_REQ_COUNT; i++) { xstrfmtcat(tmp, ", %s", txn_req_inx[i]); } query = xstrdup_printf("select %s from %s", tmp, txn_table); if (extra) { xstrfmtcat(query, "%s", extra); xfree(extra); } xstrcat(query, " order by timestamp;"); xfree(tmp); if (debug_flags & DEBUG_FLAG_DB_QUERY) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); goto end_it; } xfree(query); txn_list = list_create(slurmdb_destroy_txn_rec); while ((row = mysql_fetch_row(result))) { slurmdb_txn_rec_t *txn = xmalloc(sizeof(slurmdb_txn_rec_t)); list_append(txn_list, txn); txn->action = slurm_atoul(row[TXN_REQ_ACTION]); txn->actor_name = xstrdup(row[TXN_REQ_ACTOR]); txn->id = slurm_atoul(row[TXN_REQ_ID]); txn->set_info = xstrdup(row[TXN_REQ_INFO]); txn->timestamp = slurm_atoul(row[TXN_REQ_TS]); txn->where_query = xstrdup(row[TXN_REQ_NAME]); txn->clusters = xstrdup(row[TXN_REQ_CLUSTER]); if (txn_cond && txn_cond->with_assoc_info && (txn->action == DBD_ADD_ASSOCS || txn->action == DBD_MODIFY_ASSOCS || txn->action == DBD_REMOVE_ASSOCS)) { MYSQL_RES *result2 = NULL; MYSQL_ROW row2; if (txn->clusters) { query = xstrdup_printf( "select " "group_concat(distinct user " "order by user), " "group_concat(distinct acct " "order by acct) " "from \"%s_%s\" where %s", txn->clusters, assoc_table, row[TXN_REQ_NAME]); debug4("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); if (!(result2 = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); continue; } xfree(query); if ((row2 = mysql_fetch_row(result2))) { if (row2[0] && row2[0][0]) txn->users = xstrdup(row2[0]); if (row2[1] && row2[1][0]) txn->accts = xstrdup(row2[1]); } mysql_free_result(result2); } else { error("We can't handle associations " "from action %s yet.", slurmdbd_msg_type_2_str(txn->action, 1)); } } } mysql_free_result(result); end_it: if (locked) slurm_mutex_unlock(&as_mysql_cluster_list_lock); return txn_list; }
extern List as_mysql_remove_qos(mysql_conn_t *mysql_conn, uint32_t uid, slurmdb_qos_cond_t *qos_cond) { ListIterator itr = NULL; List ret_list = NULL; int rc = SLURM_SUCCESS; char *object = NULL; char *extra = NULL, *query = NULL, *name_char = NULL, *assoc_char = NULL; time_t now = time(NULL); char *user_name = NULL; int set = 0; MYSQL_RES *result = NULL; MYSQL_ROW row; if (!qos_cond) { error("we need something to change"); return NULL; } if (check_connection(mysql_conn) != SLURM_SUCCESS) return NULL; xstrcat(extra, "where deleted=0"); if (qos_cond->description_list && list_count(qos_cond->description_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->description_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "description='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (qos_cond->id_list && list_count(qos_cond->id_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->id_list); while ((object = list_next(itr))) { if (!object[0]) continue; if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "id='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (qos_cond->name_list && list_count(qos_cond->name_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->name_list); while ((object = list_next(itr))) { if (!object[0]) continue; if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "name='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (!extra) { error("Nothing to remove"); return NULL; } query = xstrdup_printf("select id, name from %s %s;", qos_table, extra); xfree(extra); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); return NULL; } name_char = NULL; ret_list = list_create(slurm_destroy_char); while ((row = mysql_fetch_row(result))) { slurmdb_qos_rec_t *qos_rec = NULL; list_append(ret_list, xstrdup(row[1])); if (!name_char) xstrfmtcat(name_char, "id='%s'", row[0]); else xstrfmtcat(name_char, " || id='%s'", row[0]); if (!assoc_char) xstrfmtcat(assoc_char, "id_qos='%s'", row[0]); else xstrfmtcat(assoc_char, " || id_qos='%s'", row[0]); xstrfmtcat(extra, ", qos=replace(qos, ',%s', '')" ", delta_qos=replace(delta_qos, ',+%s', '')" ", delta_qos=replace(delta_qos, ',-%s', '')", row[0], row[0], row[0]); qos_rec = xmalloc(sizeof(slurmdb_qos_rec_t)); /* we only need id when removing no real need to init */ qos_rec->id = slurm_atoul(row[0]); if (addto_update_list(mysql_conn->update_list, SLURMDB_REMOVE_QOS, qos_rec) != SLURM_SUCCESS) slurmdb_destroy_qos_rec(qos_rec); } mysql_free_result(result); if (!list_count(ret_list)) { errno = SLURM_NO_CHANGE_IN_DATA; debug3("didn't effect anything\n%s", query); xfree(query); return ret_list; } xfree(query); /* remove this qos from all the users/accts that have it */ query = xstrdup_printf("update %s set mod_time=%ld %s where deleted=0;", assoc_table, now, extra); xfree(extra); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); rc = mysql_db_query(mysql_conn, query); xfree(query); if (rc != SLURM_SUCCESS) { reset_mysql_conn(mysql_conn); list_destroy(ret_list); return NULL; } user_name = uid_to_string((uid_t) uid); slurm_mutex_lock(&as_mysql_cluster_list_lock); itr = list_iterator_create(as_mysql_cluster_list); while ((object = list_next(itr))) { if ((rc = remove_common(mysql_conn, DBD_REMOVE_QOS, now, user_name, qos_table, name_char, assoc_char, object, NULL, NULL)) != SLURM_SUCCESS) break; } list_iterator_destroy(itr); slurm_mutex_unlock(&as_mysql_cluster_list_lock); xfree(assoc_char); xfree(name_char); xfree(user_name); if (rc == SLURM_ERROR) { list_destroy(ret_list); return NULL; } return ret_list; }
extern List as_mysql_jobacct_process_get_jobs(mysql_conn_t *mysql_conn, uid_t uid, slurmdb_job_cond_t *job_cond) { char *extra = NULL; char *tmp = NULL, *tmp2 = NULL; ListIterator itr = NULL; int is_admin=1; int i; List job_list = NULL; uint16_t private_data = 0; slurmdb_user_rec_t user; int only_pending = 0; List use_cluster_list = as_mysql_cluster_list; char *cluster_name; assoc_mgr_lock_t locks = { NO_LOCK, NO_LOCK, NO_LOCK, NO_LOCK, READ_LOCK, NO_LOCK, NO_LOCK }; memset(&user, 0, sizeof(slurmdb_user_rec_t)); user.uid = uid; private_data = slurm_get_private_data(); if (private_data & PRIVATE_DATA_JOBS) { if (!(is_admin = is_user_min_admin_level( mysql_conn, uid, SLURMDB_ADMIN_OPERATOR))) { /* Only fill in the coordinator accounts here we will check them later when we actually try to get the jobs. */ is_user_any_coord(mysql_conn, &user); } if (!is_admin && !user.name) { debug("User %u has no assocations, and is not admin, " "so not returning any jobs.", user.uid); return NULL; } } if (job_cond && job_cond->state_list && (list_count(job_cond->state_list) == 1) && (slurm_atoul(list_peek(job_cond->state_list)) == JOB_PENDING)) only_pending = 1; setup_job_cond_limits(job_cond, &extra); xfree(tmp); xstrfmtcat(tmp, "%s", job_req_inx[0]); for(i=1; i<JOB_REQ_COUNT; i++) { xstrfmtcat(tmp, ", %s", job_req_inx[i]); } xfree(tmp2); xstrfmtcat(tmp2, "%s", step_req_inx[0]); for(i=1; i<STEP_REQ_COUNT; i++) { xstrfmtcat(tmp2, ", %s", step_req_inx[i]); } if (job_cond && job_cond->cluster_list && list_count(job_cond->cluster_list)) use_cluster_list = job_cond->cluster_list; else slurm_mutex_lock(&as_mysql_cluster_list_lock); assoc_mgr_lock(&locks); job_list = list_create(slurmdb_destroy_job_rec); itr = list_iterator_create(use_cluster_list); while ((cluster_name = list_next(itr))) { int rc; if ((rc = _cluster_get_jobs(mysql_conn, &user, job_cond, cluster_name, tmp, tmp2, extra, is_admin, only_pending, job_list)) != SLURM_SUCCESS) error("Problem getting jobs for cluster %s", cluster_name); } list_iterator_destroy(itr); assoc_mgr_unlock(&locks); if (use_cluster_list == as_mysql_cluster_list) slurm_mutex_unlock(&as_mysql_cluster_list_lock); xfree(tmp); xfree(tmp2); xfree(extra); return job_list; }
extern List as_mysql_get_qos(mysql_conn_t *mysql_conn, uid_t uid, slurmdb_qos_cond_t *qos_cond) { char *query = NULL; char *extra = NULL; char *tmp = NULL; List qos_list = NULL; ListIterator itr = NULL; char *object = NULL; int set = 0; int i=0; MYSQL_RES *result = NULL; MYSQL_ROW row; /* if this changes you will need to edit the corresponding enum */ char *qos_req_inx[] = { "name", "description", "id", "flags", "grace_time", "grp_cpu_mins", "grp_cpu_run_mins", "grp_cpus", "grp_jobs", "grp_nodes", "grp_submit_jobs", "grp_wall", "max_cpu_mins_per_job", "max_cpu_run_mins_per_user", "max_cpus_per_job", "max_jobs_per_user", "max_nodes_per_job", "max_submit_jobs_per_user", "max_wall_duration_per_job", "preempt", "preempt_mode", "priority", "usage_factor", "usage_thres", }; enum { QOS_REQ_NAME, QOS_REQ_DESC, QOS_REQ_ID, QOS_REQ_FLAGS, QOS_REQ_GRACE, QOS_REQ_GCM, QOS_REQ_GCRM, QOS_REQ_GC, QOS_REQ_GJ, QOS_REQ_GN, QOS_REQ_GSJ, QOS_REQ_GW, QOS_REQ_MCMPJ, QOS_REQ_MCRM, QOS_REQ_MCPJ, QOS_REQ_MJPU, QOS_REQ_MNPJ, QOS_REQ_MSJPU, QOS_REQ_MWPJ, QOS_REQ_PREE, QOS_REQ_PREEM, QOS_REQ_PRIO, QOS_REQ_UF, QOS_REQ_UT, QOS_REQ_COUNT }; if (check_connection(mysql_conn) != SLURM_SUCCESS) return NULL; if (!qos_cond) { xstrcat(extra, "where deleted=0"); goto empty; } if (qos_cond->with_deleted) xstrcat(extra, "where (deleted=0 || deleted=1)"); else xstrcat(extra, "where deleted=0"); if (qos_cond->description_list && list_count(qos_cond->description_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->description_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "description='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (qos_cond->id_list && list_count(qos_cond->id_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->id_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "id='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (qos_cond->name_list && list_count(qos_cond->name_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(qos_cond->name_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "name='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } empty: xfree(tmp); xstrfmtcat(tmp, "%s", qos_req_inx[i]); for(i=1; i<QOS_REQ_COUNT; i++) { xstrfmtcat(tmp, ", %s", qos_req_inx[i]); } query = xstrdup_printf("select %s from %s %s", tmp, qos_table, extra); xfree(tmp); xfree(extra); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); return NULL; } xfree(query); qos_list = list_create(slurmdb_destroy_qos_rec); while ((row = mysql_fetch_row(result))) { slurmdb_qos_rec_t *qos = xmalloc(sizeof(slurmdb_qos_rec_t)); list_append(qos_list, qos); if (row[QOS_REQ_DESC] && row[QOS_REQ_DESC][0]) qos->description = xstrdup(row[QOS_REQ_DESC]); qos->id = slurm_atoul(row[QOS_REQ_ID]); qos->flags = slurm_atoul(row[QOS_REQ_FLAGS]); if (row[QOS_REQ_NAME] && row[QOS_REQ_NAME][0]) qos->name = xstrdup(row[QOS_REQ_NAME]); if (row[QOS_REQ_GRACE]) qos->grace_time = slurm_atoul(row[QOS_REQ_GRACE]); else qos->grace_time = (uint32_t)NO_VAL; if (row[QOS_REQ_GCM]) qos->grp_cpu_mins = slurm_atoull(row[QOS_REQ_GCM]); else qos->grp_cpu_mins = INFINITE; if (row[QOS_REQ_GCRM]) qos->grp_cpu_run_mins = slurm_atoull(row[QOS_REQ_GCRM]); else qos->grp_cpu_run_mins = INFINITE; if (row[QOS_REQ_GC]) qos->grp_cpus = slurm_atoul(row[QOS_REQ_GC]); else qos->grp_cpus = INFINITE; if (row[QOS_REQ_GJ]) qos->grp_jobs = slurm_atoul(row[QOS_REQ_GJ]); else qos->grp_jobs = INFINITE; if (row[QOS_REQ_GN]) qos->grp_nodes = slurm_atoul(row[QOS_REQ_GN]); else qos->grp_nodes = INFINITE; if (row[QOS_REQ_GSJ]) qos->grp_submit_jobs = slurm_atoul(row[QOS_REQ_GSJ]); else qos->grp_submit_jobs = INFINITE; if (row[QOS_REQ_GW]) qos->grp_wall = slurm_atoul(row[QOS_REQ_GW]); else qos->grp_wall = INFINITE; if (row[QOS_REQ_MCMPJ]) qos->max_cpu_mins_pj = slurm_atoull(row[QOS_REQ_MCMPJ]); else qos->max_cpu_mins_pj = (uint64_t)INFINITE; if (row[QOS_REQ_MCRM]) qos->max_cpu_run_mins_pu = slurm_atoull(row[QOS_REQ_MCRM]); else qos->max_cpu_run_mins_pu = (uint64_t)INFINITE; if (row[QOS_REQ_MCPJ]) qos->max_cpus_pj = slurm_atoul(row[QOS_REQ_MCPJ]); else qos->max_cpus_pj = INFINITE; if (row[QOS_REQ_MJPU]) qos->max_jobs_pu = slurm_atoul(row[QOS_REQ_MJPU]); else qos->max_jobs_pu = INFINITE; if (row[QOS_REQ_MNPJ]) qos->max_nodes_pj = slurm_atoul(row[QOS_REQ_MNPJ]); else qos->max_nodes_pj = INFINITE; if (row[QOS_REQ_MSJPU]) qos->max_submit_jobs_pu = slurm_atoul(row[QOS_REQ_MSJPU]); else qos->max_submit_jobs_pu = INFINITE; if (row[QOS_REQ_MWPJ]) qos->max_wall_pj = slurm_atoul(row[QOS_REQ_MWPJ]); else qos->max_wall_pj = INFINITE; if (row[QOS_REQ_PREE] && row[QOS_REQ_PREE][0]) { if (!qos->preempt_bitstr) qos->preempt_bitstr = bit_alloc(g_qos_count); bit_unfmt(qos->preempt_bitstr, row[QOS_REQ_PREE]+1); } if (row[QOS_REQ_PREEM]) qos->preempt_mode = slurm_atoul(row[QOS_REQ_PREEM]); if (row[QOS_REQ_PRIO]) qos->priority = slurm_atoul(row[QOS_REQ_PRIO]); if (row[QOS_REQ_UF]) qos->usage_factor = atof(row[QOS_REQ_UF]); if (row[QOS_REQ_UT]) qos->usage_thres = atof(row[QOS_REQ_UT]); else qos->usage_thres = (double)INFINITE; } mysql_free_result(result); return qos_list; }
extern List setup_cluster_list_with_inx(mysql_conn_t *mysql_conn, slurmdb_job_cond_t *job_cond, void **curr_cluster) { List local_cluster_list = NULL; time_t now = time(NULL); MYSQL_RES *result = NULL; MYSQL_ROW row; hostlist_t temp_hl = NULL; hostlist_iterator_t h_itr = NULL; char *query = NULL; int dims = 0; if (!job_cond || !job_cond->used_nodes) return NULL; if (!job_cond->cluster_list || list_count(job_cond->cluster_list) != 1) { error("If you are doing a query against nodes " "you must only have 1 cluster " "you are asking for."); return NULL; } /* get the dimensions of this cluster so we know how to deal with the hostlists */ query = xstrdup_printf("select dimensions, flags from %s where " "name='%s'", cluster_table, (char *)list_peek(job_cond->cluster_list)); debug4("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); return NULL; } xfree(query); if (!(row = mysql_fetch_row(result))) { error("Couldn't get the dimensions of cluster '%s'.", (char *)list_peek(job_cond->cluster_list)); mysql_free_result(result); return NULL; } /* On a Cray System when dealing with hostlists as we are here this always needs to be 1. */ if (slurm_atoul(row[1]) & CLUSTER_FLAG_CRAY_A) dims = 1; else dims = atoi(row[0]); mysql_free_result(result); temp_hl = hostlist_create_dims(job_cond->used_nodes, dims); if (hostlist_count(temp_hl) <= 0) { error("we didn't get any real hosts to look for."); goto no_hosts; } h_itr = hostlist_iterator_create(temp_hl); query = xstrdup_printf("select cluster_nodes, time_start, " "time_end from \"%s_%s\" where node_name='' " "&& cluster_nodes !=''", (char *)list_peek(job_cond->cluster_list), event_table); if (job_cond->usage_start) { if (!job_cond->usage_end) job_cond->usage_end = now; xstrfmtcat(query, " && ((time_start < %ld) " "&& (time_end >= %ld || time_end = 0))", job_cond->usage_end, job_cond->usage_start); } if (debug_flags & DEBUG_FLAG_DB_JOB) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); goto no_hosts; } xfree(query); local_cluster_list = list_create(_destroy_local_cluster); while ((row = mysql_fetch_row(result))) { char *host = NULL; int loc = 0; local_cluster_t *local_cluster = xmalloc(sizeof(local_cluster_t)); local_cluster->hl = hostlist_create_dims(row[0], dims); local_cluster->start = slurm_atoul(row[1]); local_cluster->end = slurm_atoul(row[2]); local_cluster->asked_bitmap = bit_alloc(hostlist_count(local_cluster->hl)); while ((host = hostlist_next_dims(h_itr, dims))) { if ((loc = hostlist_find( local_cluster->hl, host)) != -1) bit_set(local_cluster->asked_bitmap, loc); free(host); } hostlist_iterator_reset(h_itr); if (bit_ffs(local_cluster->asked_bitmap) != -1) { list_append(local_cluster_list, local_cluster); if (local_cluster->end == 0) { local_cluster->end = now; (*curr_cluster) = local_cluster; } else if (!(*curr_cluster) || (((local_cluster_t *)(*curr_cluster))->end < local_cluster->end)) { (*curr_cluster) = local_cluster; } } else _destroy_local_cluster(local_cluster); } mysql_free_result(result); if (!list_count(local_cluster_list)) { FREE_NULL_LIST(local_cluster_list); local_cluster_list = NULL; goto no_hosts; } no_hosts: hostlist_iterator_destroy(h_itr); hostlist_destroy(temp_hl); return local_cluster_list; }
extern int as_mysql_cluster_cpus(mysql_conn_t *mysql_conn, char *cluster_nodes, uint32_t cpus, time_t event_time) { char* query; int rc = SLURM_SUCCESS; int first = 0; MYSQL_RES *result = NULL; MYSQL_ROW row; if (check_connection(mysql_conn) != SLURM_SUCCESS) return ESLURM_DB_CONNECTION; /* Record the processor count */ query = xstrdup_printf( "select cpu_count, cluster_nodes from \"%s_%s\" where " "time_end=0 and node_name='' and state=0 limit 1", mysql_conn->cluster_name, event_table); if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); if (mysql_errno(mysql_conn->db_conn) == ER_NO_SUCH_TABLE) rc = ESLURM_ACCESS_DENIED; else rc = SLURM_ERROR; return rc; } xfree(query); /* we only are checking the first one here */ if (!(row = mysql_fetch_row(result))) { debug("We don't have an entry for this machine %s " "most likely a first time running.", mysql_conn->cluster_name); /* Get all nodes in a down state and jobs pending or running. * This is for the first time a cluster registers * * We will return ACCOUNTING_FIRST_REG so this * is taken care of since the message thread * may not be up when we run this in the controller or * in the slurmdbd. */ if (!cpus) { rc = 0; goto end_it; } first = 1; goto add_it; } /* If cpus is 0 we want to return the cpu count for this cluster */ if (!cpus) { rc = atoi(row[0]); goto end_it; } if (slurm_atoul(row[0]) == cpus) { if (debug_flags & DEBUG_FLAG_DB_EVENT) DB_DEBUG(mysql_conn->conn, "we have the same cpu count as before for %s, " "no need to update the database.", mysql_conn->cluster_name); if (cluster_nodes) { if (!row[1][0]) { debug("Adding cluster nodes '%s' to " "last instance of cluster '%s'.", cluster_nodes, mysql_conn->cluster_name); query = xstrdup_printf( "update \"%s_%s\" set " "cluster_nodes='%s' " "where time_end=0 and node_name=''", mysql_conn->cluster_name, event_table, cluster_nodes); rc = mysql_db_query(mysql_conn, query); xfree(query); goto update_it; } else if (!strcmp(cluster_nodes, row[1])) { if (debug_flags & DEBUG_FLAG_DB_EVENT) DB_DEBUG(mysql_conn->conn, "we have the same nodes " "in the cluster " "as before no need to " "update the database."); goto update_it; } } else goto end_it; } else debug("%s has changed from %s cpus to %u", mysql_conn->cluster_name, row[0], cpus); /* reset all the entries for this cluster since the cpus changed some of the downed nodes may have gone away. Request them again with ACCOUNTING_FIRST_REG */ query = xstrdup_printf( "update \"%s_%s\" set time_end=%ld where time_end=0", mysql_conn->cluster_name, event_table, event_time); rc = mysql_db_query(mysql_conn, query); xfree(query); first = 1; if (rc != SLURM_SUCCESS) goto end_it; add_it: query = xstrdup_printf( "insert into \"%s_%s\" (cluster_nodes, cpu_count, " "time_start, reason) " "values ('%s', %u, %ld, 'Cluster processor count')", mysql_conn->cluster_name, event_table, cluster_nodes, cpus, event_time); rc = mysql_db_query(mysql_conn, query); xfree(query); update_it: query = xstrdup_printf( "update \"%s_%s\" set time_end=%ld where time_end=0 " "and state=%u and node_name='';", mysql_conn->cluster_name, event_table, event_time, NODE_STATE_DOWN); rc = mysql_db_query(mysql_conn, query); xfree(query); end_it: mysql_free_result(result); if (first && rc == SLURM_SUCCESS) rc = ACCOUNTING_FIRST_REG; return rc; }
extern List as_mysql_get_clusters(mysql_conn_t *mysql_conn, uid_t uid, slurmdb_cluster_cond_t *cluster_cond) { char *query = NULL; char *extra = NULL; char *tmp = NULL; List cluster_list = NULL; ListIterator itr = NULL; int i=0; MYSQL_RES *result = NULL; MYSQL_ROW row; slurmdb_assoc_cond_t assoc_cond; ListIterator assoc_itr = NULL; slurmdb_cluster_rec_t *cluster = NULL; slurmdb_assoc_rec_t *assoc = NULL; List assoc_list = NULL; /* if this changes you will need to edit the corresponding enum */ char *cluster_req_inx[] = { "name", "classification", "control_host", "control_port", "rpc_version", "dimensions", "flags", "plugin_id_select" }; enum { CLUSTER_REQ_NAME, CLUSTER_REQ_CLASS, CLUSTER_REQ_CH, CLUSTER_REQ_CP, CLUSTER_REQ_VERSION, CLUSTER_REQ_DIMS, CLUSTER_REQ_FLAGS, CLUSTER_REQ_PI_SELECT, CLUSTER_REQ_COUNT }; if (check_connection(mysql_conn) != SLURM_SUCCESS) return NULL; if (!cluster_cond) { xstrcat(extra, " where deleted=0"); goto empty; } _setup_cluster_cond_limits(cluster_cond, &extra); empty: xfree(tmp); i=0; xstrfmtcat(tmp, "%s", cluster_req_inx[i]); for(i=1; i<CLUSTER_REQ_COUNT; i++) { xstrfmtcat(tmp, ", %s", cluster_req_inx[i]); } query = xstrdup_printf("select %s from %s%s", tmp, cluster_table, extra); xfree(tmp); xfree(extra); if (debug_flags & DEBUG_FLAG_DB_ASSOC) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); return NULL; } xfree(query); cluster_list = list_create(slurmdb_destroy_cluster_rec); memset(&assoc_cond, 0, sizeof(slurmdb_assoc_cond_t)); if (cluster_cond) { /* I don't think we want the with_usage flag here. * We do need the with_deleted though. */ //assoc_cond.with_usage = cluster_cond->with_usage; assoc_cond.with_deleted = cluster_cond->with_deleted; } assoc_cond.cluster_list = list_create(NULL); while ((row = mysql_fetch_row(result))) { MYSQL_RES *result2 = NULL; MYSQL_ROW row2; cluster = xmalloc(sizeof(slurmdb_cluster_rec_t)); list_append(cluster_list, cluster); cluster->name = xstrdup(row[CLUSTER_REQ_NAME]); list_append(assoc_cond.cluster_list, cluster->name); cluster->classification = slurm_atoul(row[CLUSTER_REQ_CLASS]); cluster->control_host = xstrdup(row[CLUSTER_REQ_CH]); cluster->control_port = slurm_atoul(row[CLUSTER_REQ_CP]); cluster->rpc_version = slurm_atoul(row[CLUSTER_REQ_VERSION]); cluster->dimensions = slurm_atoul(row[CLUSTER_REQ_DIMS]); cluster->flags = slurm_atoul(row[CLUSTER_REQ_FLAGS]); cluster->plugin_id_select = slurm_atoul(row[CLUSTER_REQ_PI_SELECT]); query = xstrdup_printf( "select tres, cluster_nodes from " "\"%s_%s\" where time_end=0 and node_name='' limit 1", cluster->name, event_table); if (debug_flags & DEBUG_FLAG_DB_TRES) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result2 = mysql_db_query_ret(mysql_conn, query, 0))) { xfree(query); continue; } xfree(query); if ((row2 = mysql_fetch_row(result2))) { cluster->tres_str = xstrdup(row2[0]); if (row2[1] && row2[1][0]) cluster->nodes = xstrdup(row2[1]); } mysql_free_result(result2); /* get the usage if requested */ if (cluster_cond && cluster_cond->with_usage) { as_mysql_get_usage( mysql_conn, uid, cluster, DBD_GET_CLUSTER_USAGE, cluster_cond->usage_start, cluster_cond->usage_end); } } mysql_free_result(result); if (!list_count(assoc_cond.cluster_list)) { FREE_NULL_LIST(assoc_cond.cluster_list); return cluster_list; } assoc_cond.acct_list = list_create(NULL); list_append(assoc_cond.acct_list, "root"); assoc_cond.user_list = list_create(NULL); list_append(assoc_cond.user_list, ""); assoc_list = as_mysql_get_assocs(mysql_conn, uid, &assoc_cond); FREE_NULL_LIST(assoc_cond.cluster_list); FREE_NULL_LIST(assoc_cond.acct_list); FREE_NULL_LIST(assoc_cond.user_list); if (!assoc_list) return cluster_list; itr = list_iterator_create(cluster_list); assoc_itr = list_iterator_create(assoc_list); while ((cluster = list_next(itr))) { while ((assoc = list_next(assoc_itr))) { if (strcmp(assoc->cluster, cluster->name)) continue; if (cluster->root_assoc) { debug("This cluster %s already has " "an association.", cluster->name); continue; } cluster->root_assoc = assoc; list_remove(assoc_itr); } list_iterator_reset(assoc_itr); } list_iterator_destroy(itr); list_iterator_destroy(assoc_itr); if (list_count(assoc_list)) error("I have %d left over associations", list_count(assoc_list)); FREE_NULL_LIST(assoc_list); return cluster_list; }
/* * scontrol_update_job - update the slurm job configuration per the supplied * arguments * IN argc - count of arguments * IN argv - list of arguments * RET 0 if no slurm error, errno otherwise. parsing error prints * error message and returns 0 */ extern int scontrol_update_job(int argc, char **argv) { bool update_size = false; int i, update_cnt = 0, rc = SLURM_SUCCESS, rc2; char *tag, *val; int taglen, vallen; job_desc_msg_t job_msg; job_array_resp_msg_t *resp = NULL; uint32_t job_uid = NO_VAL; slurm_init_job_desc_msg (&job_msg); for (i = 0; i < argc; i++) { char *add_info = NULL; tag = argv[i]; val = strchr(argv[i], '='); if (val) { taglen = val - argv[i]; if ((taglen > 0) && ((val[-1] == '+') || (val[-1] == '-'))) { add_info = val - 1; taglen--; } val++; vallen = strlen(val); } else if (xstrncasecmp(tag, "Nice", MAX(strlen(tag), 2)) == 0){ /* "Nice" is the only tag that might not have an equal sign, so it is handled specially. */ job_msg.nice = NICE_OFFSET + 100; update_cnt++; continue; } else if (!val && argv[i + 1]) { tag = argv[i]; taglen = strlen(tag); val = argv[++i]; vallen = strlen(val); } else { exit_code = 1; fprintf (stderr, "Invalid input: %s\n", argv[i]); fprintf (stderr, "Request aborted\n"); return -1; } if (xstrncasecmp(tag, "JobId", MAX(taglen, 3)) == 0) { job_msg.job_id_str = val; } else if (xstrncasecmp(tag, "AdminComment", MAX(taglen, 3)) == 0) { if (add_info) { if (add_info[0] == '-') { error("Invalid syntax, AdminComment can not be subtracted from."); exit_code = 1; return 0; } job_msg.admin_comment = add_info; /* * Mark as unset so we know we handled this * correctly as there is a check later to make * sure we know we got a +-. */ add_info = NULL; } else job_msg.admin_comment = val; update_cnt++; } else if (xstrncasecmp(tag, "ArrayTaskThrottle", MAX(taglen, 10)) == 0) { int throttle; throttle = strtoll(val, (char **) NULL, 10); if (throttle < 0) { error("Invalid ArrayTaskThrottle value"); exit_code = 1; return 0; } job_msg.array_inx = val; update_cnt++; } else if (xstrncasecmp(tag, "Comment", MAX(taglen, 3)) == 0) { job_msg.comment = val; update_cnt++; } else if (xstrncasecmp(tag, "Clusters", MAX(taglen, 8)) == 0) { job_msg.clusters = val; update_cnt++; } else if (xstrncasecmp(tag, "ClusterFeatures", MAX(taglen, 8)) == 0) { job_msg.cluster_features = val; update_cnt++; } else if (xstrncasecmp(tag, "DelayBoot", MAX(taglen, 5)) == 0) { int time_sec = time_str2secs(val); if (time_sec == NO_VAL) { error("Invalid DelayBoot value"); exit_code = 1; return 0; } job_msg.delay_boot = time_sec; update_cnt++; } else if (xstrncasecmp(tag, "TimeLimit", MAX(taglen, 5)) == 0) { uint32_t job_current_time, time_limit; if (val && ((val[0] == '+') || (val[0] == '-'))) { if (add_info) { error("Invalid syntax, variations of +=- are not accepted."); exit_code = 1; return 0; } add_info = val; val++; } time_limit = time_str2mins(val); if (time_limit == NO_VAL) { error("Invalid TimeLimit value"); exit_code = 1; return 0; } if (add_info) { if (!job_msg.job_id_str) { error("JobId must precede TimeLimit " "increment or decrement"); exit_code = 1; return 0; } job_current_time = _get_job_time(job_msg. job_id_str); if (job_current_time == NO_VAL) { exit_code = 1; return 0; } if (add_info[0] == '+') { time_limit += job_current_time; } else if (time_limit > job_current_time) { error("TimeLimit decrement larger than" " current time limit (%u > %u)", time_limit, job_current_time); exit_code = 1; return 0; } else { time_limit = job_current_time - time_limit; } /* * Mark as unset so we know we handled this * correctly as there is a check later to make * sure we know we got a +-. */ add_info = NULL; } job_msg.time_limit = time_limit; update_cnt++; } else if (xstrncasecmp(tag, "TimeMin", MAX(taglen, 5)) == 0) { int time_min = time_str2mins(val); if ((time_min < 0) && (time_min != INFINITE)) { error("Invalid TimeMin value"); exit_code = 1; return 0; } job_msg.time_min = time_min; update_cnt++; } else if (xstrncasecmp(tag, "Priority", MAX(taglen, 2)) == 0) { if (parse_uint32(val, &job_msg.priority)) { error ("Invalid Priority value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "Nice", MAX(taglen, 2)) == 0) { long long tmp_nice; tmp_nice = strtoll(val, (char **)NULL, 10); if (llabs(tmp_nice) > (NICE_OFFSET - 3)) { error("Nice value out of range (+/- %u). Value " "ignored", NICE_OFFSET - 3); exit_code = 1; return 0; } job_msg.nice = NICE_OFFSET + tmp_nice; update_cnt++; } else if (!xstrncasecmp(tag, "CPUsPerTask", MAX(taglen, 9))) { if (parse_uint16(val, &job_msg.cpus_per_task)) { error("Invalid CPUsPerTask value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (!xstrncasecmp(tag, "CpusPerTres", MAX(taglen, 9))) { job_msg.cpus_per_tres = val; update_cnt++; } else if (xstrncasecmp(tag, "NumCPUs", MAX(taglen, 6)) == 0) { int min_cpus, max_cpus=0; if (!get_resource_arg_range(val, "NumCPUs", &min_cpus, &max_cpus, false) || (min_cpus <= 0) || (max_cpus && (max_cpus < min_cpus))) { error ("Invalid NumCPUs value: %s", val); exit_code = 1; return 0; } job_msg.min_cpus = min_cpus; if (max_cpus) job_msg.max_cpus = max_cpus; update_cnt++; } /* ReqProcs was removed in Slurm version 2.1 */ else if ((xstrncasecmp(tag, "NumTasks", MAX(taglen, 8)) == 0) || (xstrncasecmp(tag, "ReqProcs", MAX(taglen, 8)) == 0)) { if (parse_uint32(val, &job_msg.num_tasks)) { error ("Invalid NumTasks value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "Requeue", MAX(taglen, 4)) == 0) { if (parse_uint16(val, &job_msg.requeue)) { error ("Invalid Requeue value: %s", val); exit_code = 1; return 0; } update_cnt++; } /* ReqNodes was replaced by NumNodes in Slurm version 2.1 */ else if ((xstrncasecmp(tag, "ReqNodes", MAX(taglen, 8)) == 0) || (xstrncasecmp(tag, "NumNodes", MAX(taglen, 8)) == 0)) { int min_nodes, max_nodes, rc; if (xstrcmp(val, "0") == 0) { job_msg.min_nodes = 0; } else if (xstrcasecmp(val, "ALL") == 0) { job_msg.min_nodes = INFINITE; } else { min_nodes = (int) job_msg.min_nodes; max_nodes = (int) job_msg.max_nodes; rc = get_resource_arg_range( val, "requested node count", &min_nodes, &max_nodes, false); if (!rc) return rc; job_msg.min_nodes = (uint32_t) min_nodes; job_msg.max_nodes = (uint32_t) max_nodes; } update_size = true; update_cnt++; } else if (xstrncasecmp(tag, "ReqSockets", MAX(taglen, 4)) == 0) { if (parse_uint16(val, &job_msg.sockets_per_node)) { error ("Invalid ReqSockets value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "ReqCores", MAX(taglen, 4)) == 0) { if (parse_uint16(val, &job_msg.cores_per_socket)) { error ("Invalid ReqCores value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "TasksPerNode", MAX(taglen, 2))==0) { if (parse_uint16(val, &job_msg.ntasks_per_node)) { error ("Invalid TasksPerNode value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "ReqThreads", MAX(taglen, 4)) == 0) { if (parse_uint16(val, &job_msg.threads_per_core)) { error ("Invalid ReqThreads value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "MinCPUsNode", MAX(taglen, 4)) == 0) { if (parse_uint16(val, &job_msg.pn_min_cpus)) { error ("Invalid MinCPUsNode value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "MinMemoryNode", MAX(taglen, 10)) == 0) { if (parse_uint64(val, &job_msg.pn_min_memory)) { error ("Invalid MinMemoryNode value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "MinMemoryCPU", MAX(taglen, 10)) == 0) { if (parse_uint64(val, &job_msg.pn_min_memory)) { error ("Invalid MinMemoryCPU value: %s", val); exit_code = 1; return 0; } job_msg.pn_min_memory |= MEM_PER_CPU; update_cnt++; } else if (xstrncasecmp(tag, "MinTmpDiskNode", MAX(taglen, 5)) == 0) { if (parse_uint32(val, &job_msg.pn_min_tmp_disk)) { error ("Invalid MinTmpDiskNode value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "Partition", MAX(taglen, 2)) == 0) { job_msg.partition = val; update_cnt++; } else if (xstrncasecmp(tag, "QOS", MAX(taglen, 2)) == 0) { job_msg.qos = val; update_cnt++; } else if (xstrncasecmp(tag, "ReservationName", MAX(taglen, 3)) == 0) { job_msg.reservation = val; update_cnt++; } else if (!xstrncasecmp(tag, "Name", MAX(taglen, 2)) || !xstrncasecmp(tag, "JobName", MAX(taglen, 4))) { job_msg.name = val; update_cnt++; } else if (xstrncasecmp(tag, "WCKey", MAX(taglen, 1)) == 0) { job_msg.wckey = val; update_cnt++; } else if (xstrncasecmp(tag, "StdOut", MAX(taglen, 6)) == 0) { job_msg.std_out = val; update_cnt++; } else if (xstrncasecmp(tag, "Switches", MAX(taglen, 5)) == 0) { char *sep_char; job_msg.req_switch = (uint32_t) strtol(val, &sep_char, 10); update_cnt++; if (sep_char && sep_char[0] == '@') { job_msg.wait4switch = time_str2mins(sep_char+1) * 60; } } else if (xstrncasecmp(tag, "wait-for-switch", MAX(taglen, 5)) == 0) { if (parse_uint32(val, &job_msg.wait4switch)) { error ("Invalid wait-for-switch value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (!xstrncasecmp(tag, "OverSubscribe", MAX(taglen, 2)) || !xstrncasecmp(tag, "Shared", MAX(taglen, 2))) { if (xstrncasecmp(val, "YES", MAX(vallen, 1)) == 0) job_msg.shared = 1; else if (xstrncasecmp(val, "NO", MAX(vallen, 1)) == 0) job_msg.shared = 0; else if (parse_uint16(val, &job_msg.shared)) { error("Invalid OverSubscribe value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "Contiguous", MAX(taglen, 3)) == 0) { if (xstrncasecmp(val, "YES", MAX(vallen, 1)) == 0) job_msg.contiguous = 1; else if (xstrncasecmp(val, "NO", MAX(vallen, 1)) == 0) job_msg.contiguous = 0; else if (parse_uint16(val, &job_msg.contiguous)) { error ("Invalid Contiguous value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (xstrncasecmp(tag, "CoreSpec", MAX(taglen, 4)) == 0) { if (!xstrcmp(val, "-1") || !xstrcmp(val, "*")) job_msg.core_spec = INFINITE16; else if (parse_uint16(val, &job_msg.core_spec)) { error ("Invalid CoreSpec value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (!xstrncasecmp(tag, "MemPerTres", MAX(taglen, 5))) { job_msg.mem_per_tres = val; update_cnt++; } else if (xstrncasecmp(tag, "ThreadSpec", MAX(taglen, 4)) == 0) { if (!xstrcmp(val, "-1") || !xstrcmp(val, "*")) job_msg.core_spec = INFINITE16; else if (parse_uint16(val, &job_msg.core_spec)) { error ("Invalid ThreadSpec value: %s", val); exit_code = 1; return 0; } else job_msg.core_spec |= CORE_SPEC_THREAD; update_cnt++; } else if (!xstrncasecmp(tag, "TresBind", MAX(taglen, 5))) { job_msg.tres_bind = val; update_cnt++; } else if (!xstrncasecmp(tag, "TresFreq", MAX(taglen, 5))) { job_msg.tres_freq = val; update_cnt++; } else if (!xstrncasecmp(tag, "TresPerJob", MAX(taglen, 8))) { job_msg.tres_per_job = val; update_cnt++; } else if (!xstrncasecmp(tag, "TresPerNode", MAX(taglen, 8))) { /* "gres" replaced by "tres_per_node" in v18.08 */ if (job_msg.tres_per_node) xstrfmtcat(job_msg.tres_per_node, ",%s", val); else job_msg.tres_per_node = xstrdup(val); update_cnt++; } else if (!xstrncasecmp(tag, "TresPerSocket", MAX(taglen, 8))) { job_msg.tres_per_socket = val; update_cnt++; } else if (!xstrncasecmp(tag, "TresPerTask", MAX(taglen, 8))) { job_msg.tres_per_task = val; update_cnt++; } else if (xstrncasecmp(tag, "ExcNodeList", MAX(taglen, 3)) == 0){ job_msg.exc_nodes = val; update_cnt++; } else if (!xstrncasecmp(tag, "NodeList", MAX(taglen, 8)) || !xstrncasecmp(tag, "ReqNodeList", MAX(taglen, 8))) { job_msg.req_nodes = val; update_size = true; update_cnt++; } else if (xstrncasecmp(tag, "Features", MAX(taglen, 1)) == 0) { job_msg.features = val; update_cnt++; } else if (xstrncasecmp(tag, "Gres", MAX(taglen, 2)) == 0) { /* "gres" replaced by "tres_per_node" in v18.08 */ if (!xstrcasecmp(val, "help") || !xstrcasecmp(val, "list")) { print_gres_help(); } else if (job_msg.tres_per_node) { xstrfmtcat(job_msg.tres_per_node, ",%s", val); } else { job_msg.tres_per_node = xstrdup(val); update_cnt++; } } else if (xstrncasecmp(tag, "Account", MAX(taglen, 1)) == 0) { job_msg.account = val; update_cnt++; } else if (xstrncasecmp(tag, "BurstBuffer", MAX(taglen, 1)) == 0) { job_msg.burst_buffer = val; update_cnt++; } else if (xstrncasecmp(tag, "Dependency", MAX(taglen, 1)) == 0) { job_msg.dependency = val; update_cnt++; } else if (xstrncasecmp(tag, "Licenses", MAX(taglen, 1)) == 0) { job_msg.licenses = val; update_cnt++; } else if (!xstrncasecmp(tag, "EligibleTime", MAX(taglen, 2)) || !xstrncasecmp(tag, "StartTime", MAX(taglen, 2))) { if ((job_msg.begin_time = parse_time(val, 0))) { if (job_msg.begin_time < time(NULL)) job_msg.begin_time = time(NULL); update_cnt++; } } else if (!xstrncasecmp(tag, "EndTime", MAX(taglen, 2))) { job_msg.end_time = parse_time(val, 0); update_cnt++; } else if (!xstrncasecmp(tag, "Reboot", MAX(taglen, 3))) { if (xstrncasecmp(val, "YES", MAX(vallen, 1)) == 0) job_msg.reboot = 1; else if (xstrncasecmp(val, "NO", MAX(vallen, 1)) == 0) job_msg.reboot = 0; else if (parse_uint16(val, &job_msg.reboot)) { error ("Invalid reboot value: %s", val); exit_code = 1; return 0; } update_cnt++; } else if (!xstrncasecmp(tag, "UserID", MAX(taglen, 3))) { uid_t user_id = 0; if (uid_from_string(val, &user_id) < 0) { exit_code = 1; fprintf (stderr, "Invalid UserID: %s\n", val); fprintf (stderr, "Request aborted\n"); return 0; } job_uid = (uint32_t) user_id; } else if (!xstrncasecmp(tag, "Deadline", MAX(taglen, 3))) { if ((job_msg.deadline = parse_time(val, 0))) { update_cnt++; } } else { exit_code = 1; fprintf (stderr, "Update of this parameter is not " "supported: %s\n", argv[i]); fprintf (stderr, "Request aborted\n"); return 0; } if (add_info) { error("Option %s does not accept [+|-]= syntax", tag); exit_code = 1; return 0; } } if (update_cnt == 0) { exit_code = 1; fprintf (stderr, "No changes specified\n"); return 0; } /* If specified, override uid with effective uid provided by * -u <uid> or --uid=<uid> */ if (euid != NO_VAL) job_msg.user_id = euid; if (!job_msg.job_id_str && job_msg.name) { /* Translate name to job ID string */ job_msg.job_id_str = _job_name2id(job_msg.name, job_uid); if (!job_msg.job_id_str) { exit_code = 1; return 0; } } if (!job_msg.job_id_str) { error("No job ID specified"); exit_code = 1; return 0; } if (update_size && !_is_single_job(job_msg.job_id_str)) { exit_code = 1; return 0; } if (_is_job_id(job_msg.job_id_str)) { job_msg.job_id_str = _next_job_id(); while (job_msg.job_id_str) { rc2 = slurm_update_job2(&job_msg, &resp); if (update_size && (rc2 == SLURM_SUCCESS)) { /* See check above for one job ID */ job_msg.job_id = slurm_atoul(job_msg.job_id_str); _update_job_size(job_msg.job_id); } if (rc2 != SLURM_SUCCESS) { rc2 = slurm_get_errno(); rc = MAX(rc, rc2); exit_code = 1; if (quiet_flag != 1) { fprintf(stderr, "%s for job %s\n", slurm_strerror(slurm_get_errno()), job_msg.job_id_str); } } else if (resp) { for (i = 0; i < resp->job_array_count; i++) { if ((resp->error_code[i] == SLURM_SUCCESS) && (resp->job_array_count == 1)) continue; exit_code = 1; if (quiet_flag == 1) continue; fprintf(stderr, "%s: %s\n", resp->job_array_id[i], slurm_strerror(resp-> error_code[i])); } slurm_free_job_array_resp(resp); resp = NULL; } job_msg.job_id_str = _next_job_id(); } } else if (job_msg.job_id_str) { exit_code = 1; rc = ESLURM_INVALID_JOB_ID; slurm_seterrno(rc); if (quiet_flag != 1) { fprintf(stderr, "%s for job %s\n", slurm_strerror(rc), job_msg.job_id_str); } } return rc; }
static int _set_rec(int *start, int argc, char **argv, List name_list, slurmdb_assoc_rec_t *assoc, slurmdb_cluster_rec_t *cluster) { int i; int rec_set = 0; int assoc_set = 0; int end = 0; int command_len = 0; int option = 0; for (i=(*start); i<argc; i++) { end = parse_option_end(argv[i]); if (!end) command_len=strlen(argv[i]); else { command_len=end-1; if (argv[i][end] == '=') { option = (int)argv[i][end-1]; end++; } } if (!strncasecmp(argv[i], "Where", MAX(command_len, 5))) { i--; break; } else if (!end && !strncasecmp(argv[i], "set", MAX(command_len, 3))) { continue; } else if (!end || !strncasecmp(argv[i], "Names", MAX(command_len, 1)) || !strncasecmp(argv[i], "Clusters", MAX(command_len, 3))) { if (name_list) slurm_addto_char_list(name_list, argv[i]+end); } else if (!strncasecmp(argv[i], "Classification", MAX(command_len, 3))) { if (cluster) { cluster->classification = str_2_classification(argv[i]+end); if (cluster->classification) rec_set = 1; } } else if (!strncasecmp(argv[i], "Federation", MAX(command_len, 3))) { if (cluster) { cluster->fed.name = xstrdup(argv[i]+end); rec_set = 1; } } else if (!strncasecmp(argv[i], "FedState", MAX(command_len, 2))) { if (cluster) { cluster->fed.state = str_2_cluster_fed_states(argv[i]+end); if (!cluster->fed.state) { exit_code=1; fprintf(stderr, "Invalid FedState " "%s.\n", argv[i]+end); break; } rec_set = 1; } } else if (!strncasecmp(argv[i], "Weight", MAX(command_len, 2))) { if (cluster) { cluster->fed.weight = slurm_atoul(argv[i]+end); rec_set = 1; } } else if (!strncasecmp(argv[i], "GrpCPURunMins", MAX(command_len, 7)) || !strncasecmp(argv[i], "GrpTRESRunMins", MAX(command_len, 8))) { exit_code=1; fprintf(stderr, "GrpTRESRunMins is not a valid option " "for the root association of a cluster.\n"); break; } else if (!strncasecmp(argv[i], "GrpCPUMins", MAX(command_len, 7)) || !strncasecmp(argv[i], "GrpTRESMins", MAX(command_len, 8))) { exit_code=1; fprintf(stderr, "GrpTRESMins is not a valid option " "for the root association of a cluster.\n"); break; } else if (!strncasecmp(argv[i], "GrpWall", MAX(command_len, 4))) { exit_code=1; fprintf(stderr, "GrpWall is not a valid option " "for the root association of a cluster.\n"); } else if (!assoc || (assoc && !(assoc_set = sacctmgr_set_assoc_rec( assoc, argv[i], argv[i]+end, command_len, option)))) { exit_code=1; fprintf(stderr, " Unknown option: %s\n" " Use keyword 'where' to modify condition\n", argv[i]); } } (*start) = i; if (rec_set && assoc_set) return CLUS_REC_SET | CLUS_ASSOC_SET; else if (rec_set) return CLUS_REC_SET; else if (assoc_set) return CLUS_ASSOC_SET; return 0; }
extern List as_mysql_get_users(mysql_conn_t *mysql_conn, uid_t uid, slurmdb_user_cond_t *user_cond) { char *query = NULL; char *extra = NULL; char *tmp = NULL; List user_list = NULL; ListIterator itr = NULL; char *object = NULL; int set = 0; int i=0, is_admin=1; MYSQL_RES *result = NULL; MYSQL_ROW row; uint16_t private_data = 0; slurmdb_user_rec_t user; /* if this changes you will need to edit the corresponding enum */ char *user_req_inx[] = { "name", "admin_level" }; enum { USER_REQ_NAME, USER_REQ_AL, USER_REQ_COUNT }; if (check_connection(mysql_conn) != SLURM_SUCCESS) return NULL; memset(&user, 0, sizeof(slurmdb_user_rec_t)); user.uid = uid; private_data = slurm_get_private_data(); if (private_data & PRIVATE_DATA_USERS) { if (!(is_admin = is_user_min_admin_level( mysql_conn, uid, SLURMDB_ADMIN_OPERATOR))) { assoc_mgr_fill_in_user( mysql_conn, &user, 1, NULL); } if (!is_admin && !user.name) { debug("User %u has no assocations, and is not admin, " "so not returning any users.", user.uid); return NULL; } } if (!user_cond) { xstrcat(extra, "where deleted=0"); set = 1; goto empty; } if (user_cond->with_deleted) xstrcat(extra, "where (deleted=0 || deleted=1)"); else xstrcat(extra, "where deleted=0"); user_list = _get_other_user_names_to_mod(mysql_conn, uid, user_cond); if (user_list) { if (!user_cond->assoc_cond) user_cond->assoc_cond = xmalloc(sizeof(slurmdb_association_rec_t)); if (!user_cond->assoc_cond->user_list) user_cond->assoc_cond->user_list = user_list; else { list_transfer(user_cond->assoc_cond->user_list, user_list); list_destroy(user_list); } user_list = NULL; } else if ((user_cond->def_acct_list && list_count(user_cond->def_acct_list)) || (user_cond->def_wckey_list && list_count(user_cond->def_wckey_list))) return NULL; if (user_cond->assoc_cond && user_cond->assoc_cond->user_list && list_count(user_cond->assoc_cond->user_list)) { set = 0; xstrcat(extra, " && ("); itr = list_iterator_create(user_cond->assoc_cond->user_list); while ((object = list_next(itr))) { if (set) xstrcat(extra, " || "); xstrfmtcat(extra, "name='%s'", object); set = 1; } list_iterator_destroy(itr); xstrcat(extra, ")"); } if (user_cond->admin_level != SLURMDB_ADMIN_NOTSET) { xstrfmtcat(extra, " && admin_level=%u", user_cond->admin_level); set = 1; } empty: /* This is here to make sure we are looking at only this user * if this flag is set. */ if (!is_admin && (private_data & PRIVATE_DATA_USERS)) { xstrfmtcat(extra, " && name='%s'", user.name); } xfree(tmp); xstrfmtcat(tmp, "%s", user_req_inx[0]); for(i=1; i<USER_REQ_COUNT; i++) { xstrfmtcat(tmp, ", %s", user_req_inx[i]); } query = xstrdup_printf("select %s from %s %s", tmp, user_table, extra); xfree(tmp); xfree(extra); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); return NULL; } xfree(query); user_list = list_create(slurmdb_destroy_user_rec); while ((row = mysql_fetch_row(result))) { slurmdb_user_rec_t *user = xmalloc(sizeof(slurmdb_user_rec_t)); list_append(user_list, user); user->name = xstrdup(row[USER_REQ_NAME]); user->admin_level = slurm_atoul(row[USER_REQ_AL]); if (user_cond && user_cond->with_coords) _get_user_coords(mysql_conn, user); } mysql_free_result(result); if (user_cond && (user_cond->with_assocs || (user_cond->assoc_cond && user_cond->assoc_cond->only_defs))) { ListIterator assoc_itr = NULL; slurmdb_user_rec_t *user = NULL; slurmdb_association_rec_t *assoc = NULL; List assoc_list = NULL; /* Make sure we don't get any non-user associations * this is done by at least having a user_list * defined */ if (!user_cond->assoc_cond) user_cond->assoc_cond = xmalloc(sizeof(slurmdb_association_cond_t)); if (!user_cond->assoc_cond->user_list) user_cond->assoc_cond->user_list = list_create(NULL); user_cond->assoc_cond->with_deleted = user_cond->with_deleted; assoc_list = as_mysql_get_assocs( mysql_conn, uid, user_cond->assoc_cond); if (!assoc_list) { error("no associations"); goto get_wckeys; } itr = list_iterator_create(user_list); assoc_itr = list_iterator_create(assoc_list); while ((user = list_next(itr))) { while ((assoc = list_next(assoc_itr))) { if (strcmp(assoc->user, user->name)) continue; /* Set up the default. This is needed * for older versions primarily that * don't have the notion of default * account per cluster. */ if (!user->default_acct && (assoc->is_def == 1)) user->default_acct = xstrdup(assoc->acct); if (!user_cond->with_assocs) { /* We just got the default so no reason to hang around if we aren't getting the associations. */ if (user->default_acct) break; else continue; } if (!user->assoc_list) user->assoc_list = list_create( slurmdb_destroy_association_rec); list_append(user->assoc_list, assoc); list_remove(assoc_itr); } list_iterator_reset(assoc_itr); } list_iterator_destroy(itr); list_iterator_destroy(assoc_itr); list_destroy(assoc_list); } get_wckeys: if (user_cond && (user_cond->with_wckeys || (user_cond->assoc_cond && user_cond->assoc_cond->only_defs))) { ListIterator wckey_itr = NULL; slurmdb_user_rec_t *user = NULL; slurmdb_wckey_rec_t *wckey = NULL; List wckey_list = NULL; slurmdb_wckey_cond_t wckey_cond; memset(&wckey_cond, 0, sizeof(slurmdb_wckey_cond_t)); if (user_cond->assoc_cond) { wckey_cond.user_list = user_cond->assoc_cond->user_list; wckey_cond.cluster_list = user_cond->assoc_cond->cluster_list; wckey_cond.only_defs = user_cond->assoc_cond->only_defs; } wckey_list = as_mysql_get_wckeys(mysql_conn, uid, &wckey_cond); if (!wckey_list) return user_list; itr = list_iterator_create(user_list); wckey_itr = list_iterator_create(wckey_list); while ((user = list_next(itr))) { while ((wckey = list_next(wckey_itr))) { if (strcmp(wckey->user, user->name)) continue; /* Set up the default. This is needed * for older versions primarily that * don't have the notion of default * wckey per cluster. */ if (!user->default_wckey && (wckey->is_def == 1)) user->default_wckey = xstrdup(wckey->name); /* We just got the default so no reason to hang around if we aren't getting the wckeys. */ if (!user_cond->with_wckeys) { /* We just got the default so no reason to hang around if we aren't getting the wckeys. */ if (user->default_wckey) break; else continue; } if (!user->wckey_list) user->wckey_list = list_create( slurmdb_destroy_wckey_rec); list_append(user->wckey_list, wckey); list_remove(wckey_itr); } list_iterator_reset(wckey_itr); /* If a user doesn't have a default wckey (they might not of had track_wckeys on), set it now. */ if (!user->default_wckey) user->default_wckey = xstrdup(""); } list_iterator_destroy(itr); list_iterator_destroy(wckey_itr); list_destroy(wckey_list); } return user_list; }
extern int as_mysql_hourly_rollup(mysql_conn_t *mysql_conn, char *cluster_name, time_t start, time_t end, uint16_t archive_data) { int rc = SLURM_SUCCESS; int add_sec = 3600; int i=0; time_t now = time(NULL); time_t curr_start = start; time_t curr_end = curr_start + add_sec; char *query = NULL; MYSQL_RES *result = NULL; MYSQL_ROW row; ListIterator a_itr = NULL; ListIterator c_itr = NULL; ListIterator w_itr = NULL; ListIterator r_itr = NULL; List assoc_usage_list = list_create(_destroy_local_id_usage); List cluster_down_list = list_create(_destroy_local_cluster_usage); List wckey_usage_list = list_create(_destroy_local_id_usage); List resv_usage_list = list_create(_destroy_local_resv_usage); uint16_t track_wckey = slurm_get_track_wckey(); /* char start_char[20], end_char[20]; */ char *job_req_inx[] = { "job.job_db_inx", "job.id_job", "job.id_assoc", "job.id_wckey", "job.array_task_pending", "job.time_eligible", "job.time_start", "job.time_end", "job.time_suspended", "job.cpus_alloc", "job.cpus_req", "job.id_resv", "SUM(step.consumed_energy)" }; char *job_str = NULL; enum { JOB_REQ_DB_INX, JOB_REQ_JOBID, JOB_REQ_ASSOCID, JOB_REQ_WCKEYID, JOB_REQ_ARRAY_PENDING, JOB_REQ_ELG, JOB_REQ_START, JOB_REQ_END, JOB_REQ_SUSPENDED, JOB_REQ_ACPU, JOB_REQ_RCPU, JOB_REQ_RESVID, JOB_REQ_ENERGY, JOB_REQ_COUNT }; char *suspend_req_inx[] = { "time_start", "time_end" }; char *suspend_str = NULL; enum { SUSPEND_REQ_START, SUSPEND_REQ_END, SUSPEND_REQ_COUNT }; char *resv_req_inx[] = { "id_resv", "assoclist", "cpus", "flags", "time_start", "time_end" }; char *resv_str = NULL; enum { RESV_REQ_ID, RESV_REQ_ASSOCS, RESV_REQ_CPU, RESV_REQ_FLAGS, RESV_REQ_START, RESV_REQ_END, RESV_REQ_COUNT }; i=0; xstrfmtcat(job_str, "%s", job_req_inx[i]); for(i=1; i<JOB_REQ_COUNT; i++) { xstrfmtcat(job_str, ", %s", job_req_inx[i]); } i=0; xstrfmtcat(suspend_str, "%s", suspend_req_inx[i]); for(i=1; i<SUSPEND_REQ_COUNT; i++) { xstrfmtcat(suspend_str, ", %s", suspend_req_inx[i]); } i=0; xstrfmtcat(resv_str, "%s", resv_req_inx[i]); for(i=1; i<RESV_REQ_COUNT; i++) { xstrfmtcat(resv_str, ", %s", resv_req_inx[i]); } /* info("begin start %s", slurm_ctime(&curr_start)); */ /* info("begin end %s", slurm_ctime(&curr_end)); */ a_itr = list_iterator_create(assoc_usage_list); c_itr = list_iterator_create(cluster_down_list); w_itr = list_iterator_create(wckey_usage_list); r_itr = list_iterator_create(resv_usage_list); while (curr_start < end) { int last_id = -1; int last_wckeyid = -1; int seconds = 0; int tot_time = 0; local_cluster_usage_t *loc_c_usage = NULL; local_cluster_usage_t *c_usage = NULL; local_resv_usage_t *r_usage = NULL; local_id_usage_t *a_usage = NULL; local_id_usage_t *w_usage = NULL; if (debug_flags & DEBUG_FLAG_DB_USAGE) DB_DEBUG(mysql_conn->conn, "%s curr hour is now %ld-%ld", cluster_name, curr_start, curr_end); /* info("start %s", slurm_ctime(&curr_start)); */ /* info("end %s", slurm_ctime(&curr_end)); */ c_usage = _setup_cluster_usage(mysql_conn, cluster_name, curr_start, curr_end, cluster_down_list); // now get the reservations during this time /* If a reservation has the IGNORE_JOBS flag we don't * have an easy way to distinguish the cpus a job not * running in the reservation, but on it's cpus. * So we will just ignore these reservations for * accounting purposes. */ query = xstrdup_printf("select %s from \"%s_%s\" where " "(time_start < %ld && time_end >= %ld) " "&& !(flags & %u)" "order by time_start", resv_str, cluster_name, resv_table, curr_end, curr_start, RESERVE_FLAG_IGN_JOBS); if (debug_flags & DEBUG_FLAG_DB_USAGE) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); _destroy_local_cluster_usage(c_usage); return SLURM_ERROR; } xfree(query); /* If a reservation overlaps another reservation we total up everything here as if they didn't but when calculating the total time for a cluster we will remove the extra time received. This may result in unexpected results with association based reports since the association is given the total amount of time of each reservation, thus equaling more time than is available. Job/Cluster/Reservation reports should be fine though since we really don't over allocate resources. The issue with us not being able to handle overlapping reservations here is unless the reservation completely overlaps the other reservation we have no idea how many cpus should be removed since this could be a heterogeneous system. This same problem exists when a reservation is created with the ignore_jobs option which will allow jobs to continue to run in the reservation that aren't suppose to. */ while ((row = mysql_fetch_row(result))) { time_t row_start = slurm_atoul(row[RESV_REQ_START]); time_t row_end = slurm_atoul(row[RESV_REQ_END]); uint32_t row_cpu = slurm_atoul(row[RESV_REQ_CPU]); uint32_t row_flags = slurm_atoul(row[RESV_REQ_FLAGS]); if (row_start < curr_start) row_start = curr_start; if (!row_end || row_end > curr_end) row_end = curr_end; /* Don't worry about it if the time is less * than 1 second. */ if ((row_end - row_start) < 1) continue; r_usage = xmalloc(sizeof(local_resv_usage_t)); r_usage->id = slurm_atoul(row[RESV_REQ_ID]); r_usage->local_assocs = list_create(slurm_destroy_char); slurm_addto_char_list(r_usage->local_assocs, row[RESV_REQ_ASSOCS]); r_usage->total_time = (row_end - row_start) * row_cpu; r_usage->start = row_start; r_usage->end = row_end; list_append(resv_usage_list, r_usage); /* Since this reservation was added to the cluster and only certain people could run there we will use this as allocated time on the system. If the reservation was a maintenance then we add the time to planned down time. */ /* only record time for the clusters that have registered. This continue should rarely if ever happen. */ if (!c_usage) continue; else if (row_flags & RESERVE_FLAG_MAINT) c_usage->pd_cpu += r_usage->total_time; else c_usage->a_cpu += r_usage->total_time; /* slurm_make_time_str(&r_usage->start, start_char, */ /* sizeof(start_char)); */ /* slurm_make_time_str(&r_usage->end, end_char, */ /* sizeof(end_char)); */ /* info("adding this much %lld to cluster %s " */ /* "%d %d %s - %s", */ /* r_usage->total_time, c_usage->name, */ /* (row_flags & RESERVE_FLAG_MAINT), */ /* r_usage->id, start_char, end_char); */ } mysql_free_result(result); /* now get the jobs during this time only */ query = xstrdup_printf("select %s from \"%s_%s\" as job " "left outer join \"%s_%s\" as step on " "job.job_db_inx=step.job_db_inx " "and (step.id_step>=0) " "where (job.time_eligible < %ld && " "(job.time_end >= %ld || " "job.time_end = 0)) " "group by job.job_db_inx " "order by job.id_assoc, " "job.time_eligible", job_str, cluster_name, job_table, cluster_name, step_table, curr_end, curr_start); if (debug_flags & DEBUG_FLAG_DB_USAGE) DB_DEBUG(mysql_conn->conn, "query\n%s", query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); _destroy_local_cluster_usage(c_usage); return SLURM_ERROR; } xfree(query); while ((row = mysql_fetch_row(result))) { uint32_t job_id = slurm_atoul(row[JOB_REQ_JOBID]); uint32_t assoc_id = slurm_atoul(row[JOB_REQ_ASSOCID]); uint32_t wckey_id = slurm_atoul(row[JOB_REQ_WCKEYID]); uint32_t array_pending = slurm_atoul(row[JOB_REQ_ARRAY_PENDING]); uint32_t resv_id = slurm_atoul(row[JOB_REQ_RESVID]); time_t row_eligible = slurm_atoul(row[JOB_REQ_ELG]); time_t row_start = slurm_atoul(row[JOB_REQ_START]); time_t row_end = slurm_atoul(row[JOB_REQ_END]); uint32_t row_acpu = slurm_atoul(row[JOB_REQ_ACPU]); uint32_t row_rcpu = slurm_atoul(row[JOB_REQ_RCPU]); uint64_t row_energy = 0; int loc_seconds = 0; seconds = 0; if (row[JOB_REQ_ENERGY]) row_energy = slurm_atoull(row[JOB_REQ_ENERGY]); if (row_start && (row_start < curr_start)) row_start = curr_start; if (!row_start && row_end) row_start = row_end; if (!row_end || row_end > curr_end) row_end = curr_end; if (!row_start || ((row_end - row_start) < 1)) goto calc_cluster; seconds = (row_end - row_start); if (slurm_atoul(row[JOB_REQ_SUSPENDED])) { MYSQL_RES *result2 = NULL; MYSQL_ROW row2; /* get the suspended time for this job */ query = xstrdup_printf( "select %s from \"%s_%s\" where " "(time_start < %ld && (time_end >= %ld " "|| time_end = 0)) && job_db_inx=%s " "order by time_start", suspend_str, cluster_name, suspend_table, curr_end, curr_start, row[JOB_REQ_DB_INX]); debug4("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); if (!(result2 = mysql_db_query_ret( mysql_conn, query, 0))) { xfree(query); _destroy_local_cluster_usage(c_usage); return SLURM_ERROR; } xfree(query); while ((row2 = mysql_fetch_row(result2))) { time_t local_start = slurm_atoul( row2[SUSPEND_REQ_START]); time_t local_end = slurm_atoul( row2[SUSPEND_REQ_END]); if (!local_start) continue; if (row_start > local_start) local_start = row_start; if (row_end < local_end) local_end = row_end; tot_time = (local_end - local_start); if (tot_time < 1) continue; seconds -= tot_time; } mysql_free_result(result2); } if (seconds < 1) { debug4("This job (%u) was suspended " "the entire hour", job_id); continue; } if (last_id != assoc_id) { a_usage = xmalloc(sizeof(local_id_usage_t)); a_usage->id = assoc_id; list_append(assoc_usage_list, a_usage); last_id = assoc_id; } a_usage->a_cpu += seconds * row_acpu; a_usage->energy += row_energy; if (!track_wckey) goto calc_cluster; /* do the wckey calculation */ if (last_wckeyid != wckey_id) { list_iterator_reset(w_itr); while ((w_usage = list_next(w_itr))) if (w_usage->id == wckey_id) break; if (!w_usage) { w_usage = xmalloc( sizeof(local_id_usage_t)); w_usage->id = wckey_id; list_append(wckey_usage_list, w_usage); } last_wckeyid = wckey_id; } w_usage->a_cpu += seconds * row_acpu; w_usage->energy += row_energy; /* do the cluster allocated calculation */ calc_cluster: /* Now figure out there was a disconnected slurmctld durning this job. */ list_iterator_reset(c_itr); while ((loc_c_usage = list_next(c_itr))) { int temp_end = row_end; int temp_start = row_start; if (loc_c_usage->start > temp_start) temp_start = loc_c_usage->start; if (loc_c_usage->end < temp_end) temp_end = loc_c_usage->end; loc_seconds = (temp_end - temp_start); if (loc_seconds < 1) continue; loc_seconds *= row_acpu; /* info(" Job %u was running for " */ /* "%d seconds while " */ /* "cluster %s's slurmctld " */ /* "wasn't responding", */ /* job_id, loc_seconds, cluster_name); */ if (loc_seconds >= loc_c_usage->total_time) loc_c_usage->total_time = 0; else { loc_c_usage->total_time -= loc_seconds * row_acpu; } } /* first figure out the reservation */ if (resv_id) { if (seconds <= 0) continue; /* Since we have already added the entire reservation as used time on the cluster we only need to calculate the used time for the reservation and then divy up the unused time over the associations able to run in the reservation. Since the job was to run, or ran a reservation we don't care about eligible time since that could totally skew the clusters reserved time since the job may be able to run outside of the reservation. */ list_iterator_reset(r_itr); while ((r_usage = list_next(r_itr))) { /* since the reservation could have changed in some way, thus making a new reservation record in the database, we have to make sure all the reservations are checked to see if such a thing has happened */ if (r_usage->id == resv_id) { int temp_end = row_end; int temp_start = row_start; if (r_usage->start > temp_start) temp_start = r_usage->start; if (r_usage->end < temp_end) temp_end = r_usage->end; if ((temp_end - temp_start) > 0) { r_usage->a_cpu += (temp_end - temp_start) * row_acpu; } } } continue; } /* only record time for the clusters that have registered. This continue should rarely if ever happen. */ if (!c_usage) continue; if (row_start && (seconds > 0)) { /* info("%d assoc %d adds " */ /* "(%d)(%d-%d) * %d = %d " */ /* "to %d", */ /* job_id, */ /* a_usage->id, */ /* seconds, */ /* row_end, row_start, */ /* row_acpu, */ /* seconds * row_acpu, */ /* row_acpu); */ c_usage->a_cpu += seconds * row_acpu; c_usage->energy += row_energy; } /* now reserved time */ if (!row_start || (row_start >= c_usage->start)) { int temp_end = row_start; int temp_start = row_eligible; if (c_usage->start > temp_start) temp_start = c_usage->start; if (c_usage->end < temp_end) temp_end = c_usage->end; loc_seconds = (temp_end - temp_start); if (loc_seconds > 0) { /* If we have pending jobs in an array they haven't been inserted into the database yet as proper job records, so handle them here. */ if (array_pending) loc_seconds *= array_pending; /* info("%d assoc %d reserved " */ /* "(%d)(%d-%d) * %d * %d = %d " */ /* "to %d", */ /* job_id, */ /* assoc_id, */ /* temp_end - temp_start, */ /* temp_end, temp_start, */ /* row_rcpu, */ /* array_pending, */ /* loc_seconds, */ /* row_rcpu); */ c_usage->r_cpu += loc_seconds * row_rcpu; } } } mysql_free_result(result); /* now figure out how much more to add to the associations that could had run in the reservation */ list_iterator_reset(r_itr); while ((r_usage = list_next(r_itr))) { int64_t idle = r_usage->total_time - r_usage->a_cpu; char *assoc = NULL; ListIterator tmp_itr = NULL; if (idle <= 0) continue; /* now divide that time by the number of associations in the reservation and add them to each association */ seconds = idle / list_count(r_usage->local_assocs); /* info("resv %d got %d for seconds for %d assocs", */ /* r_usage->id, seconds, */ /* list_count(r_usage->local_assocs)); */ tmp_itr = list_iterator_create(r_usage->local_assocs); while ((assoc = list_next(tmp_itr))) { uint32_t associd = slurm_atoul(assoc); if (last_id != associd) { list_iterator_reset(a_itr); while ((a_usage = list_next(a_itr))) { if (a_usage->id == associd) { last_id = a_usage->id; break; } } } if (!a_usage) { a_usage = xmalloc( sizeof(local_id_usage_t)); a_usage->id = associd; list_append(assoc_usage_list, a_usage); last_id = associd; } a_usage->a_cpu += seconds; } list_iterator_destroy(tmp_itr); } /* now apply the down time from the slurmctld disconnects */ if (c_usage) { list_iterator_reset(c_itr); while ((loc_c_usage = list_next(c_itr))) c_usage->d_cpu += loc_c_usage->total_time; if ((rc = _process_cluster_usage( mysql_conn, cluster_name, curr_start, curr_end, now, c_usage)) != SLURM_SUCCESS) { _destroy_local_cluster_usage(c_usage); goto end_it; } } list_iterator_reset(a_itr); while ((a_usage = list_next(a_itr))) { /* info("association (%d) %d alloc %d", */ /* a_usage->id, last_id, */ /* a_usage->a_cpu); */ if (query) { xstrfmtcat(query, ", (%ld, %ld, %d, %ld, %"PRIu64", " "%"PRIu64")", now, now, a_usage->id, curr_start, a_usage->a_cpu, a_usage->energy); } else { xstrfmtcat(query, "insert into \"%s_%s\" " "(creation_time, " "mod_time, id_assoc, time_start, " "alloc_cpu_secs, consumed_energy) " "values " "(%ld, %ld, %d, %ld, %"PRIu64", " "%"PRIu64")", cluster_name, assoc_hour_table, now, now, a_usage->id, curr_start, a_usage->a_cpu, a_usage->energy); } } if (query) { xstrfmtcat(query, " on duplicate key update " "mod_time=%ld, " "alloc_cpu_secs=VALUES(alloc_cpu_secs), " "consumed_energy=VALUES(consumed_energy);", now); if (debug_flags & DEBUG_FLAG_DB_USAGE) DB_DEBUG(mysql_conn->conn, "query\n%s", query); rc = mysql_db_query(mysql_conn, query); xfree(query); if (rc != SLURM_SUCCESS) { error("Couldn't add assoc hour rollup"); _destroy_local_cluster_usage(c_usage); goto end_it; } } if (!track_wckey) goto end_loop; list_iterator_reset(w_itr); while ((w_usage = list_next(w_itr))) { /* info("association (%d) %d alloc %d", */ /* w_usage->id, last_id, */ /* w_usage->a_cpu); */ if (query) { xstrfmtcat(query, ", (%ld, %ld, %d, %ld, " "%"PRIu64", %"PRIu64")", now, now, w_usage->id, curr_start, w_usage->a_cpu, w_usage->energy); } else { xstrfmtcat(query, "insert into \"%s_%s\" " "(creation_time, " "mod_time, id_wckey, time_start, " "alloc_cpu_secs, consumed_energy) " "values " "(%ld, %ld, %d, %ld, " "%"PRIu64", %"PRIu64")", cluster_name, wckey_hour_table, now, now, w_usage->id, curr_start, w_usage->a_cpu, w_usage->energy); } } if (query) { xstrfmtcat(query, " on duplicate key update " "mod_time=%ld, " "alloc_cpu_secs=VALUES(alloc_cpu_secs), " "consumed_energy=VALUES(consumed_energy);", now); if (debug_flags & DEBUG_FLAG_DB_USAGE) DB_DEBUG(mysql_conn->conn, "query\n%s", query); rc = mysql_db_query(mysql_conn, query); xfree(query); if (rc != SLURM_SUCCESS) { error("Couldn't add wckey hour rollup"); _destroy_local_cluster_usage(c_usage); goto end_it; } } end_loop: _destroy_local_cluster_usage(c_usage); list_flush(assoc_usage_list); list_flush(cluster_down_list); list_flush(wckey_usage_list); list_flush(resv_usage_list); curr_start = curr_end; curr_end = curr_start + add_sec; } end_it: xfree(suspend_str); xfree(job_str); xfree(resv_str); list_iterator_destroy(a_itr); list_iterator_destroy(c_itr); list_iterator_destroy(w_itr); list_iterator_destroy(r_itr); list_destroy(assoc_usage_list); list_destroy(cluster_down_list); list_destroy(wckey_usage_list); list_destroy(resv_usage_list); /* info("stop start %s", slurm_ctime(&curr_start)); */ /* info("stop end %s", slurm_ctime(&curr_end)); */ /* go check to see if we archive and purge */ if (rc == SLURM_SUCCESS) rc = _process_purge(mysql_conn, cluster_name, archive_data, SLURMDB_PURGE_HOURS); return rc; }
extern int as_mysql_modify_resv(mysql_conn_t *mysql_conn, slurmdb_reservation_rec_t *resv) { MYSQL_RES *result = NULL; MYSQL_ROW row; int rc = SLURM_SUCCESS; char *cols = NULL, *vals = NULL, *extra = NULL, *query = NULL; time_t start = 0, now = time(NULL); int i; int set = 0; char *resv_req_inx[] = { "assoclist", "time_start", "time_end", "resv_name", "nodelist", "node_inx", "flags", "tres" }; enum { RESV_ASSOCS, RESV_START, RESV_END, RESV_NAME, RESV_NODES, RESV_NODE_INX, RESV_FLAGS, RESV_TRES, RESV_COUNT }; if (!resv) { error("No reservation was given to edit"); return SLURM_ERROR; } if (!resv->id) { error("We need an id to edit a reservation."); return SLURM_ERROR; } if (!resv->time_start) { error("We need a start time to edit a reservation."); return SLURM_ERROR; } if (!resv->cluster || !resv->cluster[0]) { error("We need a cluster name to edit a reservation."); return SLURM_ERROR; } if (!resv->time_start_prev) { error("We need a time to check for last " "start of reservation."); return SLURM_ERROR; } xstrfmtcat(cols, "%s", resv_req_inx[0]); for (i=1; i<RESV_COUNT; i++) { xstrfmtcat(cols, ", %s", resv_req_inx[i]); } /* check for both the last start and the start because most likely the start time hasn't changed, but something else may have since the last time we did an update to the reservation. */ query = xstrdup_printf("select %s from \"%s_%s\" where id_resv=%u " "and (time_start=%ld || time_start=%ld) " "and deleted=0 order by time_start desc " "limit 1 FOR UPDATE;", cols, resv->cluster, resv_table, resv->id, resv->time_start, resv->time_start_prev); try_again: debug4("%d(%s:%d) query\n%s", mysql_conn->conn, THIS_FILE, __LINE__, query); if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) { rc = SLURM_ERROR; goto end_it; } if (!(row = mysql_fetch_row(result))) { rc = SLURM_ERROR; mysql_free_result(result); error("There is no reservation by id %u, " "time_start %ld, and cluster '%s'", resv->id, resv->time_start_prev, resv->cluster); if (!set && resv->time_end) { /* This should never really happen, but just incase the controller and the database get out of sync we check to see if there is a reservation not deleted that hasn't ended yet. */ xfree(query); query = xstrdup_printf( "select %s from \"%s_%s\" where id_resv=%u " "and time_start <= %ld and deleted=0 " "order by time_start desc " "limit 1;", cols, resv->cluster, resv_table, resv->id, resv->time_end); set = 1; goto try_again; } goto end_it; } start = slurm_atoul(row[RESV_START]); xfree(query); xfree(cols); set = 0; /* check differences here */ if (!resv->name && row[RESV_NAME] && row[RESV_NAME][0]) // if this changes we just update the // record, no need to create a new one since // this doesn't really effect the // reservation accounting wise resv->name = xstrdup(row[RESV_NAME]); if (resv->assocs) set = 1; else if (row[RESV_ASSOCS] && row[RESV_ASSOCS][0]) resv->assocs = xstrdup(row[RESV_ASSOCS]); if (resv->flags != NO_VAL) set = 1; else resv->flags = slurm_atoul(row[RESV_FLAGS]); if (resv->nodes) set = 1; else if (row[RESV_NODES] && row[RESV_NODES][0]) { resv->nodes = xstrdup(row[RESV_NODES]); resv->node_inx = xstrdup(row[RESV_NODE_INX]); } if (!resv->time_end) resv->time_end = slurm_atoul(row[RESV_END]); if (resv->tres_str) set = 1; else if (row[RESV_TRES] && row[RESV_TRES][0]) resv->tres_str = xstrdup(row[RESV_TRES]); mysql_free_result(result); _setup_resv_limits(resv, &cols, &vals, &extra); /* use start below instead of resv->time_start_prev * just incase we have a different one from being out * of sync */ if ((start > now) || !set) { /* we haven't started the reservation yet, or we are changing the associations or end time which we can just update it */ query = xstrdup_printf("update \"%s_%s\" set deleted=0%s " "where deleted=0 and id_resv=%u " "and time_start=%ld;", resv->cluster, resv_table, extra, resv->id, start); } else { /* time_start is already done above and we * changed something that is in need on a new * entry. */ query = xstrdup_printf("update \"%s_%s\" set time_end=%ld " "where deleted=0 && id_resv=%u " "and time_start=%ld;", resv->cluster, resv_table, resv->time_start-1, resv->id, start); xstrfmtcat(query, "insert into \"%s_%s\" (id_resv%s) " "values (%u%s) " "on duplicate key update deleted=0%s;", resv->cluster, resv_table, cols, resv->id, vals, extra); } if (debug_flags & DEBUG_FLAG_DB_RESV) DB_DEBUG(mysql_conn->conn, "query\n%s", query); rc = mysql_db_query(mysql_conn, query); end_it: xfree(query); xfree(cols); xfree(vals); xfree(extra); return rc; }