1 /*****************************************************************************\
2 * accounting_storage_mysql.c - accounting interface to as_mysql.
3 *****************************************************************************
4 * Copyright (C) 2004-2007 The Regents of the University of California.
5 * Copyright (C) 2008-2010 Lawrence Livermore National Security.
6 * Copyright (C) 2011-2018 SchedMD LLC.
7 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
8 * Written by Danny Auble <da@schedmd.com, da@llnl.gov>
9 *
10 * This file is part of Slurm, a resource management program.
11 * For details, see <https://slurm.schedmd.com/>.
12 * Please also read the included file: DISCLAIMER.
13 *
14 * Slurm is free software; you can redistribute it and/or modify it under
15 * the terms of the GNU General Public License as published by the Free
16 * Software Foundation; either version 2 of the License, or (at your option)
17 * any later version.
18 *
19 * In addition, as a special exception, the copyright holders give permission
20 * to link the code of portions of this program with the OpenSSL library under
21 * certain conditions as described in each individual source file, and
22 * distribute linked combinations including the two. You must obey the GNU
23 * General Public License in all respects for all of the code used other than
24 * OpenSSL. If you modify file(s) with this exception, you may extend this
25 * exception to your version of the file(s), but you are not obligated to do
26 * so. If you do not wish to do so, delete this exception statement from your
27 * version. If you delete this exception statement from all source files in
28 * the program, then also delete it here.
29 *
30 * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
31 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
33 * details.
34 *
35 * You should have received a copy of the GNU General Public License along
36 * with Slurm; if not, write to the Free Software Foundation, Inc.,
37 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 *****************************************************************************
39 * Notes on as_mysql configuration
40 * Assumes mysql is installed as user root
41 * Assumes SlurmUser is configured as user slurm
42 * # mysql --user=root -p
43 * mysql> GRANT ALL ON *.* TO 'slurm'@'localhost' IDENTIFIED BY PASSWORD 'pw';
44 * mysql> GRANT SELECT, INSERT ON *.* TO 'slurm'@'localhost';
45 \*****************************************************************************/
46
47 #include "accounting_storage_mysql.h"
48 #include "as_mysql_acct.h"
49 #include "as_mysql_tres.h"
50 #include "as_mysql_archive.h"
51 #include "as_mysql_assoc.h"
52 #include "as_mysql_cluster.h"
53 #include "as_mysql_convert.h"
54 #include "as_mysql_federation.h"
55 #include "as_mysql_fix_runaway_jobs.h"
56 #include "as_mysql_job.h"
57 #include "as_mysql_jobacct_process.h"
58 #include "as_mysql_problems.h"
59 #include "as_mysql_qos.h"
60 #include "as_mysql_resource.h"
61 #include "as_mysql_resv.h"
62 #include "as_mysql_rollup.h"
63 #include "as_mysql_txn.h"
64 #include "as_mysql_usage.h"
65 #include "as_mysql_user.h"
66 #include "as_mysql_wckey.h"
67
68 List as_mysql_cluster_list = NULL;
69 /* This total list is only used for converting things, so no
70 need to keep it upto date even though it lives until the
71 end of the life of the slurmdbd.
72 */
73 List as_mysql_total_cluster_list = NULL;
74 pthread_mutex_t as_mysql_cluster_list_lock = PTHREAD_MUTEX_INITIALIZER;
75
76 /*
77 * These variables are required by the generic plugin interface. If they
78 * are not found in the plugin, the plugin loader will ignore it.
79 *
80 * plugin_name - a string giving a human-readable description of the
81 * plugin. There is no maximum length, but the symbol must refer to
82 * a valid string.
83 *
84 * plugin_type - a string suggesting the type of the plugin or its
85 * applicability to a particular form of data or method of data handling.
86 * If the low-level plugin API is used, the contents of this string are
87 * unimportant and may be anything. Slurm uses the higher-level plugin
88 * interface which requires this string to be of the form
89 *
90 * <application>/<method>
91 *
92 * where <application> is a description of the intended application of
93 * the plugin (e.g., "accounting_storage" for Slurm job completion
94 * logging) and <method>
95 * is a description of how this plugin satisfies that application. Slurm will
96 * only load job completion logging plugins if the plugin_type string has a
97 * prefix of "accounting_storage/".
98 *
99 * plugin_version - an unsigned 32-bit integer containing the Slurm version
100 * (major.minor.micro combined into a single number).
101 */
102 const char plugin_name[] = "Accounting storage MYSQL plugin";
103 const char plugin_type[] = "accounting_storage/as_mysql";
104 const uint32_t plugin_version = SLURM_VERSION_NUMBER;
105
106 static mysql_db_info_t *mysql_db_info = NULL;
107 static char *mysql_db_name = NULL;
108
109 #define DELETE_SEC_BACK 86400
110
111 char *acct_coord_table = "acct_coord_table";
112 char *acct_table = "acct_table";
113 char *tres_table = "tres_table";
114 char *assoc_day_table = "assoc_usage_day_table";
115 char *assoc_hour_table = "assoc_usage_hour_table";
116 char *assoc_month_table = "assoc_usage_month_table";
117 char *assoc_table = "assoc_table";
118 char *clus_res_table = "clus_res_table";
119 char *cluster_day_table = "usage_day_table";
120 char *cluster_hour_table = "usage_hour_table";
121 char *cluster_month_table = "usage_month_table";
122 char *cluster_table = "cluster_table";
123 char *convert_version_table = "convert_version_table";
124 char *federation_table = "federation_table";
125 char *event_table = "event_table";
126 char *job_table = "job_table";
127 char *last_ran_table = "last_ran_table";
128 char *qos_table = "qos_table";
129 char *resv_table = "resv_table";
130 char *res_table = "res_table";
131 char *step_table = "step_table";
132 char *txn_table = "txn_table";
133 char *user_table = "user_table";
134 char *suspend_table = "suspend_table";
135 char *wckey_day_table = "wckey_usage_day_table";
136 char *wckey_hour_table = "wckey_usage_hour_table";
137 char *wckey_month_table = "wckey_usage_month_table";
138 char *wckey_table = "wckey_table";
139
140 char *event_view = "event_view";
141 char *event_ext_view = "event_ext_view";
142 char *job_view = "job_view";
143 char *job_ext_view = "job_ext_view";
144 char *resv_view = "resv_view";
145 char *resv_ext_view = "resv_ext_view";
146 char *step_view = "step_view";
147 char *step_ext_view = "step_ext_view";
148
149 uint64_t debug_flags = 0;
150 bool backup_dbd = 0;
151
152 static char *default_qos_str = NULL;
153
154 enum {
155 JASSOC_JOB,
156 JASSOC_ACCT,
157 JASSOC_USER,
158 JASSOC_PART,
159 JASSOC_COUNT
160 };
161
162 extern int acct_storage_p_close_connection(mysql_conn_t **mysql_conn);
163
_get_cluster_names(mysql_conn_t * mysql_conn,bool with_deleted)164 static List _get_cluster_names(mysql_conn_t *mysql_conn, bool with_deleted)
165 {
166 MYSQL_RES *result = NULL;
167 MYSQL_ROW row;
168 List ret_list = NULL;
169
170 char *query = xstrdup_printf("select name from %s", cluster_table);
171
172 if (!with_deleted)
173 xstrcat(query, " where deleted=0");
174
175 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
176 xfree(query);
177 return NULL;
178 }
179 xfree(query);
180
181 ret_list = list_create(xfree_ptr);
182 while ((row = mysql_fetch_row(result))) {
183 if (row[0] && row[0][0])
184 list_append(ret_list, xstrdup(row[0]));
185 }
186 mysql_free_result(result);
187
188 return ret_list;
189 }
190
_set_qos_cnt(mysql_conn_t * mysql_conn)191 static int _set_qos_cnt(mysql_conn_t *mysql_conn)
192 {
193 MYSQL_RES *result = NULL;
194 MYSQL_ROW row;
195 char *query = xstrdup_printf("select MAX(id) from %s", qos_table);
196 assoc_mgr_lock_t locks = { NO_LOCK, NO_LOCK, WRITE_LOCK, NO_LOCK,
197 NO_LOCK, NO_LOCK, NO_LOCK };
198
199 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
200 xfree(query);
201 return SLURM_ERROR;
202 }
203 xfree(query);
204
205 if (!(row = mysql_fetch_row(result))) {
206 mysql_free_result(result);
207 return SLURM_ERROR;
208 }
209
210 /* Set the current qos_count on the system for
211 generating bitstr of that length. Since 0 isn't
212 possible as an id we add 1 to the total to burn 0 and
213 start at the 1 bit.
214 */
215 assoc_mgr_lock(&locks);
216 g_qos_count = slurm_atoul(row[0]) + 1;
217 assoc_mgr_unlock(&locks);
218 mysql_free_result(result);
219
220 return SLURM_SUCCESS;
221 }
222
_process_running_jobs_result(char * cluster_name,MYSQL_RES * result,List ret_list)223 static void _process_running_jobs_result(char *cluster_name,
224 MYSQL_RES *result, List ret_list)
225 {
226 MYSQL_ROW row;
227 char *object;
228
229 while ((row = mysql_fetch_row(result))) {
230 if (!row[JASSOC_USER][0]) {
231 /* This should never happen */
232 error("How did we get a job running on an association "
233 "that isn't a user association job %s cluster "
234 "'%s' acct '%s'?", row[JASSOC_JOB],
235 cluster_name, row[JASSOC_ACCT]);
236 continue;
237 }
238 object = xstrdup_printf(
239 "JobID = %-10s C = %-10s A = %-10s U = %-9s",
240 row[JASSOC_JOB], cluster_name, row[JASSOC_ACCT],
241 row[JASSOC_USER]);
242 if (row[JASSOC_PART][0])
243 // see if there is a partition name
244 xstrfmtcat(object, " P = %s", row[JASSOC_PART]);
245 list_append(ret_list, object);
246 }
247 }
248
249 /* this function is here to see if any of what we are trying to remove
250 * has jobs that are not completed. If we have jobs and the object is less
251 * than a day old we don't want to delete it, only set the deleted flag.
252 */
_check_jobs_before_remove(mysql_conn_t * mysql_conn,char * cluster_name,char * assoc_char,List ret_list,bool * already_flushed)253 static bool _check_jobs_before_remove(mysql_conn_t *mysql_conn,
254 char *cluster_name,
255 char *assoc_char,
256 List ret_list,
257 bool *already_flushed)
258 {
259 char *query = NULL, *object = NULL;
260 bool rc = 0;
261 int i;
262 MYSQL_RES *result = NULL;
263
264 /* if this changes you will need to edit the corresponding
265 * enum above in the global settings */
266 static char *jassoc_req_inx[] = {
267 "t0.id_job",
268 "t1.acct",
269 "t1.user",
270 "t1.partition"
271 };
272 if (ret_list) {
273 xstrcat(object, jassoc_req_inx[0]);
274 for(i=1; i<JASSOC_COUNT; i++)
275 xstrfmtcat(object, ", %s", jassoc_req_inx[i]);
276
277 query = xstrdup_printf(
278 "select distinct %s "
279 "from \"%s_%s\" as t0, "
280 "\"%s_%s\" as t1, \"%s_%s\" as t2 "
281 "where t1.lft between "
282 "t2.lft and t2.rgt && (%s) "
283 "and t0.id_assoc=t1.id_assoc "
284 "and t0.time_end=0 && t0.state<%d;",
285 object, cluster_name, job_table,
286 cluster_name, assoc_table,
287 cluster_name, assoc_table,
288 assoc_char, JOB_COMPLETE);
289 xfree(object);
290 } else {
291 query = xstrdup_printf(
292 "select t0.id_assoc from \"%s_%s\" as t0, "
293 "\"%s_%s\" as t1, \"%s_%s\" as t2 "
294 "where t1.lft between "
295 "t2.lft and t2.rgt && (%s) "
296 "and t0.id_assoc=t1.id_assoc limit 1;",
297 cluster_name, job_table,
298 cluster_name, assoc_table,
299 cluster_name, assoc_table,
300 assoc_char);
301 }
302
303 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
304 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
305 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
306 xfree(query);
307 return rc;
308 }
309 xfree(query);
310
311 if (mysql_num_rows(result)) {
312 debug4("We have jobs for this combo");
313 rc = true;
314 if (ret_list && !(*already_flushed)) {
315 list_flush(ret_list);
316 (*already_flushed) = 1;
317 reset_mysql_conn(mysql_conn);
318 }
319 if (ret_list)
320 _process_running_jobs_result(cluster_name, result,
321 ret_list);
322 }
323
324 mysql_free_result(result);
325 return rc;
326 }
327
328 /* Same as above but for associations instead of other tables */
_check_jobs_before_remove_assoc(mysql_conn_t * mysql_conn,char * cluster_name,char * assoc_char,List ret_list,bool * already_flushed)329 static bool _check_jobs_before_remove_assoc(mysql_conn_t *mysql_conn,
330 char *cluster_name,
331 char *assoc_char,
332 List ret_list,
333 bool *already_flushed)
334 {
335 char *query = NULL, *object = NULL;
336 bool rc = 0;
337 int i;
338 MYSQL_RES *result = NULL;
339
340 /* if this changes you will need to edit the corresponding
341 * enum above in the global settings */
342 static char *jassoc_req_inx[] = {
343 "t1.id_job",
344 "t2.acct",
345 "t2.user",
346 "t2.partition"
347 };
348
349 if (ret_list) {
350 xstrcat(object, jassoc_req_inx[0]);
351 for(i=1; i<JASSOC_COUNT; i++)
352 xstrfmtcat(object, ", %s", jassoc_req_inx[i]);
353
354 query = xstrdup_printf("select %s "
355 "from \"%s_%s\" as t1, \"%s_%s\" as t2 "
356 "where (%s) and t1.id_assoc=t2.id_assoc "
357 "and t1.time_end=0 && t1.state<%d;",
358 object, cluster_name, job_table,
359 cluster_name, assoc_table,
360 assoc_char, JOB_COMPLETE);
361 xfree(object);
362 } else {
363 query = xstrdup_printf(
364 "select t1.id_assoc from \"%s_%s\" as t1, "
365 "\"%s_%s\" as t2 where (%s) "
366 "and t1.id_assoc=t2.id_assoc limit 1;",
367 cluster_name, job_table,
368 cluster_name, assoc_table,
369 assoc_char);
370 }
371
372 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
373 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
374
375 if (!(result = mysql_db_query_ret(
376 mysql_conn, query, 0))) {
377 xfree(query);
378 return rc;
379 }
380 xfree(query);
381
382 if (mysql_num_rows(result)) {
383 debug4("We have jobs for this combo");
384 rc = true;
385 if (ret_list && !(*already_flushed)) {
386 list_flush(ret_list);
387 (*already_flushed) = 1;
388 reset_mysql_conn(mysql_conn);
389 }
390 }
391
392 if (ret_list)
393 _process_running_jobs_result(cluster_name, result, ret_list);
394
395 mysql_free_result(result);
396 return rc;
397 }
398
399 /* Same as above but for things having nothing to do with associations
400 * like qos or wckey */
_check_jobs_before_remove_without_assoctable(mysql_conn_t * mysql_conn,char * cluster_name,char * where_char)401 static bool _check_jobs_before_remove_without_assoctable(
402 mysql_conn_t *mysql_conn, char *cluster_name, char *where_char)
403 {
404 char *query = NULL;
405 bool rc = 0;
406 MYSQL_RES *result = NULL;
407
408 query = xstrdup_printf("select id_assoc from \"%s_%s\" "
409 "where (%s) limit 1;",
410 cluster_name, job_table, where_char);
411
412 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
413 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
414
415 if (!(result = mysql_db_query_ret(
416 mysql_conn, query, 0))) {
417 xfree(query);
418 return rc;
419 }
420 xfree(query);
421
422 if (mysql_num_rows(result)) {
423 debug4("We have jobs for this combo");
424 rc = true;
425 }
426
427 mysql_free_result(result);
428 return rc;
429 }
430
431 /* static int _add_remove_tres_limit(char *tres_limit_str, char *name, */
432 /* char **cols, char **vals, char **extra) */
433 /* { */
434 /* int rc = SLURM_SUCCESS; */
435 /* char *tmp_str = tres_limit_str; */
436 /* uint64_t value; */
437 /* bool first = true; */
438
439 /* if (!tmp_str || !tmp_str[0]) */
440 /* return SLURM_SUCCESS; */
441
442 /* while (tmp_str) { */
443 /* if (id == atoi(tmp_str)) { */
444 /* if (!(tmp_str = strchr(tmp_str, '='))) { */
445 /* error("_add_remove_tres_limit: no value found"); */
446 /* rc = SLURM_ERROR; */
447 /* break; */
448 /* } */
449 /* if (first) */
450 /* slurm_atoull(++tmp_str); */
451 /* } */
452
453 /* if (!(tmp_str = strchr(tmp_str, ','))) */
454 /* break; */
455 /* tmp_str++; */
456 /* } */
457
458 /* return SLURM_SUCCESS; */
459 /* } */
460
461 /* Any time a new table is added set it up here */
_as_mysql_acct_check_tables(mysql_conn_t * mysql_conn)462 static int _as_mysql_acct_check_tables(mysql_conn_t *mysql_conn)
463 {
464 storage_field_t acct_coord_table_fields[] = {
465 { "creation_time", "bigint unsigned not null" },
466 { "mod_time", "bigint unsigned default 0 not null" },
467 { "deleted", "tinyint default 0" },
468 { "acct", "tinytext not null" },
469 { "user", "tinytext not null" },
470 { NULL, NULL}
471 };
472
473 storage_field_t acct_table_fields[] = {
474 { "creation_time", "bigint unsigned not null" },
475 { "mod_time", "bigint unsigned default 0 not null" },
476 { "deleted", "tinyint default 0" },
477 { "name", "tinytext not null" },
478 { "description", "text not null" },
479 { "organization", "text not null" },
480 { NULL, NULL}
481 };
482
483 storage_field_t tres_table_fields[] = {
484 { "creation_time", "bigint unsigned not null" },
485 { "deleted", "tinyint default 0 not null" },
486 { "id", "int not null auto_increment" },
487 { "type", "tinytext not null" },
488 { "name", "tinytext not null default ''" },
489 { NULL, NULL}
490 };
491
492 storage_field_t cluster_table_fields[] = {
493 { "creation_time", "bigint unsigned not null" },
494 { "mod_time", "bigint unsigned default 0 not null" },
495 { "deleted", "tinyint default 0" },
496 { "name", "tinytext not null" },
497 { "control_host", "tinytext not null default ''" },
498 { "control_port", "int unsigned not null default 0" },
499 { "last_port", "int unsigned not null default 0" },
500 { "rpc_version", "smallint unsigned not null default 0" },
501 { "classification", "smallint unsigned default 0" },
502 { "dimensions", "smallint unsigned default 1" },
503 { "plugin_id_select", "smallint unsigned default 0" },
504 { "flags", "int unsigned default 0" },
505 { "federation", "tinytext not null" },
506 { "features", "text not null default ''" },
507 { "fed_id", "int unsigned default 0 not null" },
508 { "fed_state", "smallint unsigned not null" },
509 { NULL, NULL}
510 };
511
512 storage_field_t clus_res_table_fields[] = {
513 { "creation_time", "bigint unsigned not null" },
514 { "mod_time", "bigint unsigned default 0 not null" },
515 { "deleted", "tinyint default 0" },
516 { "cluster", "tinytext not null" },
517 { "res_id", "int not null" },
518 { "percent_allowed", "int unsigned default 0" },
519 { NULL, NULL}
520 };
521
522 storage_field_t convert_version_table_fields[] = {
523 { "mod_time", "bigint unsigned default 0 not null" },
524 { "version", "int default 0" },
525 { NULL, NULL}
526 };
527
528 storage_field_t federation_table_fields[] = {
529 { "creation_time", "int unsigned not null" },
530 { "mod_time", "int unsigned default 0 not null" },
531 { "deleted", "tinyint default 0" },
532 { "name", "tinytext not null" },
533 { "flags", "int unsigned default 0" },
534 { NULL, NULL}
535 };
536
537 storage_field_t qos_table_fields[] = {
538 { "creation_time", "bigint unsigned not null" },
539 { "mod_time", "bigint unsigned default 0 not null" },
540 { "deleted", "tinyint default 0" },
541 { "id", "int not null auto_increment" },
542 { "name", "tinytext not null" },
543 { "description", "text" },
544 { "flags", "int unsigned default 0" },
545 { "grace_time", "int unsigned default NULL" },
546 { "max_jobs_pa", "int default NULL" },
547 { "max_jobs_per_user", "int default NULL" },
548 { "max_jobs_accrue_pa", "int default NULL" },
549 { "max_jobs_accrue_pu", "int default NULL" },
550 { "min_prio_thresh", "int default NULL" },
551 { "max_submit_jobs_pa", "int default NULL" },
552 { "max_submit_jobs_per_user", "int default NULL" },
553 { "max_tres_pa", "text not null default ''" },
554 { "max_tres_pj", "text not null default ''" },
555 { "max_tres_pn", "text not null default ''" },
556 { "max_tres_pu", "text not null default ''" },
557 { "max_tres_mins_pj", "text not null default ''" },
558 { "max_tres_run_mins_pa", "text not null default ''" },
559 { "max_tres_run_mins_pu", "text not null default ''" },
560 { "min_tres_pj", "text not null default ''" },
561 { "max_wall_duration_per_job", "int default NULL" },
562 { "grp_jobs", "int default NULL" },
563 { "grp_jobs_accrue", "int default NULL" },
564 { "grp_submit_jobs", "int default NULL" },
565 { "grp_tres", "text not null default ''" },
566 { "grp_tres_mins", "text not null default ''" },
567 { "grp_tres_run_mins", "text not null default ''" },
568 { "grp_wall", "int default NULL" },
569 { "preempt", "text not null default ''" },
570 { "preempt_mode", "int default 0" },
571 { "preempt_exempt_time", "int unsigned default NULL" },
572 { "priority", "int unsigned default 0" },
573 { "usage_factor", "double default 1.0 not null" },
574 { "usage_thres", "double default NULL" },
575 { NULL, NULL}
576 };
577
578 storage_field_t res_table_fields[] = {
579 { "creation_time", "bigint unsigned not null" },
580 { "mod_time", "bigint unsigned default 0 not null" },
581 { "deleted", "tinyint default 0" },
582 { "id", "int not null auto_increment" },
583 { "name", "tinytext not null" },
584 { "description", "text default null" },
585 { "manager", "tinytext not null" },
586 { "server", "tinytext not null" },
587 { "count", "int unsigned default 0" },
588 { "type", "int unsigned default 0"},
589 { "flags", "int unsigned default 0"},
590 { NULL, NULL}
591 };
592
593 storage_field_t txn_table_fields[] = {
594 { "id", "int not null auto_increment" },
595 { "timestamp", "bigint unsigned default 0 not null" },
596 { "action", "smallint not null" },
597 { "name", "text not null" },
598 { "actor", "tinytext not null" },
599 { "cluster", "tinytext not null default ''" },
600 { "info", "blob" },
601 { NULL, NULL}
602 };
603
604 storage_field_t user_table_fields[] = {
605 { "creation_time", "bigint unsigned not null" },
606 { "mod_time", "bigint unsigned default 0 not null" },
607 { "deleted", "tinyint default 0" },
608 { "name", "tinytext not null" },
609 { "admin_level", "smallint default 1 not null" },
610 { NULL, NULL}
611 };
612
613 /*
614 * If more limits are added here they need to be added to
615 * get_parent_limits_select in as_mysql_assoc.c
616 */
617 char *get_parent_proc =
618 "drop procedure if exists get_parent_limits; "
619 "create procedure get_parent_limits("
620 "my_table text, acct text, cluster text, without_limits int) "
621 "begin "
622 "set @par_id = NULL; "
623 "set @mj = NULL; "
624 "set @mja = NULL; "
625 "set @mpt = NULL; "
626 "set @msj = NULL; "
627 "set @mwpj = NULL; "
628 "set @mtpj = ''; "
629 "set @mtpn = ''; "
630 "set @mtmpj = ''; "
631 "set @mtrm = ''; "
632 "set @prio = NULL; "
633 "set @def_qos_id = NULL; "
634 "set @qos = ''; "
635 "set @delta_qos = ''; "
636 "set @my_acct = acct; "
637 "if without_limits then "
638 "set @mj = 0; "
639 "set @msj = 0; "
640 "set @mwpj = 0; "
641 "set @prio = 0; "
642 "set @def_qos_id = 0; "
643 "set @qos = 1; "
644 "end if; "
645 "REPEAT "
646 "set @s = 'select '; "
647 "if @par_id is NULL then set @s = CONCAT("
648 "@s, '@par_id := id_assoc, '); "
649 "end if; "
650 "if @mj is NULL then set @s = CONCAT("
651 "@s, '@mj := max_jobs, '); "
652 "end if; "
653 "if @mja is NULL then set @s = CONCAT("
654 "@s, '@mja := max_jobs_accrue, '); "
655 "end if; "
656 "if @mpt is NULL then set @s = CONCAT("
657 "@s, '@mpt := min_prio_thresh, '); "
658 "end if; "
659 "if @msj is NULL then set @s = CONCAT("
660 "@s, '@msj := max_submit_jobs, '); "
661 "end if; "
662 "if @mwpj is NULL then set @s = CONCAT("
663 "@s, '@mwpj := max_wall_pj, '); "
664 "end if; "
665 "if @prio is NULL then set @s = CONCAT("
666 "@s, '@prio := priority, '); "
667 "end if; "
668 "if @def_qos_id is NULL then set @s = CONCAT("
669 "@s, '@def_qos_id := def_qos_id, '); "
670 "end if; "
671 "if @qos = '' then set @s = CONCAT("
672 "@s, '@qos := qos, "
673 "@delta_qos := REPLACE(CONCAT(delta_qos, @delta_qos), "
674 "\\\',,\\\', \\\',\\\'), '); "
675 "end if; "
676 /* "set @s = CONCAT(@s, @mtpj := REPLACE(CONCAT(@mtpj, max_tres_pj), " */
677 /* "\\\',,\\\', \\\',\\\'), '); " */
678 /* "@mtmpj := REPLACE(CONCAT(@mtmpj, max_tres_mins_pj), " */
679 /* "\\\',,\\\', \\\',\\\'), '); " */
680 /* "@mtrm := REPLACE(CONCAT(@mtrm, max_tres_run_mins), " */
681 /* "\\\',,\\\', \\\',\\\'), '); " */
682 "set @s = concat(@s, "
683 "'@mtpj := CONCAT(@mtpj, "
684 "if (@mtpj != \\\'\\\' && max_tres_pj != \\\'\\\', "
685 "\\\',\\\', \\\'\\\'), max_tres_pj), "
686 "@mtpn := CONCAT(@mtpn, "
687 "if (@mtpn != \\\'\\\' && max_tres_pn != \\\'\\\', "
688 "\\\',\\\', \\\'\\\'), max_tres_pn), "
689 "@mtmpj := CONCAT(@mtmpj, "
690 "if (@mtmpj != \\\'\\\' && max_tres_mins_pj != \\\'\\\', "
691 "\\\',\\\', \\\'\\\'), max_tres_mins_pj), "
692 "@mtrm := CONCAT(@mtrm, "
693 "if (@mtrm != \\\'\\\' && max_tres_run_mins != \\\'\\\', "
694 "\\\',\\\', \\\'\\\'), max_tres_run_mins), "
695 "@my_acct_new := parent_acct from \"', "
696 "cluster, '_', my_table, '\" where "
697 "acct = \\\'', @my_acct, '\\\' && user=\\\'\\\''); "
698 "prepare query from @s; "
699 "execute query; "
700 "deallocate prepare query; "
701 "set @my_acct = @my_acct_new; "
702 "UNTIL without_limits || @my_acct = '' END REPEAT; "
703 "END;";
704 /* char *get_parent_proc = */
705 /* "drop procedure if exists get_parent_limits; " */
706 /* "create procedure get_parent_limits(" */
707 /* "my_table text, acct text, cluster text, without_limits int) " */
708 /* "begin " */
709 /* "set @par_id = NULL; " */
710 /* "set @mj = NULL; " */
711 /* "set @msj = NULL; " */
712 /* "set @mcpj = NULL; " */
713 /* "set @mnpj = NULL; " */
714 /* "set @mwpj = NULL; " */
715 /* "set @mcmpj = NULL; " */
716 /* "set @mcrm = NULL; " */
717 /* "set @def_qos_id = NULL; " */
718 /* "set @qos = ''; " */
719 /* "set @delta_qos = ''; " */
720 /* "set @my_acct = acct; " */
721 /* "if without_limits then " */
722 /* "set @mj = 0; " */
723 /* "set @msj = 0; " */
724 /* "set @mcpj = 0; " */
725 /* "set @mnpj = 0; " */
726 /* "set @mwpj = 0; " */
727 /* "set @mcmpj = 0; " */
728 /* "set @mcrm = 0; " */
729 /* "set @def_qos_id = 0; " */
730 /* "set @qos = 1; " */
731 /* "end if; " */
732 /* "REPEAT " */
733 /* "set @s = 'select '; " */
734 /* "if @par_id is NULL then set @s = CONCAT(" */
735 /* "@s, '@par_id := id_assoc, '); " */
736 /* "end if; " */
737 /* "if @mj is NULL then set @s = CONCAT(" */
738 /* "@s, '@mj := max_jobs, '); " */
739 /* "end if; " */
740 /* "if @msj is NULL then set @s = CONCAT(" */
741 /* "@s, '@msj := max_submit_jobs, '); " */
742 /* "end if; " */
743 /* "if @mcpj is NULL then set @s = CONCAT(" */
744 /* "@s, '@mcpj := max_cpus_pj, ') ;" */
745 /* "end if; " */
746 /* "if @mnpj is NULL then set @s = CONCAT(" */
747 /* "@s, '@mnpj := max_nodes_pj, ') ;" */
748 /* "end if; " */
749 /* "if @mwpj is NULL then set @s = CONCAT(" */
750 /* "@s, '@mwpj := max_wall_pj, '); " */
751 /* "end if; " */
752 /* "if @mcmpj is NULL then set @s = CONCAT(" */
753 /* "@s, '@mcmpj := max_cpu_mins_pj, '); " */
754 /* "end if; " */
755 /* "if @mcrm is NULL then set @s = CONCAT(" */
756 /* "@s, '@mcrm := max_cpu_run_mins, '); " */
757 /* "end if; " */
758 /* "if @def_qos_id is NULL then set @s = CONCAT(" */
759 /* "@s, '@def_qos_id := def_qos_id, '); " */
760 /* "end if; " */
761 /* "if @qos = '' then set @s = CONCAT(" */
762 /* "@s, '@qos := qos, " */
763 /* "@delta_qos := REPLACE(CONCAT(delta_qos, @delta_qos), " */
764 /* "\\\',,\\\', \\\',\\\'), '); " */
765 /* "end if; " */
766 /* "set @s = concat(@s, '@my_acct_new := parent_acct from \"', " */
767 /* "cluster, '_', my_table, '\" where " */
768 /* "acct = \\\'', @my_acct, '\\\' && user=\\\'\\\''); " */
769 /* "prepare query from @s; " */
770 /* "execute query; " */
771 /* "deallocate prepare query; " */
772 /* "set @my_acct = @my_acct_new; " */
773 /* "UNTIL (@mj != -1 && @msj != -1 && @mcpj != -1 " */
774 /* "&& @mnpj != -1 && @mwpj != -1 && @mcmpj != -1 " */
775 /* "&& @mcrm != -1 && @def_qos_id != -1 && @qos != '') " */
776 /* "|| @my_acct = '' END REPEAT; " */
777 /* "END;"; */
778 char *get_coord_qos =
779 "drop procedure if exists get_coord_qos; "
780 "create procedure get_coord_qos(my_table text, acct text, "
781 "cluster text, coord text) "
782 "begin "
783 "set @qos = ''; "
784 "set @delta_qos = ''; "
785 "set @found_coord = NULL; "
786 "set @my_acct = acct; "
787 "REPEAT "
788 "set @s = 'select @qos := t1.qos, "
789 "@delta_qos := REPLACE(CONCAT(t1.delta_qos, @delta_qos), "
790 "\\\',,\\\', \\\',\\\'), @my_acct_new := parent_acct, "
791 "@found_coord_curr := t2.user '; "
792 "set @s = concat(@s, 'from \"', cluster, '_', my_table, '\" "
793 "as t1 left outer join acct_coord_table as t2 on "
794 "t1.acct=t2.acct where t1.acct = @my_acct && t1.user=\\\'\\\' "
795 "&& (t2.user=\\\'', coord, '\\\' || t2.user is null)'); "
796 "prepare query from @s; "
797 "execute query; "
798 "deallocate prepare query; "
799 "if @found_coord_curr is not NULL then "
800 "set @found_coord = @found_coord_curr; "
801 "end if; "
802 "if @found_coord is NULL then "
803 "set @qos = ''; "
804 "set @delta_qos = ''; "
805 "end if; "
806 "set @my_acct = @my_acct_new; "
807 "UNTIL @qos != '' || @my_acct = '' END REPEAT; "
808 "select REPLACE(CONCAT(@qos, @delta_qos), ',,', ','); "
809 "END;";
810 char *query = NULL;
811 time_t now = time(NULL);
812 char *cluster_name = NULL;
813 int rc = SLURM_SUCCESS, rc2;
814 ListIterator itr = NULL;
815
816 /* Make the convert version table since we will check that going
817 * forward to see if we need to update or not.
818 */
819
820 if (mysql_db_create_table(mysql_conn, convert_version_table,
821 convert_version_table_fields,
822 ", primary key (version))") == SLURM_ERROR)
823 return SLURM_ERROR;
824
825 /* Make the cluster table first since we build other tables
826 built off this one */
827 if (mysql_db_create_table(mysql_conn, cluster_table,
828 cluster_table_fields,
829 ", primary key (name(42)))") == SLURM_ERROR)
830 return SLURM_ERROR;
831
832 /* This table needs to be made before conversions also since
833 we add a cluster column.
834 */
835 if (mysql_db_create_table(mysql_conn, txn_table, txn_table_fields,
836 ", primary key (id))") == SLURM_ERROR)
837 return SLURM_ERROR;
838
839 if (mysql_db_create_table(mysql_conn, tres_table,
840 tres_table_fields,
841 ", primary key (id), "
842 "unique index udex (type(42), name(42))) "
843 "auto_increment=1001")
844 == SLURM_ERROR)
845 return SLURM_ERROR;
846
847 if (!backup_dbd) {
848 /* We always want CPU to be the first one, so create
849 it now. We also add MEM here, the others tres
850 are site specific and could vary. None but CPU
851 matter on order though. CPU always has to be 1.
852
853 TRES_OFFSET is needed since there's no way to force
854 the number of first automatic id in MySQL. auto_increment
855 value is lost on mysqld restart. Bug 4553.
856 */
857 query = xstrdup_printf(
858 "insert into %s (creation_time, id, deleted, type) values "
859 "(%ld, %d, 0, 'cpu'), "
860 "(%ld, %d, 0, 'mem'), "
861 "(%ld, %d, 0, 'energy'), "
862 "(%ld, %d, 0, 'node'), "
863 "(%ld, %d, 0, 'billing'), "
864 "(%ld, %d, 0, 'vmem'), "
865 "(%ld, %d, 0, 'pages'), "
866 "(%ld, %d, 1, 'dynamic_offset') "
867 "on duplicate key update deleted=VALUES(deleted), type=VALUES(type), id=VALUES(id);",
868 tres_table,
869 now, TRES_CPU,
870 now, TRES_MEM,
871 now, TRES_ENERGY,
872 now, TRES_NODE,
873 now, TRES_BILLING,
874 now, TRES_VMEM,
875 now, TRES_PAGES,
876 now, TRES_OFFSET);
877 if (debug_flags & DEBUG_FLAG_DB_TRES)
878 DB_DEBUG(mysql_conn->conn, "%s", query);
879 rc = mysql_db_query(mysql_conn, query);
880 xfree(query);
881 if (rc != SLURM_SUCCESS)
882 fatal("problem adding static tres");
883
884 /* Now insert TRES that have a name */
885 query = xstrdup_printf(
886 "insert into %s (creation_time, id, deleted, type, name) values "
887 "(%ld, %d, 0, 'fs', 'disk') "
888 "on duplicate key update deleted=VALUES(deleted), type=VALUES(type), name=VALUES(name), id=VALUES(id);",
889 tres_table,
890 now, TRES_FS_DISK);
891 if (debug_flags & DEBUG_FLAG_DB_TRES)
892 DB_DEBUG(mysql_conn->conn, "%s", query);
893 rc = mysql_db_query(mysql_conn, query);
894 xfree(query);
895 if (rc != SLURM_SUCCESS)
896 fatal("problem adding static tres");
897 }
898
899 slurm_mutex_lock(&as_mysql_cluster_list_lock);
900 if (!(as_mysql_cluster_list = _get_cluster_names(mysql_conn, 0))) {
901 error("issue getting contents of %s", cluster_table);
902 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
903 return SLURM_ERROR;
904 }
905
906 /* This total list is only used for converting things, so no
907 need to keep it upto date even though it lives until the
908 end of the life of the slurmdbd.
909 */
910 if (!(as_mysql_total_cluster_list =
911 _get_cluster_names(mysql_conn, 1))) {
912 error("issue getting total contents of %s", cluster_table);
913 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
914 return SLURM_ERROR;
915 }
916
917 if ((rc = as_mysql_convert_tables_pre_create(mysql_conn)) !=
918 SLURM_SUCCESS) {
919 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
920 error("issue converting tables before create");
921 return rc;
922 } else if (backup_dbd) {
923 /*
924 * We do not want to create/check the database if we are the
925 * backup (see Bug 3827). This is only handled on the primary.
926 */
927
928 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
929
930 /* We do want to set the QOS count though. */
931 if (rc == SLURM_SUCCESS)
932 rc = _set_qos_cnt(mysql_conn);
933
934 return rc;
935 }
936
937 /* might as well do all the cluster centric tables inside this
938 * lock. We need to do this on all the clusters deleted or
939 * other wise just to make sure everything is kept up to
940 * date. */
941 itr = list_iterator_create(as_mysql_total_cluster_list);
942 while ((cluster_name = list_next(itr))) {
943 if ((rc = create_cluster_tables(mysql_conn, cluster_name))
944 != SLURM_SUCCESS)
945 break;
946 }
947 list_iterator_destroy(itr);
948 if (rc != SLURM_SUCCESS) {
949 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
950 return rc;
951 }
952
953 rc = as_mysql_convert_tables_post_create(mysql_conn);
954
955 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
956 if (rc != SLURM_SUCCESS) {
957 error("issue converting tables after create");
958 return rc;
959 }
960
961 if (mysql_db_create_table(mysql_conn, acct_coord_table,
962 acct_coord_table_fields,
963 ", primary key (acct(42), user(42)), "
964 "key user (user(42)))")
965 == SLURM_ERROR)
966 return SLURM_ERROR;
967
968 if (mysql_db_create_table(mysql_conn, acct_table, acct_table_fields,
969 ", primary key (name(42)))") == SLURM_ERROR)
970 return SLURM_ERROR;
971
972 if (mysql_db_create_table(mysql_conn, res_table,
973 res_table_fields,
974 ", primary key (id), "
975 "unique index udex (name(42), server(42), type))")
976 == SLURM_ERROR)
977 return SLURM_ERROR;
978
979 if (mysql_db_create_table(mysql_conn, clus_res_table,
980 clus_res_table_fields,
981 ", primary key (res_id, cluster(42)), "
982 "unique index udex (res_id, cluster(42)))")
983 == SLURM_ERROR)
984 return SLURM_ERROR;
985
986
987 if (mysql_db_create_table(mysql_conn, qos_table,
988 qos_table_fields,
989 ", primary key (id), "
990 "unique index udex (name(42)))")
991 == SLURM_ERROR)
992 return SLURM_ERROR;
993 else {
994 int qos_id = 0;
995 if (slurmdbd_conf && slurmdbd_conf->default_qos) {
996 List char_list = list_create(xfree_ptr);
997 char *qos = NULL;
998 ListIterator itr = NULL;
999 slurm_addto_char_list(char_list,
1000 slurmdbd_conf->default_qos);
1001 /* NOTE: you can not use list_pop, or list_push
1002 anywhere either, since as_mysql is
1003 exporting something of the same type as a macro,
1004 which messes everything up
1005 (my_list.h is the bad boy).
1006 */
1007 itr = list_iterator_create(char_list);
1008 while ((qos = list_next(itr))) {
1009 query = xstrdup_printf(
1010 "insert into %s "
1011 "(creation_time, mod_time, name, "
1012 "description) "
1013 "values (%ld, %ld, '%s', "
1014 "'Added as default') "
1015 "on duplicate key update "
1016 "id=LAST_INSERT_ID(id), deleted=0;",
1017 qos_table, now, now, qos);
1018 if (debug_flags & DEBUG_FLAG_DB_QOS)
1019 DB_DEBUG(mysql_conn->conn, "%s", query);
1020 qos_id = (int)mysql_db_insert_ret_id(
1021 mysql_conn, query);
1022 if (!qos_id)
1023 fatal("problem added qos '%s", qos);
1024 xstrfmtcat(default_qos_str, ",%d", qos_id);
1025 xfree(query);
1026 }
1027 list_iterator_destroy(itr);
1028 FREE_NULL_LIST(char_list);
1029 } else {
1030 query = xstrdup_printf(
1031 "insert into %s "
1032 "(creation_time, mod_time, name, description) "
1033 "values (%ld, %ld, 'normal', "
1034 "'Normal QOS default') "
1035 "on duplicate key update "
1036 "id=LAST_INSERT_ID(id), deleted=0;",
1037 qos_table, now, now);
1038 if (debug_flags & DEBUG_FLAG_DB_QOS)
1039 DB_DEBUG(mysql_conn->conn, "%s", query);
1040 qos_id = (int)mysql_db_insert_ret_id(mysql_conn, query);
1041 if (!qos_id)
1042 fatal("problem added qos 'normal");
1043
1044 xstrfmtcat(default_qos_str, ",%d", qos_id);
1045 xfree(query);
1046 }
1047
1048 if (_set_qos_cnt(mysql_conn) != SLURM_SUCCESS)
1049 return SLURM_ERROR;
1050 }
1051
1052 /* This must be ran after create_cluster_tables() */
1053 if (mysql_db_create_table(mysql_conn, user_table, user_table_fields,
1054 ", primary key (name(42)))") == SLURM_ERROR)
1055 return SLURM_ERROR;
1056
1057 if (mysql_db_create_table(mysql_conn, federation_table,
1058 federation_table_fields,
1059 ", primary key (name(42)))") == SLURM_ERROR)
1060 return SLURM_ERROR;
1061
1062 rc = as_mysql_convert_non_cluster_tables_post_create(mysql_conn);
1063
1064 if (rc != SLURM_SUCCESS) {
1065 error("issue converting non-cluster tables after create");
1066 return rc;
1067 }
1068
1069 rc2 = mysql_db_query(mysql_conn, get_parent_proc);
1070 if (rc2 != SLURM_SUCCESS)
1071 rc = rc2;
1072 rc2 = mysql_db_query(mysql_conn, get_coord_qos);
1073 if (rc2 != SLURM_SUCCESS)
1074 rc = rc2;
1075
1076 /* Add user root to be a user by default and have this default
1077 * account be root. If already there just update
1078 * name='root'. That way if the admins delete it it will
1079 * remain deleted. Creation time will be 0 so it will never
1080 * really be deleted.
1081 */
1082 query = xstrdup_printf(
1083 "insert into %s (creation_time, mod_time, name, "
1084 "admin_level) values (%ld, %ld, 'root', %d) "
1085 "on duplicate key update name='root';",
1086 user_table, (long)now, (long)now, SLURMDB_ADMIN_SUPER_USER);
1087 xstrfmtcat(query,
1088 "insert into %s (creation_time, mod_time, name, "
1089 "description, organization) values (%ld, %ld, 'root', "
1090 "'default root account', 'root') on duplicate key "
1091 "update name='root';",
1092 acct_table, (long)now, (long)now);
1093
1094 //DB_DEBUG(mysql_conn->conn, "%s", query);
1095 mysql_db_query(mysql_conn, query);
1096 xfree(query);
1097
1098 return rc;
1099 }
1100
1101 /* This should be added to the beginning of each function to make sure
1102 * we have a connection to the database before we try to use it.
1103 */
check_connection(mysql_conn_t * mysql_conn)1104 extern int check_connection(mysql_conn_t *mysql_conn)
1105 {
1106 if (!mysql_conn) {
1107 error("We need a connection to run this");
1108 errno = ESLURM_DB_CONNECTION;
1109 return ESLURM_DB_CONNECTION;
1110 } else if (mysql_db_ping(mysql_conn) != 0) {
1111 /* avoid memory leak and end thread */
1112 mysql_db_close_db_connection(mysql_conn);
1113 if (mysql_db_get_db_connection(
1114 mysql_conn, mysql_db_name, mysql_db_info)
1115 != SLURM_SUCCESS) {
1116 error("unable to re-connect to as_mysql database");
1117 errno = ESLURM_DB_CONNECTION;
1118 return ESLURM_DB_CONNECTION;
1119 }
1120 }
1121
1122 if (mysql_conn->cluster_deleted) {
1123 errno = ESLURM_CLUSTER_DELETED;
1124 return ESLURM_CLUSTER_DELETED;
1125 }
1126
1127 return SLURM_SUCCESS;
1128 }
1129
1130 /* Let me know if the last statement had rows that were affected.
1131 * This only gets called by a non-threaded connection, so there is no
1132 * need to worry about locks.
1133 */
last_affected_rows(mysql_conn_t * mysql_conn)1134 extern int last_affected_rows(mysql_conn_t *mysql_conn)
1135 {
1136 int status=0, rows=0;
1137 MYSQL_RES *result = NULL;
1138
1139 do {
1140 result = mysql_store_result(mysql_conn->db_conn);
1141 if (result)
1142 mysql_free_result(result);
1143 else
1144 if (mysql_field_count(mysql_conn->db_conn) == 0) {
1145 status = mysql_affected_rows(
1146 mysql_conn->db_conn);
1147 if (status > 0)
1148 rows = status;
1149 }
1150 if ((status = mysql_next_result(mysql_conn->db_conn)) > 0)
1151 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
1152 DB_DEBUG(mysql_conn->conn,
1153 "Could not execute statement\n");
1154 } while (status == 0);
1155
1156 return rows;
1157 }
1158
reset_mysql_conn(mysql_conn_t * mysql_conn)1159 extern void reset_mysql_conn(mysql_conn_t *mysql_conn)
1160 {
1161 if (mysql_conn->rollback)
1162 mysql_db_rollback(mysql_conn);
1163 xfree(mysql_conn->pre_commit_query);
1164 list_flush(mysql_conn->update_list);
1165 }
1166
create_cluster_assoc_table(mysql_conn_t * mysql_conn,char * cluster_name)1167 extern int create_cluster_assoc_table(
1168 mysql_conn_t *mysql_conn, char *cluster_name)
1169 {
1170 storage_field_t assoc_table_fields[] = {
1171 { "creation_time", "bigint unsigned not null" },
1172 { "mod_time", "bigint unsigned default 0 not null" },
1173 { "deleted", "tinyint default 0 not null" },
1174 { "is_def", "tinyint default 0 not null" },
1175 { "id_assoc", "int unsigned not null auto_increment" },
1176 { "user", "tinytext not null default ''" },
1177 { "acct", "tinytext not null" },
1178 { "partition", "tinytext not null default ''" },
1179 { "parent_acct", "tinytext not null default ''" },
1180 { "lft", "int not null" },
1181 { "rgt", "int not null" },
1182 { "shares", "int default 1 not null" },
1183 { "max_jobs", "int default NULL" },
1184 { "max_jobs_accrue", "int default NULL" },
1185 { "min_prio_thresh", "int default NULL" },
1186 { "max_submit_jobs", "int default NULL" },
1187 { "max_tres_pj", "text not null default ''" },
1188 { "max_tres_pn", "text not null default ''" },
1189 { "max_tres_mins_pj", "text not null default ''" },
1190 { "max_tres_run_mins", "text not null default ''" },
1191 { "max_wall_pj", "int default NULL" },
1192 { "grp_jobs", "int default NULL" },
1193 { "grp_jobs_accrue", "int default NULL" },
1194 { "grp_submit_jobs", "int default NULL" },
1195 { "grp_tres", "text not null default ''" },
1196 { "grp_tres_mins", "text not null default ''" },
1197 { "grp_tres_run_mins", "text not null default ''" },
1198 { "grp_wall", "int default NULL" },
1199 { "priority", "int unsigned default NULL" },
1200 { "def_qos_id", "int default NULL" },
1201 { "qos", "blob not null default ''" },
1202 { "delta_qos", "blob not null default ''" },
1203 { NULL, NULL}
1204 };
1205
1206 char table_name[200];
1207
1208 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1209 cluster_name, assoc_table);
1210 if (mysql_db_create_table(mysql_conn, table_name,
1211 assoc_table_fields,
1212 ", primary key (id_assoc), "
1213 "unique index udex (user(42), acct(42), "
1214 "`partition`(42)), "
1215 "key lft (lft), key account (acct(42)))")
1216 == SLURM_ERROR)
1217 return SLURM_ERROR;
1218
1219 return SLURM_SUCCESS;
1220 }
1221
create_cluster_tables(mysql_conn_t * mysql_conn,char * cluster_name)1222 extern int create_cluster_tables(mysql_conn_t *mysql_conn, char *cluster_name)
1223 {
1224 storage_field_t cluster_usage_table_fields[] = {
1225 { "creation_time", "bigint unsigned not null" },
1226 { "mod_time", "bigint unsigned default 0 not null" },
1227 { "deleted", "tinyint default 0 not null" },
1228 { "id_tres", "int not null" },
1229 { "time_start", "bigint unsigned not null" },
1230 { "count", "bigint unsigned default 0 not null" },
1231 { "alloc_secs", "bigint unsigned default 0 not null" },
1232 { "down_secs", "bigint unsigned default 0 not null" },
1233 { "pdown_secs", "bigint unsigned default 0 not null" },
1234 { "idle_secs", "bigint unsigned default 0 not null" },
1235 { "resv_secs", "bigint unsigned default 0 not null" },
1236 { "over_secs", "bigint unsigned default 0 not null" },
1237 { NULL, NULL}
1238 };
1239
1240 storage_field_t event_table_fields[] = {
1241 { "time_start", "bigint unsigned not null" },
1242 { "time_end", "bigint unsigned default 0 not null" },
1243 { "node_name", "tinytext default '' not null" },
1244 { "cluster_nodes", "text not null default ''" },
1245 { "reason", "tinytext not null" },
1246 { "reason_uid", "int unsigned default 0xfffffffe not null" },
1247 { "state", "int unsigned default 0 not null" },
1248 { "tres", "text not null default ''" },
1249 { NULL, NULL}
1250 };
1251
1252 storage_field_t id_usage_table_fields[] = {
1253 { "creation_time", "bigint unsigned not null" },
1254 { "mod_time", "bigint unsigned default 0 not null" },
1255 { "deleted", "tinyint default 0 not null" },
1256 { "id", "int unsigned not null" },
1257 { "id_tres", "int default 1 not null" },
1258 { "time_start", "bigint unsigned not null" },
1259 { "alloc_secs", "bigint unsigned default 0 not null" },
1260 { NULL, NULL}
1261 };
1262
1263 storage_field_t job_table_fields[] = {
1264 { "job_db_inx", "bigint unsigned not null auto_increment" },
1265 { "mod_time", "bigint unsigned default 0 not null" },
1266 { "deleted", "tinyint default 0 not null" },
1267 { "account", "tinytext" },
1268 { "admin_comment", "text" },
1269 { "array_task_str", "text" },
1270 { "array_max_tasks", "int unsigned default 0 not null" },
1271 { "array_task_pending", "int unsigned default 0 not null" },
1272 { "constraints", "text default ''" },
1273 { "cpus_req", "int unsigned not null" },
1274 { "derived_ec", "int unsigned default 0 not null" },
1275 { "derived_es", "text" },
1276 { "exit_code", "int unsigned default 0 not null" },
1277 { "flags", "int unsigned default 0 not null" },
1278 { "job_name", "tinytext not null" },
1279 { "id_assoc", "int unsigned not null" },
1280 { "id_array_job", "int unsigned default 0 not null" },
1281 { "id_array_task", "int unsigned default 0xfffffffe not null" },
1282 { "id_block", "tinytext" },
1283 { "id_job", "int unsigned not null" },
1284 { "id_qos", "int unsigned default 0 not null" },
1285 { "id_resv", "int unsigned not null" },
1286 { "id_wckey", "int unsigned not null" },
1287 { "id_user", "int unsigned not null" },
1288 { "id_group", "int unsigned not null" },
1289 { "het_job_id", "int unsigned not null" },
1290 { "het_job_offset", "int unsigned not null" },
1291 { "kill_requid", "int default -1 not null" },
1292 { "state_reason_prev", "int unsigned not null" },
1293 { "mcs_label", "tinytext default ''" },
1294 { "mem_req", "bigint unsigned default 0 not null" },
1295 { "nodelist", "text" },
1296 { "nodes_alloc", "int unsigned not null" },
1297 { "node_inx", "text" },
1298 { "partition", "tinytext not null" },
1299 { "priority", "int unsigned not null" },
1300 { "state", "int unsigned not null" },
1301 { "timelimit", "int unsigned default 0 not null" },
1302 { "time_submit", "bigint unsigned default 0 not null" },
1303 { "time_eligible", "bigint unsigned default 0 not null" },
1304 { "time_start", "bigint unsigned default 0 not null" },
1305 { "time_end", "bigint unsigned default 0 not null" },
1306 { "time_suspended", "bigint unsigned default 0 not null" },
1307 { "gres_req", "text not null default ''" },
1308 { "gres_alloc", "text not null default ''" },
1309 { "gres_used", "text not null default ''" },
1310 { "wckey", "tinytext not null default ''" },
1311 { "work_dir", "text not null default ''" },
1312 { "system_comment", "text" },
1313 { "track_steps", "tinyint not null" },
1314 { "tres_alloc", "text not null default ''" },
1315 { "tres_req", "text not null default ''" },
1316 { NULL, NULL}
1317 };
1318
1319 storage_field_t last_ran_table_fields[] = {
1320 { "hourly_rollup", "bigint unsigned default 0 not null" },
1321 { "daily_rollup", "bigint unsigned default 0 not null" },
1322 { "monthly_rollup", "bigint unsigned default 0 not null" },
1323 { NULL, NULL}
1324 };
1325
1326 storage_field_t resv_table_fields[] = {
1327 { "id_resv", "int unsigned default 0 not null" },
1328 { "deleted", "tinyint default 0 not null" },
1329 { "assoclist", "text not null default ''" },
1330 { "flags", "bigint unsigned default 0 not null" },
1331 { "nodelist", "text not null default ''" },
1332 { "node_inx", "text not null default ''" },
1333 { "resv_name", "text not null" },
1334 { "time_start", "bigint unsigned default 0 not null"},
1335 { "time_end", "bigint unsigned default 0 not null" },
1336 { "tres", "text not null default ''" },
1337 { "unused_wall", "double unsigned default 0.0 not null" },
1338 { NULL, NULL}
1339 };
1340
1341 storage_field_t step_table_fields[] = {
1342 { "job_db_inx", "bigint unsigned not null" },
1343 { "deleted", "tinyint default 0 not null" },
1344 { "exit_code", "int default 0 not null" },
1345 { "id_step", "int not null" },
1346 { "kill_requid", "int default -1 not null" },
1347 { "nodelist", "text not null" },
1348 { "nodes_alloc", "int unsigned not null" },
1349 { "node_inx", "text" },
1350 { "state", "smallint unsigned not null" },
1351 { "step_name", "text not null" },
1352 { "task_cnt", "int unsigned not null" },
1353 { "task_dist", "smallint default 0 not null" },
1354 { "time_start", "bigint unsigned default 0 not null" },
1355 { "time_end", "bigint unsigned default 0 not null" },
1356 { "time_suspended", "bigint unsigned default 0 not null" },
1357 { "user_sec", "int unsigned default 0 not null" },
1358 { "user_usec", "int unsigned default 0 not null" },
1359 { "sys_sec", "int unsigned default 0 not null" },
1360 { "sys_usec", "int unsigned default 0 not null" },
1361 { "act_cpufreq", "double unsigned default 0.0 not null" },
1362 { "consumed_energy", "bigint unsigned default 0 not null" },
1363 { "req_cpufreq_min", "int unsigned default 0 not null" },
1364 { "req_cpufreq", "int unsigned default 0 not null" }, /* max */
1365 { "req_cpufreq_gov", "int unsigned default 0 not null" },
1366 { "tres_alloc", "text not null default ''" },
1367 { "tres_usage_in_ave", "text not null default ''" },
1368 { "tres_usage_in_max", "text not null default ''" },
1369 { "tres_usage_in_max_taskid", "text not null default ''" },
1370 { "tres_usage_in_max_nodeid", "text not null default ''" },
1371 { "tres_usage_in_min", "text not null default ''" },
1372 { "tres_usage_in_min_taskid", "text not null default ''" },
1373 { "tres_usage_in_min_nodeid", "text not null default ''" },
1374 { "tres_usage_in_tot", "text not null default ''" },
1375 { "tres_usage_out_ave", "text not null default ''" },
1376 { "tres_usage_out_max", "text not null default ''" },
1377 { "tres_usage_out_max_taskid", "text not null default ''" },
1378 { "tres_usage_out_max_nodeid", "text not null default ''" },
1379 { "tres_usage_out_min", "text not null default ''" },
1380 { "tres_usage_out_min_taskid", "text not null default ''" },
1381 { "tres_usage_out_min_nodeid", "text not null default ''" },
1382 { "tres_usage_out_tot", "text not null default ''" },
1383 { NULL, NULL}
1384 };
1385
1386 storage_field_t suspend_table_fields[] = {
1387 { "job_db_inx", "bigint unsigned not null" },
1388 { "id_assoc", "int not null" },
1389 { "time_start", "bigint unsigned default 0 not null" },
1390 { "time_end", "bigint unsigned default 0 not null" },
1391 { NULL, NULL}
1392 };
1393
1394 storage_field_t wckey_table_fields[] = {
1395 { "creation_time", "bigint unsigned not null" },
1396 { "mod_time", "bigint unsigned default 0 not null" },
1397 { "deleted", "tinyint default 0 not null" },
1398 { "is_def", "tinyint default 0 not null" },
1399 { "id_wckey", "int unsigned not null auto_increment" },
1400 { "wckey_name", "tinytext not null default ''" },
1401 { "user", "tinytext not null" },
1402 { NULL, NULL}
1403 };
1404
1405 char table_name[200];
1406
1407 if (create_cluster_assoc_table(mysql_conn, cluster_name)
1408 == SLURM_ERROR)
1409 return SLURM_ERROR;
1410
1411 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1412 cluster_name, assoc_day_table);
1413
1414 if (mysql_db_create_table(mysql_conn, table_name,
1415 id_usage_table_fields,
1416 ", primary key (id, id_tres, time_start))")
1417 == SLURM_ERROR)
1418 return SLURM_ERROR;
1419
1420 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1421 cluster_name, assoc_hour_table);
1422
1423 if (mysql_db_create_table(mysql_conn, table_name,
1424 id_usage_table_fields,
1425 ", primary key (id, id_tres, time_start))")
1426 == SLURM_ERROR)
1427 return SLURM_ERROR;
1428
1429 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1430 cluster_name, assoc_month_table);
1431
1432 if (mysql_db_create_table(mysql_conn, table_name,
1433 id_usage_table_fields,
1434 ", primary key (id, id_tres, time_start))")
1435 == SLURM_ERROR)
1436 return SLURM_ERROR;
1437
1438 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1439 cluster_name, cluster_day_table);
1440
1441 if (mysql_db_create_table(mysql_conn, table_name,
1442 cluster_usage_table_fields,
1443 ", primary key (id_tres, time_start))")
1444 == SLURM_ERROR)
1445 return SLURM_ERROR;
1446
1447 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1448 cluster_name, cluster_hour_table);
1449
1450 if (mysql_db_create_table(mysql_conn, table_name,
1451 cluster_usage_table_fields,
1452 ", primary key (id_tres, time_start))")
1453 == SLURM_ERROR)
1454 return SLURM_ERROR;
1455
1456 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1457 cluster_name, cluster_month_table);
1458
1459 if (mysql_db_create_table(mysql_conn, table_name,
1460 cluster_usage_table_fields,
1461 ", primary key (id_tres, time_start))")
1462 == SLURM_ERROR)
1463 return SLURM_ERROR;
1464
1465 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1466 cluster_name, event_table);
1467
1468 if (mysql_db_create_table(mysql_conn, table_name,
1469 event_table_fields,
1470 ", primary key (node_name(42), time_start), "
1471 "key rollup (node_name(42), time_start, "
1472 "time_end, state))") == SLURM_ERROR)
1473 return SLURM_ERROR;
1474
1475 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1476 cluster_name, job_table);
1477
1478 /*
1479 * sacct_def is the index for query's with state as time_start is used
1480 * in these queries. sacct_def2 is for plain sacct queries.
1481 */
1482 if (mysql_db_create_table(mysql_conn, table_name, job_table_fields,
1483 ", primary key (job_db_inx), "
1484 "unique index (id_job, time_submit), "
1485 "key old_tuple (id_job, "
1486 "id_assoc, time_submit), "
1487 "key rollup (time_eligible, time_end), "
1488 "key rollup2 (time_end, time_eligible), "
1489 "key nodes_alloc (nodes_alloc), "
1490 "key wckey (id_wckey), "
1491 "key qos (id_qos), "
1492 "key association (id_assoc), "
1493 "key array_job (id_array_job), "
1494 "key het_job (het_job_id), "
1495 "key reserv (id_resv), "
1496 "key sacct_def (id_user, time_start, "
1497 "time_end), "
1498 "key sacct_def2 (id_user, time_end, "
1499 "time_eligible))")
1500 == SLURM_ERROR)
1501 return SLURM_ERROR;
1502
1503 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1504 cluster_name, last_ran_table);
1505 if (mysql_db_create_table(mysql_conn, table_name,
1506 last_ran_table_fields,
1507 ", primary key (hourly_rollup, "
1508 "daily_rollup, monthly_rollup))")
1509 == SLURM_ERROR)
1510 return SLURM_ERROR;
1511
1512 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1513 cluster_name, resv_table);
1514 if (mysql_db_create_table(mysql_conn, table_name,
1515 resv_table_fields,
1516 ", primary key (id_resv, time_start))")
1517 == SLURM_ERROR)
1518 return SLURM_ERROR;
1519
1520 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1521 cluster_name, step_table);
1522 if (mysql_db_create_table(mysql_conn, table_name,
1523 step_table_fields,
1524 ", primary key (job_db_inx, id_step))")
1525 == SLURM_ERROR)
1526 return SLURM_ERROR;
1527
1528 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1529 cluster_name, suspend_table);
1530 if (mysql_db_create_table(mysql_conn, table_name,
1531 suspend_table_fields,
1532 ", primary key (job_db_inx, time_start), "
1533 "key job_db_inx_times (job_db_inx, "
1534 "time_start, time_end))") == SLURM_ERROR)
1535 return SLURM_ERROR;
1536
1537 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1538 cluster_name, wckey_table);
1539 if (mysql_db_create_table(mysql_conn, table_name,
1540 wckey_table_fields,
1541 ", primary key (id_wckey), "
1542 " unique index udex (wckey_name(42), "
1543 "user(42)))")
1544 == SLURM_ERROR)
1545 return SLURM_ERROR;
1546
1547 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1548 cluster_name, wckey_day_table);
1549
1550 if (mysql_db_create_table(mysql_conn, table_name,
1551 id_usage_table_fields,
1552 ", primary key (id, id_tres, time_start))")
1553 == SLURM_ERROR)
1554 return SLURM_ERROR;
1555
1556 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1557 cluster_name, wckey_hour_table);
1558
1559 if (mysql_db_create_table(mysql_conn, table_name,
1560 id_usage_table_fields,
1561 ", primary key (id, id_tres, time_start))")
1562 == SLURM_ERROR)
1563 return SLURM_ERROR;
1564
1565 snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
1566 cluster_name, wckey_month_table);
1567
1568 if (mysql_db_create_table(mysql_conn, table_name,
1569 id_usage_table_fields,
1570 ", primary key (id, id_tres, time_start))")
1571 == SLURM_ERROR)
1572 return SLURM_ERROR;
1573
1574 return SLURM_SUCCESS;
1575 }
1576
remove_cluster_tables(mysql_conn_t * mysql_conn,char * cluster_name)1577 extern int remove_cluster_tables(mysql_conn_t *mysql_conn, char *cluster_name)
1578 {
1579 char *query = NULL;
1580 int rc = SLURM_SUCCESS;
1581 MYSQL_RES *result = NULL;
1582
1583 query = xstrdup_printf("select id_assoc from \"%s_%s\" limit 1;",
1584 cluster_name, assoc_table);
1585 debug4("%d(%s:%d) query\n%s",
1586 mysql_conn->conn, THIS_FILE, __LINE__, query);
1587 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
1588 xfree(query);
1589 error("no result given when querying cluster %s", cluster_name);
1590 return SLURM_ERROR;
1591 }
1592 xfree(query);
1593
1594 if (mysql_num_rows(result)) {
1595 mysql_free_result(result);
1596 debug4("we still have associations, can't remove tables");
1597 return SLURM_SUCCESS;
1598 }
1599 mysql_free_result(result);
1600 xstrfmtcat(mysql_conn->pre_commit_query,
1601 "drop table \"%s_%s\", \"%s_%s\", \"%s_%s\", "
1602 "\"%s_%s\", \"%s_%s\", \"%s_%s\", \"%s_%s\", "
1603 "\"%s_%s\", \"%s_%s\", \"%s_%s\", \"%s_%s\", "
1604 "\"%s_%s\", \"%s_%s\", \"%s_%s\", \"%s_%s\", "
1605 "\"%s_%s\", \"%s_%s\";",
1606 cluster_name, assoc_table,
1607 cluster_name, assoc_day_table,
1608 cluster_name, assoc_hour_table,
1609 cluster_name, assoc_month_table,
1610 cluster_name, cluster_day_table,
1611 cluster_name, cluster_hour_table,
1612 cluster_name, cluster_month_table,
1613 cluster_name, event_table,
1614 cluster_name, job_table,
1615 cluster_name, last_ran_table,
1616 cluster_name, resv_table,
1617 cluster_name, step_table,
1618 cluster_name, suspend_table,
1619 cluster_name, wckey_table,
1620 cluster_name, wckey_day_table,
1621 cluster_name, wckey_hour_table,
1622 cluster_name, wckey_month_table);
1623 /* Since we could possibly add this exact cluster after this
1624 we will require a commit before doing anything else. This
1625 flag will give us that.
1626 */
1627 mysql_conn->cluster_deleted = 1;
1628 return rc;
1629 }
1630
setup_assoc_limits(slurmdb_assoc_rec_t * assoc,char ** cols,char ** vals,char ** extra,qos_level_t qos_level,bool for_add)1631 extern int setup_assoc_limits(slurmdb_assoc_rec_t *assoc,
1632 char **cols, char **vals,
1633 char **extra, qos_level_t qos_level,
1634 bool for_add)
1635 {
1636 uint32_t tres_str_flags = TRES_STR_FLAG_REMOVE |
1637 TRES_STR_FLAG_SORT_ID | TRES_STR_FLAG_SIMPLE |
1638 TRES_STR_FLAG_NO_NULL;
1639
1640 assoc_mgr_lock_t locks = { NO_LOCK, NO_LOCK, READ_LOCK, NO_LOCK,
1641 NO_LOCK, NO_LOCK, NO_LOCK };
1642 if (!assoc)
1643 return SLURM_ERROR;
1644
1645 if (for_add) {
1646 /* If we are adding we should make sure we don't get
1647 old reside sitting around from a former life.
1648 */
1649 if (assoc->shares_raw == NO_VAL)
1650 assoc->shares_raw = INFINITE;
1651 if (assoc->grp_jobs == NO_VAL)
1652 assoc->grp_jobs = INFINITE;
1653 if (assoc->grp_jobs_accrue == NO_VAL)
1654 assoc->grp_jobs_accrue = INFINITE;
1655 if (assoc->grp_submit_jobs == NO_VAL)
1656 assoc->grp_submit_jobs = INFINITE;
1657 if (assoc->grp_wall == NO_VAL)
1658 assoc->grp_wall = INFINITE;
1659 if (assoc->max_jobs == NO_VAL)
1660 assoc->max_jobs = INFINITE;
1661 if (assoc->max_jobs_accrue == NO_VAL)
1662 assoc->max_jobs_accrue = INFINITE;
1663 if (assoc->min_prio_thresh == NO_VAL)
1664 assoc->min_prio_thresh = INFINITE;
1665 if (assoc->max_submit_jobs == NO_VAL)
1666 assoc->max_submit_jobs = INFINITE;
1667 if (assoc->max_wall_pj == NO_VAL)
1668 assoc->max_wall_pj = INFINITE;
1669 if (assoc->priority == NO_VAL)
1670 assoc->priority = INFINITE;
1671 if (assoc->def_qos_id == NO_VAL)
1672 assoc->def_qos_id = INFINITE;
1673 }
1674
1675 if (assoc->shares_raw == INFINITE) {
1676 xstrcat(*cols, ", shares");
1677 xstrcat(*vals, ", 1");
1678 xstrcat(*extra, ", shares=1");
1679 assoc->shares_raw = 1;
1680 } else if ((assoc->shares_raw != NO_VAL)
1681 && (int32_t)assoc->shares_raw >= 0) {
1682 xstrcat(*cols, ", shares");
1683 xstrfmtcat(*vals, ", %u", assoc->shares_raw);
1684 xstrfmtcat(*extra, ", shares=%u", assoc->shares_raw);
1685 }
1686
1687 if (assoc->grp_jobs == INFINITE) {
1688 xstrcat(*cols, ", grp_jobs");
1689 xstrcat(*vals, ", NULL");
1690 xstrcat(*extra, ", grp_jobs=NULL");
1691 } else if ((assoc->grp_jobs != NO_VAL)
1692 && ((int32_t)assoc->grp_jobs >= 0)) {
1693 xstrcat(*cols, ", grp_jobs");
1694 xstrfmtcat(*vals, ", %u", assoc->grp_jobs);
1695 xstrfmtcat(*extra, ", grp_jobs=%u", assoc->grp_jobs);
1696 }
1697
1698 if (assoc->grp_jobs_accrue == INFINITE) {
1699 xstrcat(*cols, ", grp_jobs_accrue");
1700 xstrcat(*vals, ", NULL");
1701 xstrcat(*extra, ", grp_jobs_accrue=NULL");
1702 } else if ((assoc->grp_jobs_accrue != NO_VAL)
1703 && ((int32_t)assoc->grp_jobs_accrue >= 0)) {
1704 xstrcat(*cols, ", grp_jobs_accrue");
1705 xstrfmtcat(*vals, ", %u", assoc->grp_jobs_accrue);
1706 xstrfmtcat(*extra, ", grp_jobs_accrue=%u",
1707 assoc->grp_jobs_accrue);
1708 }
1709
1710 if (assoc->grp_submit_jobs == INFINITE) {
1711 xstrcat(*cols, ", grp_submit_jobs");
1712 xstrcat(*vals, ", NULL");
1713 xstrcat(*extra, ", grp_submit_jobs=NULL");
1714 } else if ((assoc->grp_submit_jobs != NO_VAL)
1715 && ((int32_t)assoc->grp_submit_jobs >= 0)) {
1716 xstrcat(*cols, ", grp_submit_jobs");
1717 xstrfmtcat(*vals, ", %u", assoc->grp_submit_jobs);
1718 xstrfmtcat(*extra, ", grp_submit_jobs=%u",
1719 assoc->grp_submit_jobs);
1720 }
1721
1722 if (assoc->grp_wall == INFINITE) {
1723 xstrcat(*cols, ", grp_wall");
1724 xstrcat(*vals, ", NULL");
1725 xstrcat(*extra, ", grp_wall=NULL");
1726 } else if ((assoc->grp_wall != NO_VAL)
1727 && ((int32_t)assoc->grp_wall >= 0)) {
1728 xstrcat(*cols, ", grp_wall");
1729 xstrfmtcat(*vals, ", %u", assoc->grp_wall);
1730 xstrfmtcat(*extra, ", grp_wall=%u", assoc->grp_wall);
1731 }
1732
1733 /* this only gets set on a user's association and is_def
1734 * could be NO_VAL only 1 is accepted */
1735 if ((assoc->is_def == 1)
1736 && ((qos_level == QOS_LEVEL_MODIFY)
1737 || (assoc->user && assoc->cluster && assoc->acct))) {
1738 xstrcat(*cols, ", is_def");
1739 xstrcat(*vals, ", 1");
1740 xstrcat(*extra, ", is_def=1");
1741 }
1742
1743 if (assoc->max_jobs == INFINITE) {
1744 xstrcat(*cols, ", max_jobs");
1745 xstrcat(*vals, ", NULL");
1746 xstrcat(*extra, ", max_jobs=NULL");
1747 } else if ((assoc->max_jobs != NO_VAL)
1748 && ((int32_t)assoc->max_jobs >= 0)) {
1749 xstrcat(*cols, ", max_jobs");
1750 xstrfmtcat(*vals, ", %u", assoc->max_jobs);
1751 xstrfmtcat(*extra, ", max_jobs=%u", assoc->max_jobs);
1752 }
1753
1754 if (assoc->max_jobs_accrue == INFINITE) {
1755 xstrcat(*cols, ", max_jobs_accrue");
1756 xstrcat(*vals, ", NULL");
1757 xstrcat(*extra, ", max_jobs_accrue=NULL");
1758 } else if ((assoc->max_jobs_accrue != NO_VAL)
1759 && ((int32_t)assoc->max_jobs_accrue >= 0)) {
1760 xstrcat(*cols, ", max_jobs_accrue");
1761 xstrfmtcat(*vals, ", %u", assoc->max_jobs_accrue);
1762 xstrfmtcat(*extra, ", max_jobs_accrue=%u",
1763 assoc->max_jobs_accrue);
1764 }
1765
1766 if (assoc->min_prio_thresh == INFINITE) {
1767 xstrcat(*cols, ", min_prio_thresh");
1768 xstrcat(*vals, ", NULL");
1769 xstrcat(*extra, ", min_prio_thresh=NULL");
1770 } else if ((assoc->min_prio_thresh != NO_VAL)
1771 && ((int32_t)assoc->min_prio_thresh >= 0)) {
1772 xstrcat(*cols, ", min_prio_thresh");
1773 xstrfmtcat(*vals, ", %u", assoc->min_prio_thresh);
1774 xstrfmtcat(*extra, ", min_prio_thresh=%u",
1775 assoc->min_prio_thresh);
1776 }
1777
1778 if (assoc->max_submit_jobs == INFINITE) {
1779 xstrcat(*cols, ", max_submit_jobs");
1780 xstrcat(*vals, ", NULL");
1781 xstrcat(*extra, ", max_submit_jobs=NULL");
1782 } else if ((assoc->max_submit_jobs != NO_VAL)
1783 && ((int32_t)assoc->max_submit_jobs >= 0)) {
1784 xstrcat(*cols, ", max_submit_jobs");
1785 xstrfmtcat(*vals, ", %u", assoc->max_submit_jobs);
1786 xstrfmtcat(*extra, ", max_submit_jobs=%u",
1787 assoc->max_submit_jobs);
1788 }
1789
1790 if (assoc->max_wall_pj == INFINITE) {
1791 xstrcat(*cols, ", max_wall_pj");
1792 xstrcat(*vals, ", NULL");
1793 xstrcat(*extra, ", max_wall_pj=NULL");
1794 } else if ((assoc->max_wall_pj != NO_VAL)
1795 && ((int32_t)assoc->max_wall_pj >= 0)) {
1796 xstrcat(*cols, ", max_wall_pj");
1797 xstrfmtcat(*vals, ", %u", assoc->max_wall_pj);
1798 xstrfmtcat(*extra, ", max_wall_pj=%u", assoc->max_wall_pj);
1799 }
1800
1801 if (assoc->priority == INFINITE) {
1802 xstrcat(*cols, ", priority");
1803 xstrcat(*vals, ", NULL");
1804 xstrcat(*extra, ", priority=NULL");
1805 } else if ((assoc->priority != NO_VAL)
1806 && ((int32_t)assoc->priority >= 0)) {
1807 xstrcat(*cols, ", priority");
1808 xstrfmtcat(*vals, ", %u", assoc->priority);
1809 xstrfmtcat(*extra, ", priority=%u", assoc->priority);
1810 }
1811
1812 if (assoc->def_qos_id == INFINITE) {
1813 xstrcat(*cols, ", def_qos_id");
1814 xstrcat(*vals, ", NULL");
1815 xstrcat(*extra, ", def_qos_id=NULL");
1816 } else if ((assoc->def_qos_id != NO_VAL)
1817 && ((int32_t)assoc->def_qos_id > 0)) {
1818 assoc_mgr_lock(&locks);
1819 if (!list_find_first(assoc_mgr_qos_list,
1820 slurmdb_find_qos_in_list, &(assoc->def_qos_id))) {
1821 assoc_mgr_unlock(&locks);
1822 return ESLURM_INVALID_QOS;
1823 }
1824 assoc_mgr_unlock(&locks);
1825 xstrcat(*cols, ", def_qos_id");
1826 xstrfmtcat(*vals, ", %u", assoc->def_qos_id);
1827 xstrfmtcat(*extra, ", def_qos_id=%u", assoc->def_qos_id);
1828 }
1829
1830 /* When modifying anything below this comment it happens in
1831 * the actual function since we have to wait until we hear
1832 * about the parent first.
1833 * What we do to make it known something needs to be changed
1834 * is we cat "" onto extra which will inform the caller
1835 * something needs changing.
1836 */
1837
1838 if (assoc->grp_tres) {
1839 if (qos_level == QOS_LEVEL_MODIFY) {
1840 xstrcat(*extra, "");
1841 goto end_modify;
1842 }
1843 xstrcat(*cols, ", grp_tres");
1844 slurmdb_combine_tres_strings(
1845 &assoc->grp_tres, NULL, tres_str_flags);
1846 xstrfmtcat(*vals, ", '%s'", assoc->grp_tres);
1847 xstrfmtcat(*extra, ", grp_tres='%s'", assoc->grp_tres);
1848 }
1849
1850 if (assoc->grp_tres_mins) {
1851 if (qos_level == QOS_LEVEL_MODIFY) {
1852 xstrcat(*extra, "");
1853 goto end_modify;
1854 }
1855 xstrcat(*cols, ", grp_tres_mins");
1856 slurmdb_combine_tres_strings(
1857 &assoc->grp_tres_mins, NULL, tres_str_flags);
1858 xstrfmtcat(*vals, ", '%s'", assoc->grp_tres_mins);
1859 xstrfmtcat(*extra, ", grp_tres_mins='%s'",
1860 assoc->grp_tres_mins);
1861 }
1862
1863 if (assoc->grp_tres_run_mins) {
1864 if (qos_level == QOS_LEVEL_MODIFY) {
1865 xstrcat(*extra, "");
1866 goto end_modify;
1867 }
1868 xstrcat(*cols, ", grp_tres_run_mins");
1869 slurmdb_combine_tres_strings(
1870 &assoc->grp_tres_run_mins, NULL, tres_str_flags);
1871 xstrfmtcat(*vals, ", '%s'", assoc->grp_tres_run_mins);
1872 xstrfmtcat(*extra, ", grp_tres_run_mins='%s'",
1873 assoc->grp_tres_run_mins);
1874 }
1875
1876 if (assoc->max_tres_pj) {
1877 if (qos_level == QOS_LEVEL_MODIFY) {
1878 xstrcat(*extra, "");
1879 goto end_modify;
1880 }
1881 xstrcat(*cols, ", max_tres_pj");
1882 slurmdb_combine_tres_strings(
1883 &assoc->max_tres_pj, NULL, tres_str_flags);
1884 xstrfmtcat(*vals, ", '%s'", assoc->max_tres_pj);
1885 xstrfmtcat(*extra, ", max_tres_pj='%s'", assoc->max_tres_pj);
1886 }
1887
1888 if (assoc->max_tres_pn) {
1889 if (qos_level == QOS_LEVEL_MODIFY) {
1890 xstrcat(*extra, "");
1891 goto end_modify;
1892 }
1893 xstrcat(*cols, ", max_tres_pn");
1894 slurmdb_combine_tres_strings(
1895 &assoc->max_tres_pn, NULL, tres_str_flags);
1896 xstrfmtcat(*vals, ", '%s'", assoc->max_tres_pn);
1897 xstrfmtcat(*extra, ", max_tres_pn='%s'", assoc->max_tres_pn);
1898 }
1899
1900 if (assoc->max_tres_mins_pj) {
1901 if (qos_level == QOS_LEVEL_MODIFY) {
1902 xstrcat(*extra, "");
1903 goto end_modify;
1904 }
1905 xstrcat(*cols, ", max_tres_mins_pj");
1906 slurmdb_combine_tres_strings(
1907 &assoc->max_tres_mins_pj, NULL, tres_str_flags);
1908 xstrfmtcat(*vals, ", '%s'", assoc->max_tres_mins_pj);
1909 xstrfmtcat(*extra, ", max_tres_mins_pj='%s'",
1910 assoc->max_tres_mins_pj);
1911 }
1912
1913 if (assoc->max_tres_run_mins) {
1914 if (qos_level == QOS_LEVEL_MODIFY) {
1915 xstrcat(*extra, "");
1916 goto end_modify;
1917 }
1918 xstrcat(*cols, ", max_tres_run_mins");
1919 slurmdb_combine_tres_strings(
1920 &assoc->max_tres_run_mins, NULL, tres_str_flags);
1921 xstrfmtcat(*vals, ", '%s'", assoc->max_tres_run_mins);
1922 xstrfmtcat(*extra, ", max_tres_run_mins='%s'",
1923 assoc->max_tres_run_mins);
1924 }
1925
1926 if (assoc->qos_list && list_count(assoc->qos_list)) {
1927 char *qos_type = "qos";
1928 char *qos_val = NULL;
1929 char *tmp_char = NULL;
1930 int set = 0;
1931 ListIterator qos_itr;
1932
1933 if (qos_level == QOS_LEVEL_MODIFY) {
1934 xstrcat(*extra, "");
1935 goto end_modify;
1936 }
1937
1938 qos_itr = list_iterator_create(assoc->qos_list);
1939 while ((tmp_char = list_next(qos_itr))) {
1940 /* we don't want to include blank names */
1941 if (!tmp_char[0])
1942 continue;
1943 if (!set) {
1944 if (tmp_char[0] == '+' || tmp_char[0] == '-')
1945 qos_type = "delta_qos";
1946 set = 1;
1947 }
1948 xstrfmtcat(qos_val, ",%s", tmp_char);
1949 }
1950
1951 list_iterator_destroy(qos_itr);
1952 if (qos_val) {
1953 xstrfmtcat(*cols, ", %s", qos_type);
1954 xstrfmtcat(*vals, ", '%s,'", qos_val);
1955 xstrfmtcat(*extra, ", %s='%s,'", qos_type, qos_val);
1956 xfree(qos_val);
1957 }
1958 } else if ((qos_level == QOS_LEVEL_SET) && default_qos_str) {
1959 /* Add default qos to the account */
1960 xstrcat(*cols, ", qos");
1961 xstrfmtcat(*vals, ", '%s,'", default_qos_str);
1962 xstrfmtcat(*extra, ", qos='%s,'", default_qos_str);
1963 if (!assoc->qos_list)
1964 assoc->qos_list = list_create(xfree_ptr);
1965 slurm_addto_char_list(assoc->qos_list, default_qos_str);
1966 } else if (qos_level != QOS_LEVEL_MODIFY) {
1967 /* clear the qos */
1968 xstrcat(*cols, ", qos, delta_qos");
1969 xstrcat(*vals, ", '', ''");
1970 xstrcat(*extra, ", qos='', delta_qos=''");
1971 }
1972 end_modify:
1973
1974 return SLURM_SUCCESS;
1975
1976 }
1977
1978 /* This is called by most modify functions to alter the table and
1979 * insert a new line in the transaction table.
1980 */
modify_common(mysql_conn_t * mysql_conn,uint16_t type,time_t now,char * user_name,char * table,char * cond_char,char * vals,char * cluster_name)1981 extern int modify_common(mysql_conn_t *mysql_conn,
1982 uint16_t type,
1983 time_t now,
1984 char *user_name,
1985 char *table,
1986 char *cond_char,
1987 char *vals,
1988 char *cluster_name)
1989 {
1990 char *query = NULL;
1991 int rc = SLURM_SUCCESS;
1992 char *tmp_cond_char = slurm_add_slash_to_quotes(cond_char);
1993 char *tmp_vals = NULL;
1994 bool cluster_centric = true;
1995
1996 /* figure out which tables we need to append the cluster name to */
1997 if ((table == cluster_table) || (table == acct_coord_table)
1998 || (table == acct_table) || (table == qos_table)
1999 || (table == txn_table) || (table == user_table)
2000 || (table == res_table) || (table == clus_res_table)
2001 || (table == federation_table))
2002 cluster_centric = false;
2003
2004 if (vals && vals[1])
2005 tmp_vals = slurm_add_slash_to_quotes(vals+2);
2006
2007 if (cluster_centric) {
2008 xassert(cluster_name);
2009 xstrfmtcat(query,
2010 "update \"%s_%s\" set mod_time=%ld%s "
2011 "where deleted=0 && %s;",
2012 cluster_name, table, now, vals, cond_char);
2013 xstrfmtcat(query,
2014 "insert into %s "
2015 "(timestamp, action, name, cluster, actor, info) "
2016 "values (%ld, %d, '%s', '%s', '%s', '%s');",
2017 txn_table,
2018 now, type, tmp_cond_char, cluster_name,
2019 user_name, tmp_vals);
2020 } else {
2021 xstrfmtcat(query,
2022 "update %s set mod_time=%ld%s "
2023 "where deleted=0 && %s;",
2024 table, now, vals, cond_char);
2025 xstrfmtcat(query,
2026 "insert into %s "
2027 "(timestamp, action, name, actor, info) "
2028 "values (%ld, %d, '%s', '%s', '%s');",
2029 txn_table,
2030 now, type, tmp_cond_char, user_name, tmp_vals);
2031 }
2032 xfree(tmp_cond_char);
2033 xfree(tmp_vals);
2034 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2035 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
2036 rc = mysql_db_query(mysql_conn, query);
2037 xfree(query);
2038
2039 if (rc != SLURM_SUCCESS) {
2040 reset_mysql_conn(mysql_conn);
2041 return SLURM_ERROR;
2042 }
2043
2044 return SLURM_SUCCESS;
2045 }
2046
2047 /* Every option in assoc_char should have a 't1.' infront of it. */
remove_common(mysql_conn_t * mysql_conn,uint16_t type,time_t now,char * user_name,char * table,char * name_char,char * assoc_char,char * cluster_name,List ret_list,bool * jobs_running)2048 extern int remove_common(mysql_conn_t *mysql_conn,
2049 uint16_t type,
2050 time_t now,
2051 char *user_name,
2052 char *table,
2053 char *name_char,
2054 char *assoc_char,
2055 char *cluster_name,
2056 List ret_list,
2057 bool *jobs_running)
2058 {
2059 int rc = SLURM_SUCCESS;
2060 char *query = NULL;
2061 char *loc_assoc_char = NULL, *loc_usage_id_char = NULL;
2062 MYSQL_RES *result = NULL;
2063 MYSQL_ROW row;
2064 time_t day_old = now - DELETE_SEC_BACK;
2065 bool has_jobs = false;
2066 char *tmp_name_char = NULL;
2067 bool cluster_centric = true;
2068 uint32_t smallest_lft = 0xFFFFFFFF;
2069
2070 /* figure out which tables we need to append the cluster name to */
2071 if ((table == cluster_table) || (table == acct_coord_table)
2072 || (table == acct_table) || (table == qos_table)
2073 || (table == txn_table) || (table == user_table)
2074 || (table == res_table) || (table == clus_res_table)
2075 || (table == federation_table))
2076 cluster_centric = false;
2077
2078 /* If we have jobs associated with this we do not want to
2079 * really delete it for accounting purposes. This is for
2080 * corner cases most of the time this won't matter.
2081 */
2082 if ((table == acct_coord_table) || (table == res_table)
2083 || (table == clus_res_table) || (table == federation_table)) {
2084 /* This doesn't apply for these tables since we are
2085 * only looking for association type tables.
2086 */
2087 } else if ((table == qos_table) || (table == wckey_table)) {
2088 if (cluster_name)
2089 has_jobs = _check_jobs_before_remove_without_assoctable(
2090 mysql_conn, cluster_name, assoc_char);
2091 } else if (table != assoc_table) {
2092 /* first check to see if we are running jobs now */
2093 if (_check_jobs_before_remove(
2094 mysql_conn, cluster_name, assoc_char,
2095 ret_list, jobs_running) || (*jobs_running))
2096 return SLURM_SUCCESS;
2097
2098 has_jobs = _check_jobs_before_remove(
2099 mysql_conn, cluster_name, assoc_char, NULL, NULL);
2100 } else {
2101 /* first check to see if we are running jobs now */
2102 if (_check_jobs_before_remove_assoc(
2103 mysql_conn, cluster_name, name_char,
2104 ret_list, jobs_running) || (*jobs_running))
2105 return SLURM_SUCCESS;
2106
2107 /* now check to see if any jobs were ever run. */
2108 has_jobs = _check_jobs_before_remove_assoc(
2109 mysql_conn, cluster_name, name_char,
2110 NULL, NULL);
2111 }
2112 /* we want to remove completely all that is less than a day old */
2113 if (!has_jobs && table != assoc_table) {
2114 if (cluster_centric) {
2115 query = xstrdup_printf("delete from \"%s_%s\" where "
2116 "creation_time>%ld && (%s);",
2117 cluster_name, table, day_old,
2118 name_char);
2119 } else {
2120 query = xstrdup_printf("delete from %s where "
2121 "creation_time>%ld && (%s);",
2122 table, day_old, name_char);
2123 }
2124 }
2125
2126 if (table != assoc_table) {
2127 if (cluster_centric) {
2128 xstrfmtcat(query,
2129 "update \"%s_%s\" set mod_time=%ld, "
2130 "deleted=1 where deleted=0 && (%s);",
2131 cluster_name, table, now, name_char);
2132 } else if (table == federation_table) {
2133 xstrfmtcat(query,
2134 "update %s set "
2135 "mod_time=%ld, deleted=1, "
2136 "flags=DEFAULT "
2137 "where deleted=0 && (%s);",
2138 federation_table, now,
2139 name_char);
2140 } else if (table == qos_table) {
2141 xstrfmtcat(query,
2142 "update %s set "
2143 "mod_time=%ld, deleted=1, "
2144 "grace_time=DEFAULT, "
2145 "max_jobs_pa=DEFAULT, "
2146 "max_jobs_per_user=DEFAULT, "
2147 "max_jobs_accrue_pa=DEFAULT, "
2148 "max_jobs_accrue_pu=DEFAULT, "
2149 "min_prio_thresh=DEFAULT, "
2150 "max_submit_jobs_pa=DEFAULT, "
2151 "max_submit_jobs_per_user=DEFAULT, "
2152 "max_tres_pa=DEFAULT, "
2153 "max_tres_pj=DEFAULT, "
2154 "max_tres_pn=DEFAULT, "
2155 "max_tres_pu=DEFAULT, "
2156 "max_tres_mins_pj=DEFAULT, "
2157 "max_tres_run_mins_pa=DEFAULT, "
2158 "max_tres_run_mins_pu=DEFAULT, "
2159 "min_tres_pj=DEFAULT, "
2160 "max_wall_duration_per_job=DEFAULT, "
2161 "grp_jobs=DEFAULT, grp_submit_jobs=DEFAULT, "
2162 "grp_jobs_accrue=DEFAULT, grp_tres=DEFAULT, "
2163 "grp_tres_mins=DEFAULT, "
2164 "grp_tres_run_mins=DEFAULT, "
2165 "grp_wall=DEFAULT, "
2166 "preempt=DEFAULT, "
2167 "preempt_exempt_time=DEFAULT, "
2168 "priority=DEFAULT, "
2169 "usage_factor=DEFAULT, "
2170 "usage_thres=DEFAULT "
2171 "where deleted=0 && (%s);",
2172 qos_table, now, name_char);
2173 } else {
2174 xstrfmtcat(query,
2175 "update %s set mod_time=%ld, deleted=1 "
2176 "where deleted=0 && (%s);",
2177 table, now, name_char);
2178 }
2179 }
2180
2181 /* If we are removing assocs use the assoc_char since the
2182 name_char has lft between statements that can change over
2183 time. The assoc_char has the actual ids of the assocs
2184 which never change.
2185 */
2186 if (type == DBD_REMOVE_ASSOCS && assoc_char)
2187 tmp_name_char = slurm_add_slash_to_quotes(assoc_char);
2188 else
2189 tmp_name_char = slurm_add_slash_to_quotes(name_char);
2190
2191 if (cluster_centric)
2192 xstrfmtcat(query,
2193 "insert into %s (timestamp, action, name, "
2194 "actor, cluster) values "
2195 "(%ld, %d, '%s', '%s', '%s');",
2196 txn_table,
2197 now, type, tmp_name_char, user_name, cluster_name);
2198 else
2199 xstrfmtcat(query,
2200 "insert into %s (timestamp, action, name, actor) "
2201 "values (%ld, %d, '%s', '%s');",
2202 txn_table,
2203 now, type, tmp_name_char, user_name);
2204
2205 xfree(tmp_name_char);
2206
2207 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2208 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
2209 rc = mysql_db_query(mysql_conn, query);
2210 xfree(query);
2211 if (rc != SLURM_SUCCESS) {
2212 reset_mysql_conn(mysql_conn);
2213 return SLURM_ERROR;
2214 } else if ((table == acct_coord_table)
2215 || (table == wckey_table)
2216 || (table == clus_res_table)
2217 || (table == res_table)
2218 || (table == federation_table)
2219 || (table == qos_table))
2220 return SLURM_SUCCESS;
2221
2222 /* mark deleted=1 or remove completely the accounting tables
2223 */
2224 if (table != assoc_table) {
2225 if (!assoc_char) {
2226 error("no assoc_char");
2227 if (mysql_conn->rollback) {
2228 mysql_db_rollback(mysql_conn);
2229 }
2230 list_flush(mysql_conn->update_list);
2231 return SLURM_ERROR;
2232 }
2233
2234 /* If we are doing this on an assoc_table we have
2235 already done this, so don't */
2236 query = xstrdup_printf("select distinct t1.id_assoc "
2237 "from \"%s_%s\" as t1, \"%s_%s\" as t2 "
2238 "where (%s) && t1.lft between "
2239 "t2.lft and t2.rgt && t1.deleted=0 "
2240 "&& t2.deleted=0;",
2241 cluster_name, assoc_table,
2242 cluster_name, assoc_table, assoc_char);
2243
2244 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2245 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
2246 if (!(result = mysql_db_query_ret(
2247 mysql_conn, query, 0))) {
2248 xfree(query);
2249 if (mysql_conn->rollback) {
2250 mysql_db_rollback(mysql_conn);
2251 }
2252 list_flush(mysql_conn->update_list);
2253 return SLURM_ERROR;
2254 }
2255 xfree(query);
2256
2257 rc = 0;
2258 xfree(loc_assoc_char);
2259 while ((row = mysql_fetch_row(result))) {
2260 slurmdb_assoc_rec_t *rem_assoc = NULL;
2261 if (loc_assoc_char)
2262 xstrcat(loc_assoc_char, " || ");
2263 xstrfmtcat(loc_assoc_char, "id_assoc=%s", row[0]);
2264
2265 rem_assoc = xmalloc(sizeof(slurmdb_assoc_rec_t));
2266 rem_assoc->id = slurm_atoul(row[0]);
2267 rem_assoc->cluster = xstrdup(cluster_name);
2268 if (addto_update_list(mysql_conn->update_list,
2269 SLURMDB_REMOVE_ASSOC,
2270 rem_assoc) != SLURM_SUCCESS)
2271 error("couldn't add to the update list");
2272 }
2273 mysql_free_result(result);
2274 } else
2275 loc_assoc_char = assoc_char;
2276
2277 if (!loc_assoc_char) {
2278 debug2("No associations with object being deleted");
2279 return rc;
2280 }
2281
2282 loc_usage_id_char = xstrdup(loc_assoc_char);
2283 xstrsubstituteall(loc_usage_id_char, "id_assoc", "id");
2284
2285 /* We should not have to delete from usage table, only flag since we
2286 * only delete things that are typos.
2287 */
2288 xstrfmtcat(query,
2289 "update \"%s_%s\" set mod_time=%ld, deleted=1 where (%s);"
2290 "update \"%s_%s\" set mod_time=%ld, deleted=1 where (%s);"
2291 "update \"%s_%s\" set mod_time=%ld, deleted=1 where (%s);",
2292 cluster_name, assoc_day_table, now, loc_usage_id_char,
2293 cluster_name, assoc_hour_table, now, loc_usage_id_char,
2294 cluster_name, assoc_month_table, now, loc_usage_id_char);
2295 xfree(loc_usage_id_char);
2296
2297 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2298 DB_DEBUG(mysql_conn->conn, "query\n%s %zu",
2299 query, strlen(query));
2300 rc = mysql_db_query(mysql_conn, query);
2301 xfree(query);
2302 if (rc != SLURM_SUCCESS) {
2303 reset_mysql_conn(mysql_conn);
2304 return SLURM_ERROR;
2305 }
2306
2307 /* If we have jobs that have ran don't go through the logic of
2308 * removing the associations. Since we may want them for
2309 * reports in the future since jobs had ran.
2310 */
2311 if (has_jobs)
2312 goto just_update;
2313
2314 /* remove completely all the associations for this added in the last
2315 * day, since they are most likely nothing we really wanted in
2316 * the first place.
2317 */
2318 query = xstrdup_printf("select id_assoc from \"%s_%s\" as t1 where "
2319 "creation_time>%ld && (%s);",
2320 cluster_name, assoc_table,
2321 day_old, loc_assoc_char);
2322
2323 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2324 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
2325 if (!(result = mysql_db_query_ret(
2326 mysql_conn, query, 0))) {
2327 xfree(query);
2328 reset_mysql_conn(mysql_conn);
2329 return SLURM_ERROR;
2330 }
2331 xfree(query);
2332
2333 while ((row = mysql_fetch_row(result))) {
2334 MYSQL_RES *result2 = NULL;
2335 MYSQL_ROW row2;
2336 uint32_t lft;
2337
2338 /* we have to do this one at a time since the lft's and rgt's
2339 change. If you think you need to remove this make
2340 sure your new way can handle changing lft and rgt's
2341 in the association. */
2342 xstrfmtcat(query,
2343 "SELECT lft, rgt, (rgt - lft + 1) "
2344 "FROM \"%s_%s\" WHERE id_assoc = %s;",
2345 cluster_name, assoc_table, row[0]);
2346 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2347 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
2348 if (!(result2 = mysql_db_query_ret(
2349 mysql_conn, query, 0))) {
2350 xfree(query);
2351 rc = SLURM_ERROR;
2352 break;
2353 }
2354 xfree(query);
2355 if (!(row2 = mysql_fetch_row(result2))) {
2356 mysql_free_result(result2);
2357 continue;
2358 }
2359
2360 xstrfmtcat(query,
2361 "delete quick from \"%s_%s\" where "
2362 "lft between %s AND %s;",
2363 cluster_name, assoc_table, row2[0], row2[1]);
2364
2365 xstrfmtcat(query,
2366 "UPDATE \"%s_%s\" SET rgt = rgt - %s WHERE rgt > %s;"
2367 "UPDATE \"%s_%s\" SET "
2368 "lft = lft - %s WHERE lft > %s;",
2369 cluster_name, assoc_table, row2[2], row2[1],
2370 cluster_name, assoc_table, row2[2], row2[1]);
2371
2372 lft = slurm_atoul(row2[0]);
2373 if (lft < smallest_lft)
2374 smallest_lft = lft;
2375
2376 mysql_free_result(result2);
2377
2378 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2379 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
2380 rc = mysql_db_query(mysql_conn, query);
2381 xfree(query);
2382 if (rc != SLURM_SUCCESS) {
2383 error("couldn't remove assoc");
2384 break;
2385 }
2386 }
2387 mysql_free_result(result);
2388 /* This already happened before, but we need to run it again
2389 since the first time we ran it we didn't know if we were
2390 going to remove the above associations.
2391 */
2392 if (rc == SLURM_SUCCESS)
2393 rc = as_mysql_get_modified_lfts(mysql_conn,
2394 cluster_name, smallest_lft);
2395
2396 if (rc == SLURM_ERROR) {
2397 reset_mysql_conn(mysql_conn);
2398 return rc;
2399 }
2400
2401 just_update:
2402 /* now update the associations themselves that are still
2403 * around clearing all the limits since if we add them back
2404 * we don't want any residue from past associations lingering
2405 * around.
2406 */
2407 query = xstrdup_printf("update \"%s_%s\" as t1 set "
2408 "mod_time=%ld, deleted=1, def_qos_id=DEFAULT, "
2409 "shares=DEFAULT, max_jobs=DEFAULT, "
2410 "max_jobs_accrue=DEFAULT, "
2411 "min_prio_thresh=DEFAULT, "
2412 "max_submit_jobs=DEFAULT, "
2413 "max_wall_pj=DEFAULT, "
2414 "max_tres_pj=DEFAULT, "
2415 "max_tres_pn=DEFAULT, "
2416 "max_tres_mins_pj=DEFAULT, "
2417 "max_tres_run_mins=DEFAULT, "
2418 "grp_jobs=DEFAULT, grp_submit_jobs=DEFAULT, "
2419 "grp_jobs_accrue=DEFAULT, grp_wall=DEFAULT, "
2420 "grp_tres=DEFAULT, "
2421 "grp_tres_mins=DEFAULT, "
2422 "grp_tres_run_mins=DEFAULT, "
2423 "qos=DEFAULT, delta_qos=DEFAULT, "
2424 "priority=DEFAULT "
2425 "where (%s);",
2426 cluster_name, assoc_table, now,
2427 loc_assoc_char);
2428
2429 if (table != assoc_table)
2430 xfree(loc_assoc_char);
2431
2432 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2433 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
2434 rc = mysql_db_query(mysql_conn, query);
2435 xfree(query);
2436 if (rc != SLURM_SUCCESS) {
2437 reset_mysql_conn(mysql_conn);
2438 }
2439
2440 return rc;
2441 }
2442
mod_tres_str(char ** out,char * mod,char * cur,char * cur_par,char * name,char ** vals,uint32_t id,bool assoc)2443 extern void mod_tres_str(char **out, char *mod, char *cur,
2444 char *cur_par, char *name, char **vals,
2445 uint32_t id, bool assoc)
2446 {
2447 uint32_t tres_str_flags = TRES_STR_FLAG_REMOVE |
2448 TRES_STR_FLAG_SORT_ID | TRES_STR_FLAG_SIMPLE |
2449 TRES_STR_FLAG_NO_NULL;
2450
2451 xassert(out);
2452 xassert(name);
2453
2454 if (!mod)
2455 return;
2456
2457 /* We have to add strings in waves or we will not be able to
2458 * get removes to work correctly. We want the string returned
2459 * after the first slurmdb_combine_tres_strings to be put in
2460 * the database.
2461 */
2462 xfree(*out); /* just to make sure */
2463 *out = xstrdup(mod);
2464 slurmdb_combine_tres_strings(out, cur, tres_str_flags);
2465
2466 if (xstrcmp(*out, cur)) {
2467 if (vals) {
2468 /* This logic is here because while the change
2469 * we are doing on the limit is the same for
2470 * each limit the other limits on the
2471 * associations might not be. What this does
2472 * is only change the limit on the association
2473 * given the id. I'm hoping someone in the
2474 * future comes up with a better way to do
2475 * this since this seems like a hack, but it
2476 * does do the job.
2477 */
2478 xstrfmtcat(*vals, ", %s = "
2479 "if (%s=%u, '%s', %s)",
2480 name, assoc ? "id_assoc" : "id", id,
2481 *out, name);
2482 /* xstrfmtcat(*vals, ", %s='%s%s')", */
2483 /* name, */
2484 /* *out[0] ? "," : "", */
2485 /* *out); */
2486 }
2487 if (cur_par)
2488 slurmdb_combine_tres_strings(
2489 out, cur_par, tres_str_flags);
2490 } else
2491 xfree(*out);
2492 }
2493
_get_database_variable(mysql_conn_t * mysql_conn,const char * variable_name,uint64_t * value)2494 static int _get_database_variable(mysql_conn_t *mysql_conn,
2495 const char *variable_name, uint64_t *value)
2496 {
2497 MYSQL_ROW row = NULL;
2498 MYSQL_RES *result = NULL;
2499 char *err_check = NULL;
2500 char *query;
2501
2502 query = xstrdup_printf("show variables like \'%s\';",
2503 variable_name);
2504 result = mysql_db_query_ret(mysql_conn, query, 0);
2505 if (!result) {
2506 error("%s: null result from query `%s`", __func__, query);
2507 xfree(query);
2508 return SLURM_ERROR;
2509 }
2510
2511 if (mysql_num_rows(result) != 1) {
2512 error("%s: invalid results from query `%s`", __func__, query);
2513 xfree(query);
2514 mysql_free_result(result);
2515 return SLURM_ERROR;
2516 }
2517
2518 xfree(query);
2519
2520 row = mysql_fetch_row(result);
2521 *value = (uint64_t) strtoll(row[1], &err_check, 10);
2522
2523 if (*err_check) {
2524 error("%s: error parsing string to int `%s`", __func__, row[1]);
2525 mysql_free_result(result);
2526 return SLURM_ERROR;
2527 }
2528 mysql_free_result(result);
2529
2530 return SLURM_SUCCESS;
2531 }
2532
2533 /*
2534 * MySQL version 5.6.48 and 5.7.30 introduced a regression in the
2535 * implementation of CONCAT() that will lead to incorrect NULL values.
2536 *
2537 * We cannot safely work around this mistake without restructing our stored
2538 * procedures, and thus fatal() here to avoid a segfault.
2539 *
2540 * Test that concat() is working as expected, rather than trying to blacklist
2541 * specific versions.
2542 */
_check_mysql_concat_is_sane(mysql_conn_t * mysql_conn)2543 static void _check_mysql_concat_is_sane(mysql_conn_t *mysql_conn)
2544 {
2545 MYSQL_ROW row = NULL;
2546 MYSQL_RES *result = NULL;
2547 char *query = "select @var := concat('');";
2548 const char *version = mysql_get_server_info(mysql_conn->db_conn);
2549
2550 info("MySQL server version is: %s", version);
2551
2552 result = mysql_db_query_ret(mysql_conn, query, 0);
2553 if (!result)
2554 fatal("%s: null result from query `%s`", __func__, query);
2555
2556 if (mysql_num_rows(result) != 1)
2557 fatal("%s: invalid results from query `%s`", __func__, query);
2558
2559 if (!(row = mysql_fetch_row(result)) || !row[0])
2560 fatal("MySQL concat() function is defective. Please upgrade to a fixed version. See https://bugs.mysql.com/bug.php?id=99485.");
2561
2562 mysql_free_result(result);
2563 }
2564
2565 /*
2566 * Check the values of innodb global database variables, and print
2567 * an error if the values are not at least half the recommendation.
2568 */
_check_database_variables(mysql_conn_t * mysql_conn)2569 static int _check_database_variables(mysql_conn_t *mysql_conn)
2570 {
2571 const char buffer_var[] = "innodb_buffer_pool_size";
2572 const uint64_t buffer_size = 1073741824;
2573 const char logfile_var[] = "innodb_log_file_size";
2574 const uint64_t logfile_size = 67108864;
2575 const char lockwait_var[] = "innodb_lock_wait_timeout";
2576 const uint64_t lockwait_timeout = 900;
2577
2578 uint64_t value;
2579 bool recommended_values = true;
2580 char *error_msg = xstrdup("Database settings not recommended values:");
2581
2582 if (_get_database_variable(mysql_conn, buffer_var, &value))
2583 goto error;
2584 debug2("%s: %"PRIu64, buffer_var, value);
2585 if (value < (buffer_size / 2)) {
2586 recommended_values = false;
2587 xstrfmtcat(error_msg, " %s", buffer_var);
2588 }
2589
2590 if (_get_database_variable(mysql_conn, logfile_var, &value))
2591 goto error;
2592 debug2("%s: %"PRIu64, logfile_var, value);
2593 if (value < (logfile_size / 2)) {
2594 recommended_values = false;
2595 xstrfmtcat(error_msg, " %s", logfile_var);
2596 }
2597
2598 if (_get_database_variable(mysql_conn, lockwait_var, &value))
2599 goto error;
2600 debug2("%s: %"PRIu64, lockwait_var, value);
2601 if (value < (lockwait_timeout / 2)) {
2602 recommended_values = false;
2603 xstrfmtcat(error_msg, " %s", lockwait_var);
2604 }
2605
2606 if (!recommended_values) {
2607 error("%s", error_msg);
2608 }
2609
2610 xfree(error_msg);
2611 return SLURM_SUCCESS;
2612
2613 error:
2614 xfree(error_msg);
2615 return SLURM_ERROR;
2616 }
2617
2618 /*
2619 * init() is called when the plugin is loaded, before any other functions
2620 * are called. Put global initialization here.
2621 */
init(void)2622 extern int init(void)
2623 {
2624 int rc = SLURM_SUCCESS;
2625 mysql_conn_t *mysql_conn = NULL;
2626
2627 debug_flags = slurm_get_debug_flags();
2628
2629 if (slurmdbd_conf->dbd_backup) {
2630 char node_name_short[128];
2631 char node_name_long[128];
2632 if (gethostname(node_name_long, sizeof(node_name_long)))
2633 fatal("getnodename: %m");
2634 if (gethostname_short(node_name_short, sizeof(node_name_short)))
2635 fatal("getnodename_short: %m");
2636 if (!xstrcmp(node_name_short, slurmdbd_conf->dbd_backup) ||
2637 !xstrcmp(node_name_long, slurmdbd_conf->dbd_backup) ||
2638 !xstrcmp(slurmdbd_conf->dbd_backup, "localhost"))
2639 backup_dbd = true;
2640 }
2641
2642 mysql_db_info = create_mysql_db_info(SLURM_MYSQL_PLUGIN_AS);
2643 mysql_db_name = acct_get_db_name();
2644
2645 debug2("mysql_connect() called for db %s", mysql_db_name);
2646 mysql_conn = create_mysql_conn(0, 1, NULL);
2647 while (mysql_db_get_db_connection(
2648 mysql_conn, mysql_db_name, mysql_db_info)
2649 != SLURM_SUCCESS) {
2650 error("The database must be up when starting "
2651 "the MYSQL plugin. Trying again in 5 seconds.");
2652 sleep(5);
2653 }
2654
2655 _check_mysql_concat_is_sane(mysql_conn);
2656 _check_database_variables(mysql_conn);
2657
2658 rc = _as_mysql_acct_check_tables(mysql_conn);
2659
2660 if (rc == SLURM_SUCCESS) {
2661 if (mysql_db_commit(mysql_conn)) {
2662 error("commit failed, meaning %s failed", plugin_name);
2663 rc = SLURM_ERROR;
2664 } else
2665 verbose("%s loaded", plugin_name);
2666 } else {
2667 verbose("%s failed", plugin_name);
2668 if (mysql_db_rollback(mysql_conn))
2669 error("rollback failed");
2670 }
2671
2672 destroy_mysql_conn(mysql_conn);
2673
2674 return rc;
2675 }
2676
fini(void)2677 extern int fini ( void )
2678 {
2679 slurm_mutex_lock(&as_mysql_cluster_list_lock);
2680 FREE_NULL_LIST(as_mysql_cluster_list);
2681 FREE_NULL_LIST(as_mysql_total_cluster_list);
2682 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
2683 slurm_mutex_destroy(&as_mysql_cluster_list_lock);
2684 destroy_mysql_db_info(mysql_db_info);
2685 xfree(mysql_db_name);
2686 xfree(default_qos_str);
2687
2688 mysql_db_cleanup();
2689 return SLURM_SUCCESS;
2690 }
2691
2692 /*
2693 * Get the dimensions of this cluster so we know how to deal with the hostlists.
2694 *
2695 * IN mysql_conn - mysql connection
2696 * IN cluster_name - name of cluster to get dimensions for
2697 * OUT dims - dimenions of cluster
2698 *
2699 * RET return SLURM_SUCCESS on success, SLURM_FAILURE otherwise.
2700 */
get_cluster_dims(mysql_conn_t * mysql_conn,char * cluster_name,int * dims)2701 extern int get_cluster_dims(mysql_conn_t *mysql_conn, char *cluster_name,
2702 int *dims)
2703 {
2704 char *query;
2705 MYSQL_ROW row;
2706 MYSQL_RES *result = NULL;
2707
2708 query = xstrdup_printf("select dimensions, flags from %s where "
2709 "name='%s'",
2710 cluster_table, cluster_name);
2711
2712 debug4("%d(%s:%d) query\n%s",
2713 mysql_conn->conn, THIS_FILE, __LINE__, query);
2714 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
2715 xfree(query);
2716 return SLURM_ERROR;
2717 }
2718 xfree(query);
2719
2720 if (!(row = mysql_fetch_row(result))) {
2721 error("Couldn't get the dimensions of cluster '%s'.",
2722 cluster_name);
2723 mysql_free_result(result);
2724 return SLURM_ERROR;
2725 }
2726
2727 /*
2728 * On a Cray System when dealing with hostlists as we are here this
2729 * always needs to be 1.
2730 */
2731 if (slurm_atoul(row[1]) & CLUSTER_FLAG_CRAY_A)
2732 *dims = 1;
2733 else
2734 *dims = atoi(row[0]);
2735
2736 mysql_free_result(result);
2737
2738 return SLURM_SUCCESS;
2739 }
2740
acct_storage_p_get_connection(const slurm_trigger_callbacks_t * cb,int conn_num,uint16_t * persist_conn_flags,bool rollback,char * cluster_name)2741 extern void *acct_storage_p_get_connection(
2742 const slurm_trigger_callbacks_t *cb,
2743 int conn_num, uint16_t *persist_conn_flags,
2744 bool rollback, char *cluster_name)
2745 {
2746 mysql_conn_t *mysql_conn = NULL;
2747
2748 debug2("acct_storage_p_get_connection: request new connection %d",
2749 rollback);
2750
2751 if (!(mysql_conn = create_mysql_conn(
2752 conn_num, rollback, cluster_name))) {
2753 fatal("couldn't get a mysql_conn");
2754 return NULL; /* Fix CLANG false positive error */
2755 }
2756
2757 errno = SLURM_SUCCESS;
2758 mysql_db_get_db_connection(mysql_conn, mysql_db_name, mysql_db_info);
2759
2760 if (mysql_conn->db_conn)
2761 errno = SLURM_SUCCESS;
2762
2763 return (void *)mysql_conn;
2764 }
2765
acct_storage_p_close_connection(mysql_conn_t ** mysql_conn)2766 extern int acct_storage_p_close_connection(mysql_conn_t **mysql_conn)
2767 {
2768 int rc;
2769
2770 if (!mysql_conn || !(*mysql_conn))
2771 return SLURM_SUCCESS;
2772
2773 acct_storage_p_commit((*mysql_conn), 0);
2774 rc = destroy_mysql_conn(*mysql_conn);
2775 *mysql_conn = NULL;
2776
2777 return rc;
2778 }
2779
acct_storage_p_commit(mysql_conn_t * mysql_conn,bool commit)2780 extern int acct_storage_p_commit(mysql_conn_t *mysql_conn, bool commit)
2781 {
2782 int rc = check_connection(mysql_conn);
2783 List update_list = NULL;
2784
2785 /* always reset this here */
2786 if (mysql_conn)
2787 mysql_conn->cluster_deleted = 0;
2788
2789 if ((rc != SLURM_SUCCESS) && (rc != ESLURM_CLUSTER_DELETED))
2790 return rc;
2791 /*
2792 * We should never get here since check_connection will return
2793 * ESLURM_DB_CONNECTION when !mysql_conn, but Coverity doesn't
2794 * understand that. CID 44841.
2795 */
2796 xassert(mysql_conn);
2797
2798 update_list = list_create(slurmdb_destroy_update_object);
2799 list_transfer(update_list, mysql_conn->update_list);
2800 debug4("got %d commits", list_count(update_list));
2801
2802 if (mysql_conn->rollback) {
2803 if (!commit) {
2804 if (mysql_db_rollback(mysql_conn))
2805 error("rollback failed");
2806 } else {
2807 int rc = SLURM_SUCCESS;
2808 /*
2809 * Handle anything here we were unable to do
2810 * because of rollback issues.
2811 */
2812 if (mysql_conn->pre_commit_query) {
2813 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
2814 DB_DEBUG(mysql_conn->conn, "query\n%s",
2815 mysql_conn->pre_commit_query);
2816 rc = mysql_db_query(
2817 mysql_conn,
2818 mysql_conn->pre_commit_query);
2819 }
2820
2821 if (rc != SLURM_SUCCESS) {
2822 if (mysql_db_rollback(mysql_conn))
2823 error("rollback failed");
2824 } else {
2825 if (mysql_db_commit(mysql_conn))
2826 error("commit failed");
2827 }
2828 }
2829 }
2830
2831 if (commit && list_count(update_list)) {
2832 char *query = NULL;
2833 MYSQL_RES *result = NULL;
2834 MYSQL_ROW row;
2835 ListIterator itr = NULL;
2836 slurmdb_update_object_t *object = NULL;
2837
2838 xstrfmtcat(query, "select control_host, control_port, "
2839 "name, rpc_version, flags "
2840 "from %s where deleted=0 && control_port != 0",
2841 cluster_table);
2842 if (!(result = mysql_db_query_ret(
2843 mysql_conn, query, 0))) {
2844 xfree(query);
2845 goto skip;
2846 }
2847 xfree(query);
2848 while ((row = mysql_fetch_row(result))) {
2849 if (slurm_atoul(row[4]) & CLUSTER_FLAG_EXT)
2850 continue;
2851 (void) slurmdb_send_accounting_update(
2852 update_list,
2853 row[2], row[0],
2854 slurm_atoul(row[1]),
2855 slurm_atoul(row[3]));
2856 }
2857 mysql_free_result(result);
2858 skip:
2859 (void) assoc_mgr_update(update_list, 0);
2860
2861 slurm_mutex_lock(&as_mysql_cluster_list_lock);
2862 itr = list_iterator_create(update_list);
2863 while ((object = list_next(itr))) {
2864 if (!object->objects || !list_count(object->objects))
2865 continue;
2866 /* We only care about clusters removed here. */
2867 switch (object->type) {
2868 case SLURMDB_REMOVE_CLUSTER:
2869 {
2870 ListIterator rem_itr = NULL;
2871 char *rem_cluster = NULL;
2872 rem_itr = list_iterator_create(object->objects);
2873 while ((rem_cluster = list_next(rem_itr))) {
2874 list_delete_all(as_mysql_cluster_list,
2875 slurm_find_char_in_list,
2876 rem_cluster);
2877 }
2878 list_iterator_destroy(rem_itr);
2879 break;
2880 }
2881 default:
2882 break;
2883 }
2884 }
2885 list_iterator_destroy(itr);
2886 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
2887 }
2888 xfree(mysql_conn->pre_commit_query);
2889 FREE_NULL_LIST(update_list);
2890
2891 return SLURM_SUCCESS;
2892 }
2893
acct_storage_p_add_users(mysql_conn_t * mysql_conn,uint32_t uid,List user_list)2894 extern int acct_storage_p_add_users(mysql_conn_t *mysql_conn, uint32_t uid,
2895 List user_list)
2896 {
2897 return as_mysql_add_users(mysql_conn, uid, user_list);
2898 }
2899
acct_storage_p_add_coord(mysql_conn_t * mysql_conn,uint32_t uid,List acct_list,slurmdb_user_cond_t * user_cond)2900 extern int acct_storage_p_add_coord(mysql_conn_t *mysql_conn, uint32_t uid,
2901 List acct_list,
2902 slurmdb_user_cond_t *user_cond)
2903 {
2904 return as_mysql_add_coord(mysql_conn, uid, acct_list, user_cond);
2905 }
2906
acct_storage_p_add_accts(mysql_conn_t * mysql_conn,uint32_t uid,List acct_list)2907 extern int acct_storage_p_add_accts(mysql_conn_t *mysql_conn, uint32_t uid,
2908 List acct_list)
2909 {
2910 return as_mysql_add_accts(mysql_conn, uid, acct_list);
2911 }
2912
acct_storage_p_add_clusters(mysql_conn_t * mysql_conn,uint32_t uid,List cluster_list)2913 extern int acct_storage_p_add_clusters(mysql_conn_t *mysql_conn, uint32_t uid,
2914 List cluster_list)
2915 {
2916 return as_mysql_add_clusters(mysql_conn, uid, cluster_list);
2917 }
2918
acct_storage_p_add_federations(mysql_conn_t * mysql_conn,uint32_t uid,List federation_list)2919 extern int acct_storage_p_add_federations(mysql_conn_t *mysql_conn,
2920 uint32_t uid, List federation_list)
2921 {
2922 return as_mysql_add_federations(mysql_conn, uid, federation_list);
2923 }
2924
acct_storage_p_add_tres(mysql_conn_t * mysql_conn,uint32_t uid,List tres_list_in)2925 extern int acct_storage_p_add_tres(mysql_conn_t *mysql_conn,
2926 uint32_t uid, List tres_list_in)
2927 {
2928 return as_mysql_add_tres(mysql_conn, uid, tres_list_in);
2929 }
2930
acct_storage_p_add_assocs(mysql_conn_t * mysql_conn,uint32_t uid,List assoc_list)2931 extern int acct_storage_p_add_assocs(mysql_conn_t *mysql_conn,
2932 uint32_t uid,
2933 List assoc_list)
2934 {
2935 return as_mysql_add_assocs(mysql_conn, uid, assoc_list);
2936 }
2937
acct_storage_p_add_qos(mysql_conn_t * mysql_conn,uint32_t uid,List qos_list)2938 extern int acct_storage_p_add_qos(mysql_conn_t *mysql_conn, uint32_t uid,
2939 List qos_list)
2940 {
2941 return as_mysql_add_qos(mysql_conn, uid, qos_list);
2942 }
2943
acct_storage_p_add_res(mysql_conn_t * mysql_conn,uint32_t uid,List res_list)2944 extern int acct_storage_p_add_res(mysql_conn_t *mysql_conn, uint32_t uid,
2945 List res_list)
2946 {
2947 return as_mysql_add_res(mysql_conn, uid, res_list);
2948 }
2949
acct_storage_p_add_wckeys(mysql_conn_t * mysql_conn,uint32_t uid,List wckey_list)2950 extern int acct_storage_p_add_wckeys(mysql_conn_t *mysql_conn, uint32_t uid,
2951 List wckey_list)
2952 {
2953 return as_mysql_add_wckeys(mysql_conn, uid, wckey_list);
2954 }
2955
acct_storage_p_add_reservation(mysql_conn_t * mysql_conn,slurmdb_reservation_rec_t * resv)2956 extern int acct_storage_p_add_reservation(mysql_conn_t *mysql_conn,
2957 slurmdb_reservation_rec_t *resv)
2958 {
2959 return as_mysql_add_resv(mysql_conn, resv);
2960 }
2961
acct_storage_p_modify_users(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_user_cond_t * user_cond,slurmdb_user_rec_t * user)2962 extern List acct_storage_p_modify_users(mysql_conn_t *mysql_conn, uint32_t uid,
2963 slurmdb_user_cond_t *user_cond,
2964 slurmdb_user_rec_t *user)
2965 {
2966 return as_mysql_modify_users(mysql_conn, uid, user_cond, user);
2967 }
2968
acct_storage_p_modify_accts(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_account_cond_t * acct_cond,slurmdb_account_rec_t * acct)2969 extern List acct_storage_p_modify_accts(mysql_conn_t *mysql_conn, uint32_t uid,
2970 slurmdb_account_cond_t *acct_cond,
2971 slurmdb_account_rec_t *acct)
2972 {
2973 return as_mysql_modify_accts(mysql_conn, uid, acct_cond, acct);
2974 }
2975
acct_storage_p_modify_clusters(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_cluster_cond_t * cluster_cond,slurmdb_cluster_rec_t * cluster)2976 extern List acct_storage_p_modify_clusters(mysql_conn_t *mysql_conn,
2977 uint32_t uid,
2978 slurmdb_cluster_cond_t *cluster_cond,
2979 slurmdb_cluster_rec_t *cluster)
2980 {
2981 return as_mysql_modify_clusters(mysql_conn, uid, cluster_cond, cluster);
2982 }
2983
acct_storage_p_modify_assocs(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_assoc_cond_t * assoc_cond,slurmdb_assoc_rec_t * assoc)2984 extern List acct_storage_p_modify_assocs(
2985 mysql_conn_t *mysql_conn, uint32_t uid,
2986 slurmdb_assoc_cond_t *assoc_cond,
2987 slurmdb_assoc_rec_t *assoc)
2988 {
2989 return as_mysql_modify_assocs(mysql_conn, uid, assoc_cond, assoc);
2990 }
2991
acct_storage_p_modify_federations(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_federation_cond_t * fed_cond,slurmdb_federation_rec_t * fed)2992 extern List acct_storage_p_modify_federations(
2993 mysql_conn_t *mysql_conn, uint32_t uid,
2994 slurmdb_federation_cond_t *fed_cond,
2995 slurmdb_federation_rec_t *fed)
2996 {
2997 return as_mysql_modify_federations(mysql_conn, uid, fed_cond, fed);
2998 }
2999
acct_storage_p_modify_job(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_job_cond_t * job_cond,slurmdb_job_rec_t * job)3000 extern List acct_storage_p_modify_job(mysql_conn_t *mysql_conn, uint32_t uid,
3001 slurmdb_job_cond_t *job_cond,
3002 slurmdb_job_rec_t *job)
3003 {
3004 return as_mysql_modify_job(mysql_conn, uid, job_cond, job);
3005 }
3006
acct_storage_p_modify_qos(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_qos_cond_t * qos_cond,slurmdb_qos_rec_t * qos)3007 extern List acct_storage_p_modify_qos(mysql_conn_t *mysql_conn, uint32_t uid,
3008 slurmdb_qos_cond_t *qos_cond,
3009 slurmdb_qos_rec_t *qos)
3010 {
3011 return as_mysql_modify_qos(mysql_conn, uid, qos_cond, qos);
3012 }
3013
acct_storage_p_modify_res(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_res_cond_t * res_cond,slurmdb_res_rec_t * res)3014 extern List acct_storage_p_modify_res(mysql_conn_t *mysql_conn,
3015 uint32_t uid,
3016 slurmdb_res_cond_t *res_cond,
3017 slurmdb_res_rec_t *res)
3018 {
3019 return as_mysql_modify_res(mysql_conn, uid, res_cond, res);
3020 }
3021
acct_storage_p_modify_wckeys(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_wckey_cond_t * wckey_cond,slurmdb_wckey_rec_t * wckey)3022 extern List acct_storage_p_modify_wckeys(mysql_conn_t *mysql_conn,
3023 uint32_t uid,
3024 slurmdb_wckey_cond_t *wckey_cond,
3025 slurmdb_wckey_rec_t *wckey)
3026 {
3027 return as_mysql_modify_wckeys(mysql_conn, uid, wckey_cond, wckey);
3028 }
3029
acct_storage_p_modify_reservation(mysql_conn_t * mysql_conn,slurmdb_reservation_rec_t * resv)3030 extern int acct_storage_p_modify_reservation(mysql_conn_t *mysql_conn,
3031 slurmdb_reservation_rec_t *resv)
3032 {
3033 return as_mysql_modify_resv(mysql_conn, resv);
3034 }
3035
acct_storage_p_remove_users(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_user_cond_t * user_cond)3036 extern List acct_storage_p_remove_users(mysql_conn_t *mysql_conn, uint32_t uid,
3037 slurmdb_user_cond_t *user_cond)
3038 {
3039 return as_mysql_remove_users(mysql_conn, uid, user_cond);
3040 }
3041
acct_storage_p_remove_coord(mysql_conn_t * mysql_conn,uint32_t uid,List acct_list,slurmdb_user_cond_t * user_cond)3042 extern List acct_storage_p_remove_coord(mysql_conn_t *mysql_conn, uint32_t uid,
3043 List acct_list,
3044 slurmdb_user_cond_t *user_cond)
3045 {
3046 return as_mysql_remove_coord(mysql_conn, uid, acct_list, user_cond);
3047 }
3048
acct_storage_p_remove_accts(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_account_cond_t * acct_cond)3049 extern List acct_storage_p_remove_accts(mysql_conn_t *mysql_conn, uint32_t uid,
3050 slurmdb_account_cond_t *acct_cond)
3051 {
3052 return as_mysql_remove_accts(mysql_conn, uid, acct_cond);
3053 }
3054
acct_storage_p_remove_clusters(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_cluster_cond_t * cluster_cond)3055 extern List acct_storage_p_remove_clusters(mysql_conn_t *mysql_conn,
3056 uint32_t uid,
3057 slurmdb_cluster_cond_t *cluster_cond)
3058 {
3059 return as_mysql_remove_clusters(mysql_conn, uid, cluster_cond);
3060 }
3061
acct_storage_p_remove_assocs(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_assoc_cond_t * assoc_cond)3062 extern List acct_storage_p_remove_assocs(
3063 mysql_conn_t *mysql_conn, uint32_t uid,
3064 slurmdb_assoc_cond_t *assoc_cond)
3065 {
3066 return as_mysql_remove_assocs(mysql_conn, uid, assoc_cond);
3067 }
3068
acct_storage_p_remove_federations(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_federation_cond_t * fed_cond)3069 extern List acct_storage_p_remove_federations(
3070 mysql_conn_t *mysql_conn, uint32_t uid,
3071 slurmdb_federation_cond_t *fed_cond)
3072 {
3073 return as_mysql_remove_federations(mysql_conn, uid, fed_cond);
3074 }
3075
acct_storage_p_remove_qos(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_qos_cond_t * qos_cond)3076 extern List acct_storage_p_remove_qos(mysql_conn_t *mysql_conn, uint32_t uid,
3077 slurmdb_qos_cond_t *qos_cond)
3078 {
3079 return as_mysql_remove_qos(mysql_conn, uid, qos_cond);
3080 }
3081
acct_storage_p_remove_res(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_res_cond_t * res_cond)3082 extern List acct_storage_p_remove_res(mysql_conn_t *mysql_conn,
3083 uint32_t uid,
3084 slurmdb_res_cond_t *res_cond)
3085 {
3086 return as_mysql_remove_res(mysql_conn, uid, res_cond);
3087 }
3088
acct_storage_p_remove_wckeys(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_wckey_cond_t * wckey_cond)3089 extern List acct_storage_p_remove_wckeys(mysql_conn_t *mysql_conn,
3090 uint32_t uid,
3091 slurmdb_wckey_cond_t *wckey_cond)
3092 {
3093 return as_mysql_remove_wckeys(mysql_conn, uid, wckey_cond);
3094 }
3095
acct_storage_p_remove_reservation(mysql_conn_t * mysql_conn,slurmdb_reservation_rec_t * resv)3096 extern int acct_storage_p_remove_reservation(mysql_conn_t *mysql_conn,
3097 slurmdb_reservation_rec_t *resv)
3098 {
3099 return as_mysql_remove_resv(mysql_conn, resv);
3100 }
3101
acct_storage_p_get_users(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_user_cond_t * user_cond)3102 extern List acct_storage_p_get_users(mysql_conn_t *mysql_conn, uid_t uid,
3103 slurmdb_user_cond_t *user_cond)
3104 {
3105 return as_mysql_get_users(mysql_conn, uid, user_cond);
3106 }
3107
acct_storage_p_get_accts(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_account_cond_t * acct_cond)3108 extern List acct_storage_p_get_accts(mysql_conn_t *mysql_conn, uid_t uid,
3109 slurmdb_account_cond_t *acct_cond)
3110 {
3111 return as_mysql_get_accts(mysql_conn, uid, acct_cond);
3112 }
3113
acct_storage_p_get_clusters(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_cluster_cond_t * cluster_cond)3114 extern List acct_storage_p_get_clusters(mysql_conn_t *mysql_conn, uid_t uid,
3115 slurmdb_cluster_cond_t *cluster_cond)
3116 {
3117 return as_mysql_get_clusters(mysql_conn, uid, cluster_cond);
3118 }
3119
acct_storage_p_get_federations(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_federation_cond_t * fed_cond)3120 extern List acct_storage_p_get_federations(mysql_conn_t *mysql_conn, uid_t uid,
3121 slurmdb_federation_cond_t *fed_cond)
3122 {
3123 return as_mysql_get_federations(mysql_conn, uid, fed_cond);
3124 }
3125
acct_storage_p_get_tres(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_tres_cond_t * tres_cond)3126 extern List acct_storage_p_get_tres(
3127 mysql_conn_t *mysql_conn, uid_t uid,
3128 slurmdb_tres_cond_t *tres_cond)
3129 {
3130 return as_mysql_get_tres(mysql_conn, uid, tres_cond);
3131 }
3132
acct_storage_p_get_assocs(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_assoc_cond_t * assoc_cond)3133 extern List acct_storage_p_get_assocs(
3134 mysql_conn_t *mysql_conn, uid_t uid,
3135 slurmdb_assoc_cond_t *assoc_cond)
3136 {
3137 return as_mysql_get_assocs(mysql_conn, uid, assoc_cond);
3138 }
3139
acct_storage_p_get_events(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_event_cond_t * event_cond)3140 extern List acct_storage_p_get_events(mysql_conn_t *mysql_conn, uint32_t uid,
3141 slurmdb_event_cond_t *event_cond)
3142 {
3143 return as_mysql_get_cluster_events(mysql_conn, uid, event_cond);
3144 }
3145
acct_storage_p_get_problems(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_assoc_cond_t * assoc_cond)3146 extern List acct_storage_p_get_problems(mysql_conn_t *mysql_conn, uint32_t uid,
3147 slurmdb_assoc_cond_t *assoc_cond)
3148 {
3149 List ret_list = NULL;
3150
3151 if (check_connection(mysql_conn) != SLURM_SUCCESS)
3152 return NULL;
3153
3154 if (!is_user_min_admin_level(mysql_conn, uid, SLURMDB_ADMIN_OPERATOR)) {
3155 errno = ESLURM_ACCESS_DENIED;
3156 return NULL;
3157 }
3158
3159 ret_list = list_create(slurmdb_destroy_assoc_rec);
3160
3161 if (as_mysql_acct_no_assocs(mysql_conn, assoc_cond, ret_list)
3162 != SLURM_SUCCESS)
3163 goto end_it;
3164
3165 if (as_mysql_acct_no_users(mysql_conn, assoc_cond, ret_list)
3166 != SLURM_SUCCESS)
3167 goto end_it;
3168
3169 if (as_mysql_user_no_assocs_or_no_uid(mysql_conn, assoc_cond, ret_list)
3170 != SLURM_SUCCESS)
3171 goto end_it;
3172
3173 end_it:
3174
3175 return ret_list;
3176 }
3177
acct_storage_p_get_config(void * db_conn,char * config_name)3178 extern List acct_storage_p_get_config(void *db_conn, char *config_name)
3179 {
3180 return NULL;
3181 }
3182
acct_storage_p_get_qos(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_qos_cond_t * qos_cond)3183 extern List acct_storage_p_get_qos(mysql_conn_t *mysql_conn, uid_t uid,
3184 slurmdb_qos_cond_t *qos_cond)
3185 {
3186 return as_mysql_get_qos(mysql_conn, uid, qos_cond);
3187 }
3188
acct_storage_p_get_res(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_res_cond_t * res_cond)3189 extern List acct_storage_p_get_res(mysql_conn_t *mysql_conn, uid_t uid,
3190 slurmdb_res_cond_t *res_cond)
3191 {
3192 return as_mysql_get_res(mysql_conn, uid, res_cond);
3193 }
3194
acct_storage_p_get_wckeys(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_wckey_cond_t * wckey_cond)3195 extern List acct_storage_p_get_wckeys(mysql_conn_t *mysql_conn, uid_t uid,
3196 slurmdb_wckey_cond_t *wckey_cond)
3197 {
3198 return as_mysql_get_wckeys(mysql_conn, uid, wckey_cond);
3199 }
3200
acct_storage_p_get_reservations(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_reservation_cond_t * resv_cond)3201 extern List acct_storage_p_get_reservations(
3202 mysql_conn_t *mysql_conn, uid_t uid,
3203 slurmdb_reservation_cond_t *resv_cond)
3204 {
3205 return as_mysql_get_resvs(mysql_conn, uid, resv_cond);
3206 }
3207
acct_storage_p_get_txn(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_txn_cond_t * txn_cond)3208 extern List acct_storage_p_get_txn(mysql_conn_t *mysql_conn, uid_t uid,
3209 slurmdb_txn_cond_t *txn_cond)
3210 {
3211 return as_mysql_get_txn(mysql_conn, uid, txn_cond);
3212 }
3213
acct_storage_p_get_usage(mysql_conn_t * mysql_conn,uid_t uid,void * in,slurmdbd_msg_type_t type,time_t start,time_t end)3214 extern int acct_storage_p_get_usage(mysql_conn_t *mysql_conn, uid_t uid,
3215 void *in, slurmdbd_msg_type_t type,
3216 time_t start, time_t end)
3217 {
3218 return as_mysql_get_usage(mysql_conn, uid, in, type, start, end);
3219 }
3220
acct_storage_p_roll_usage(mysql_conn_t * mysql_conn,time_t sent_start,time_t sent_end,uint16_t archive_data,List * rollup_stats_list_in)3221 extern int acct_storage_p_roll_usage(mysql_conn_t *mysql_conn,
3222 time_t sent_start, time_t sent_end,
3223 uint16_t archive_data,
3224 List *rollup_stats_list_in)
3225 {
3226 return as_mysql_roll_usage(mysql_conn, sent_start, sent_end,
3227 archive_data, rollup_stats_list_in);
3228 }
3229
acct_storage_p_fix_runaway_jobs(void * db_conn,uint32_t uid,List jobs)3230 extern int acct_storage_p_fix_runaway_jobs(void *db_conn, uint32_t uid,
3231 List jobs)
3232 {
3233 return as_mysql_fix_runaway_jobs(db_conn, uid, jobs);
3234 }
3235
clusteracct_storage_p_node_down(mysql_conn_t * mysql_conn,node_record_t * node_ptr,time_t event_time,char * reason,uint32_t reason_uid)3236 extern int clusteracct_storage_p_node_down(mysql_conn_t *mysql_conn,
3237 node_record_t *node_ptr,
3238 time_t event_time, char *reason,
3239 uint32_t reason_uid)
3240 {
3241 return as_mysql_node_down(mysql_conn, node_ptr,
3242 event_time, reason, reason_uid);
3243 }
3244
clusteracct_storage_p_node_up(mysql_conn_t * mysql_conn,node_record_t * node_ptr,time_t event_time)3245 extern int clusteracct_storage_p_node_up(mysql_conn_t *mysql_conn,
3246 node_record_t *node_ptr,
3247 time_t event_time)
3248 {
3249 return as_mysql_node_up(mysql_conn, node_ptr, event_time);
3250 }
3251
3252 /* This is only called when not running from the slurmdbd so we can
3253 * assumes some things like rpc_version.
3254 */
clusteracct_storage_p_register_ctld(mysql_conn_t * mysql_conn,uint16_t port)3255 extern int clusteracct_storage_p_register_ctld(mysql_conn_t *mysql_conn,
3256 uint16_t port)
3257 {
3258 return as_mysql_register_ctld(
3259 mysql_conn, mysql_conn->cluster_name, port);
3260 }
3261
clusteracct_storage_p_register_disconn_ctld(mysql_conn_t * mysql_conn,char * control_host)3262 extern uint16_t clusteracct_storage_p_register_disconn_ctld(
3263 mysql_conn_t *mysql_conn, char *control_host)
3264 {
3265 uint16_t control_port = 0;
3266 char *query = NULL;
3267 MYSQL_RES *result = NULL;
3268 MYSQL_ROW row;
3269
3270 if (check_connection(mysql_conn) != SLURM_SUCCESS)
3271 return ESLURM_DB_CONNECTION;
3272
3273 if (!mysql_conn->cluster_name) {
3274 error("%s:%d no cluster name", THIS_FILE, __LINE__);
3275 return control_port;
3276 } else if (!control_host) {
3277 error("%s:%d no control host for cluster %s",
3278 THIS_FILE, __LINE__, mysql_conn->cluster_name);
3279 return control_port;
3280 }
3281
3282 query = xstrdup_printf("select last_port from %s where name='%s';",
3283 cluster_table, mysql_conn->cluster_name);
3284 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
3285 xfree(query);
3286 error("register_disconn_ctld: no result given for cluster %s",
3287 mysql_conn->cluster_name);
3288 return control_port;
3289 }
3290 xfree(query);
3291
3292 if ((row = mysql_fetch_row(result))) {
3293 control_port = slurm_atoul(row[0]);
3294 /* If there is ever a network issue talking to the DBD, and
3295 both the DBD and the ctrl stay up when the ctld goes to
3296 talk to the DBD again it may not re-register (<=2.2).
3297 Since the slurmctld didn't go down we can presume the port
3298 is still the same and just use the last information as the
3299 information we should use and go along our merry way.
3300 */
3301 query = xstrdup_printf(
3302 "update %s set control_host='%s', "
3303 "control_port=%u where name='%s';",
3304 cluster_table, control_host, control_port,
3305 mysql_conn->cluster_name);
3306 if (debug_flags & DEBUG_FLAG_DB_EVENT)
3307 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
3308 if (mysql_db_query(mysql_conn, query) != SLURM_SUCCESS)
3309 control_port = 0;
3310 xfree(query);
3311 }
3312 mysql_free_result(result);
3313
3314 return control_port;
3315 }
3316
clusteracct_storage_p_fini_ctld(mysql_conn_t * mysql_conn,slurmdb_cluster_rec_t * cluster_rec)3317 extern int clusteracct_storage_p_fini_ctld(mysql_conn_t *mysql_conn,
3318 slurmdb_cluster_rec_t *cluster_rec)
3319 {
3320 if (check_connection(mysql_conn) != SLURM_SUCCESS)
3321 return ESLURM_DB_CONNECTION;
3322
3323 if (!cluster_rec || (!mysql_conn->cluster_name && !cluster_rec->name)) {
3324 error("%s:%d no cluster name", THIS_FILE, __LINE__);
3325 return SLURM_ERROR;
3326 }
3327
3328 if (!cluster_rec->name)
3329 cluster_rec->name = mysql_conn->cluster_name;
3330
3331 return as_mysql_fini_ctld(mysql_conn, cluster_rec);
3332 }
3333
clusteracct_storage_p_cluster_tres(mysql_conn_t * mysql_conn,char * cluster_nodes,char * tres_str_in,time_t event_time,uint16_t rpc_version)3334 extern int clusteracct_storage_p_cluster_tres(mysql_conn_t *mysql_conn,
3335 char *cluster_nodes,
3336 char *tres_str_in,
3337 time_t event_time,
3338 uint16_t rpc_version)
3339 {
3340 return as_mysql_cluster_tres(mysql_conn,
3341 cluster_nodes, &tres_str_in,
3342 event_time, rpc_version);
3343 }
3344
3345 /*
3346 * load into the storage the start of a job
3347 */
jobacct_storage_p_job_start(mysql_conn_t * mysql_conn,job_record_t * job_ptr)3348 extern int jobacct_storage_p_job_start(mysql_conn_t *mysql_conn,
3349 job_record_t *job_ptr)
3350 {
3351 return as_mysql_job_start(mysql_conn, job_ptr);
3352 }
3353
3354 /*
3355 * load into the storage the end of a job
3356 */
jobacct_storage_p_job_complete(mysql_conn_t * mysql_conn,job_record_t * job_ptr)3357 extern int jobacct_storage_p_job_complete(mysql_conn_t *mysql_conn,
3358 job_record_t *job_ptr)
3359 {
3360 return as_mysql_job_complete(mysql_conn, job_ptr);
3361 }
3362
3363 /*
3364 * load into the storage the start of a job step
3365 */
jobacct_storage_p_step_start(mysql_conn_t * mysql_conn,step_record_t * step_ptr)3366 extern int jobacct_storage_p_step_start(mysql_conn_t *mysql_conn,
3367 step_record_t *step_ptr)
3368 {
3369 return as_mysql_step_start(mysql_conn, step_ptr);
3370 }
3371
3372 /*
3373 * load into the storage the end of a job step
3374 */
jobacct_storage_p_step_complete(mysql_conn_t * mysql_conn,step_record_t * step_ptr)3375 extern int jobacct_storage_p_step_complete(mysql_conn_t *mysql_conn,
3376 step_record_t *step_ptr)
3377 {
3378 return as_mysql_step_complete(mysql_conn, step_ptr);
3379 }
3380
3381 /*
3382 * load into the storage a suspension of a job
3383 */
jobacct_storage_p_suspend(mysql_conn_t * mysql_conn,job_record_t * job_ptr)3384 extern int jobacct_storage_p_suspend(mysql_conn_t *mysql_conn,
3385 job_record_t *job_ptr)
3386 {
3387 return as_mysql_suspend(mysql_conn, 0, job_ptr);
3388 }
3389
3390 /*
3391 * get info from the storage
3392 * returns List of job_rec_t *
3393 * note List needs to be freed when called
3394 */
jobacct_storage_p_get_jobs_cond(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_job_cond_t * job_cond)3395 extern List jobacct_storage_p_get_jobs_cond(mysql_conn_t *mysql_conn,
3396 uid_t uid,
3397 slurmdb_job_cond_t *job_cond)
3398 {
3399 List job_list = NULL;
3400
3401 if (check_connection(mysql_conn) != SLURM_SUCCESS) {
3402 return NULL;
3403 }
3404 job_list = as_mysql_jobacct_process_get_jobs(mysql_conn, uid, job_cond);
3405
3406 return job_list;
3407 }
3408
3409 /*
3410 * expire old info from the storage
3411 */
jobacct_storage_p_archive(mysql_conn_t * mysql_conn,slurmdb_archive_cond_t * arch_cond)3412 extern int jobacct_storage_p_archive(mysql_conn_t *mysql_conn,
3413 slurmdb_archive_cond_t *arch_cond)
3414 {
3415 int rc;
3416
3417 if (check_connection(mysql_conn) != SLURM_SUCCESS)
3418 return ESLURM_DB_CONNECTION;
3419
3420 /* Make sure only 1 archive is happening at a time. */
3421 slurm_mutex_lock(&usage_rollup_lock);
3422 rc = as_mysql_jobacct_process_archive(mysql_conn, arch_cond);
3423 slurm_mutex_unlock(&usage_rollup_lock);
3424
3425 return rc;
3426 }
3427
3428 /*
3429 * load old info into the storage
3430 */
jobacct_storage_p_archive_load(mysql_conn_t * mysql_conn,slurmdb_archive_rec_t * arch_rec)3431 extern int jobacct_storage_p_archive_load(mysql_conn_t *mysql_conn,
3432 slurmdb_archive_rec_t *arch_rec)
3433 {
3434 if (check_connection(mysql_conn) != SLURM_SUCCESS)
3435 return ESLURM_DB_CONNECTION;
3436
3437 return as_mysql_jobacct_process_archive_load(mysql_conn, arch_rec);
3438 }
3439
acct_storage_p_update_shares_used(mysql_conn_t * mysql_conn,List shares_used)3440 extern int acct_storage_p_update_shares_used(mysql_conn_t *mysql_conn,
3441 List shares_used)
3442 {
3443 /* No plans to have the database hold the used shares */
3444 return SLURM_SUCCESS;
3445 }
3446
acct_storage_p_flush_jobs_on_cluster(mysql_conn_t * mysql_conn,time_t event_time)3447 extern int acct_storage_p_flush_jobs_on_cluster(
3448 mysql_conn_t *mysql_conn, time_t event_time)
3449 {
3450 return as_mysql_flush_jobs_on_cluster(mysql_conn, event_time);
3451 }
3452
acct_storage_p_reconfig(mysql_conn_t * mysql_conn,bool dbd)3453 extern int acct_storage_p_reconfig(mysql_conn_t *mysql_conn, bool dbd)
3454 {
3455 debug_flags = slurm_get_debug_flags();
3456 return SLURM_SUCCESS;
3457 }
3458
acct_storage_p_reset_lft_rgt(mysql_conn_t * mysql_conn,uid_t uid,List cluster_list)3459 extern int acct_storage_p_reset_lft_rgt(mysql_conn_t *mysql_conn, uid_t uid,
3460 List cluster_list)
3461 {
3462 if (check_connection(mysql_conn) != SLURM_SUCCESS)
3463 return ESLURM_DB_CONNECTION;
3464
3465 return as_mysql_reset_lft_rgt(mysql_conn, uid, cluster_list);
3466 }
3467
acct_storage_p_get_stats(void * db_conn,bool dbd)3468 extern int acct_storage_p_get_stats(void *db_conn, bool dbd)
3469 {
3470 return SLURM_SUCCESS;
3471 }
3472
acct_storage_p_clear_stats(void * db_conn,bool dbd)3473 extern int acct_storage_p_clear_stats(void *db_conn, bool dbd)
3474 {
3475 return SLURM_SUCCESS;
3476 }
3477
acct_storage_p_get_data(void * db_conn,acct_storage_info_t dinfo,void * data)3478 extern int acct_storage_p_get_data(void *db_conn, acct_storage_info_t dinfo,
3479 void *data)
3480 {
3481 return SLURM_SUCCESS;
3482 }
3483
acct_storage_p_shutdown(void * db_conn,bool dbd)3484 extern int acct_storage_p_shutdown(void *db_conn, bool dbd)
3485 {
3486 return SLURM_SUCCESS;
3487 }
3488