1 /*****************************************************************************\
2  *  as_mysql_convert.c - functions dealing with converting from tables in
3  *                    slurm <= 17.02.
4  *****************************************************************************
5  *
6  *  Copyright (C) 2015 SchedMD LLC.
7  *  Written by Danny Auble <da@schedmd.com>
8  *
9  *  This file is part of Slurm, a resource management program.
10  *  For details, see <https://slurm.schedmd.com/>.
11  *  Please also read the included file: DISCLAIMER.
12  *
13  *  Slurm is free software; you can redistribute it and/or modify it under
14  *  the terms of the GNU General Public License as published by the Free
15  *  Software Foundation; either version 2 of the License, or (at your option)
16  *  any later version.
17  *
18  *  In addition, as a special exception, the copyright holders give permission
19  *  to link the code of portions of this program with the OpenSSL library under
20  *  certain conditions as described in each individual source file, and
21  *  distribute linked combinations including the two. You must obey the GNU
22  *  General Public License in all respects for all of the code used other than
23  *  OpenSSL. If you modify file(s) with this exception, you may extend this
24  *  exception to your version of the file(s), but you are not obligated to do
25  *  so. If you do not wish to do so, delete this exception statement from your
26  *  version.  If you delete this exception statement from all source files in
27  *  the program, then also delete it here.
28  *
29  *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
30  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
31  *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
32  *  details.
33  *
34  *  You should have received a copy of the GNU General Public License along
35  *  with Slurm; if not, write to the Free Software Foundation, Inc.,
36  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
37 \*****************************************************************************/
38 
39 #include "as_mysql_convert.h"
40 #include "as_mysql_tres.h"
41 #include "src/common/slurm_jobacct_gather.h"
42 
43 /*
44  * Any time you have to add to an existing convert update this number.
45  * NOTE: 6 was the first version of 18.08.
46  * NOTE: 7 was the first version of 19.05.
47  * NOTE: 8 was the first version of 20.02.
48  */
49 #define CONVERT_VERSION 8
50 
51 typedef struct {
52 	uint64_t count;
53 	uint32_t id;
54 } local_tres_t;
55 
56 static uint32_t db_curr_ver = NO_VAL;
57 
_set_tres_value(char * tres_str,uint64_t * tres_array)58 static void _set_tres_value(char *tres_str, uint64_t *tres_array)
59 {
60 	char *tmp_str = tres_str;
61 	int id;
62 
63 	xassert(tres_array);
64 
65 	if (!tres_str || !tres_str[0])
66 		return;
67 
68 	while (tmp_str) {
69 		id = atoi(tmp_str);
70 		/* 0 isn't a valid tres id */
71 		if (id <= 0) {
72 			error("%s: no id found at %s",
73 			      __func__, tmp_str);
74 			break;
75 		}
76 		if (!(tmp_str = strchr(tmp_str, '='))) {
77 			error("%s: no value found %s", __func__, tres_str);
78 			break;
79 		}
80 
81 		/*
82 		 * The id's of static tres will be one more than the array
83 		 * position.
84 		 */
85 		id--;
86 
87 		if (id >= g_tres_count)
88 			debug2("%s: Unknown tres location %d", __func__, id);
89 		else
90 			tres_array[id] = slurm_atoull(++tmp_str);
91 
92 		if (!(tmp_str = strchr(tmp_str, ',')))
93 			break;
94 
95 		tmp_str++;
96 	}
97 }
98 
_convert_job_table_pre(mysql_conn_t * mysql_conn,char * cluster_name)99 static int _convert_job_table_pre(mysql_conn_t *mysql_conn, char *cluster_name)
100 {
101 	int rc = SLURM_SUCCESS;
102 	char *query = NULL;
103 
104 	if (db_curr_ver < 8) {
105 		/*
106 		 * Change the names pack_job_id and pack_job_offset to be het_*
107 		 */
108 		query = xstrdup_printf(
109 			"alter table \"%s_%s\" "
110 			"change pack_job_id het_job_id int unsigned not null, "
111 			"change pack_job_offset het_job_offset "
112 			"int unsigned not null;",
113 			cluster_name, job_table);
114 	}
115 
116 	if (query) {
117 		if (debug_flags & DEBUG_FLAG_DB_QUERY)
118 			DB_DEBUG(mysql_conn->conn, "query\n%s", query);
119 
120 		rc = mysql_db_query(mysql_conn, query);
121 		xfree(query);
122 		if (rc != SLURM_SUCCESS)
123 			error("%s: Can't convert %s_%s info: %m",
124 			      __func__, cluster_name, job_table);
125 	}
126 
127 	return rc;
128 }
129 
_convert_step_table_pre(mysql_conn_t * mysql_conn,char * cluster_name)130 static int _convert_step_table_pre(mysql_conn_t *mysql_conn, char *cluster_name)
131 {
132 	int rc = SLURM_SUCCESS;
133 	MYSQL_RES *result = NULL;
134 	MYSQL_ROW row;
135 	storage_field_t step_table_fields_17_11[] = {
136 		{ "job_db_inx", "bigint unsigned not null" },
137 		{ "deleted", "tinyint default 0 not null" },
138 		{ "exit_code", "int default 0 not null" },
139 		{ "id_step", "int not null" },
140 		{ "kill_requid", "int default -1 not null" },
141 		{ "nodelist", "text not null" },
142 		{ "nodes_alloc", "int unsigned not null" },
143 		{ "node_inx", "text" },
144 		{ "state", "smallint unsigned not null" },
145 		{ "step_name", "text not null" },
146 		{ "task_cnt", "int unsigned not null" },
147 		{ "task_dist", "smallint default 0 not null" },
148 		{ "time_start", "bigint unsigned default 0 not null" },
149 		{ "time_end", "bigint unsigned default 0 not null" },
150 		{ "time_suspended", "bigint unsigned default 0 not null" },
151 		{ "user_sec", "int unsigned default 0 not null" },
152 		{ "user_usec", "int unsigned default 0 not null" },
153 		{ "sys_sec", "int unsigned default 0 not null" },
154 		{ "sys_usec", "int unsigned default 0 not null" },
155 		{ "max_pages", "int unsigned default 0 not null" },
156 		{ "max_pages_task", "int unsigned default 0 not null" },
157 		{ "max_pages_node", "int unsigned default 0 not null" },
158 		{ "ave_pages", "double unsigned default 0.0 not null" },
159 		{ "max_rss", "bigint unsigned default 0 not null" },
160 		{ "max_rss_task", "int unsigned default 0 not null" },
161 		{ "max_rss_node", "int unsigned default 0 not null" },
162 		{ "ave_rss", "double unsigned default 0.0 not null" },
163 		{ "max_vsize", "bigint unsigned default 0 not null" },
164 		{ "max_vsize_task", "int unsigned default 0 not null" },
165 		{ "max_vsize_node", "int unsigned default 0 not null" },
166 		{ "ave_vsize", "double unsigned default 0.0 not null" },
167 		{ "min_cpu", "int unsigned default 0xfffffffe not null" },
168 		{ "min_cpu_task", "int unsigned default 0 not null" },
169 		{ "min_cpu_node", "int unsigned default 0 not null" },
170 		{ "ave_cpu", "double unsigned default 0.0 not null" },
171 		{ "act_cpufreq", "double unsigned default 0.0 not null" },
172 		{ "consumed_energy", "bigint unsigned default 0 not null" },
173 		{ "req_cpufreq_min", "int unsigned default 0 not null" },
174 		{ "req_cpufreq", "int unsigned default 0 not null" }, /* max */
175 		{ "req_cpufreq_gov", "int unsigned default 0 not null" },
176 		{ "max_disk_read", "double unsigned default 0.0 not null" },
177 		{ "max_disk_read_task", "int unsigned default 0 not null" },
178 		{ "max_disk_read_node", "int unsigned default 0 not null" },
179 		{ "ave_disk_read", "double unsigned default 0.0 not null" },
180 		{ "max_disk_write", "double unsigned default 0.0 not null" },
181 		{ "max_disk_write_task", "int unsigned default 0 not null" },
182 		{ "max_disk_write_node", "int unsigned default 0 not null" },
183 		{ "ave_disk_write", "double unsigned default 0.0 not null" },
184 		{ "tres_alloc", "text not null default ''" },
185 		{ "tres_usage_in_ave", "text not null default ''" },
186 		{ "tres_usage_in_max", "text not null default ''" },
187 		{ "tres_usage_in_max_taskid", "text not null default ''" },
188 		{ "tres_usage_in_max_nodeid", "text not null default ''" },
189 		{ "tres_usage_in_min", "text not null default ''" },
190 		{ "tres_usage_in_min_taskid", "text not null default ''" },
191 		{ "tres_usage_in_min_nodeid", "text not null default ''" },
192 		{ "tres_usage_in_tot", "text not null default ''" },
193 		{ "tres_usage_out_ave", "text not null default ''" },
194 		{ "tres_usage_out_max", "text not null default ''" },
195 		{ "tres_usage_out_max_taskid", "text not null default ''" },
196 		{ "tres_usage_out_max_nodeid", "text not null default ''" },
197 		{ "tres_usage_out_min", "text not null default ''" },
198 		{ "tres_usage_out_min_taskid", "text not null default ''" },
199 		{ "tres_usage_out_min_nodeid", "text not null default ''" },
200 		{ "tres_usage_out_tot", "text not null default ''" },
201 		{ NULL, NULL}
202 	};
203 
204 	char *query = NULL, *tmp = NULL;
205 	char table_name[200];
206 	int i;
207 
208 	if (db_curr_ver < 6) {
209 		char *step_req_inx[] = {
210 			"job_db_inx",
211 			"id_step",
212 			"max_disk_read",
213 			"max_disk_read_task",
214 			"max_disk_read_node",
215 			"ave_disk_read",
216 			"max_disk_write",
217 			"max_disk_write_task",
218 			"max_disk_write_node",
219 			"ave_disk_write",
220 			"max_vsize",
221 			"max_vsize_task",
222 			"max_vsize_node",
223 			"ave_vsize",
224 			"max_rss",
225 			"max_rss_task",
226 			"max_rss_node",
227 			"ave_rss",
228 			"max_pages",
229 			"max_pages_task",
230 			"max_pages_node",
231 			"ave_pages",
232 			"min_cpu",
233 			"min_cpu_task",
234 			"min_cpu_node",
235 			"ave_cpu",
236 			"tres_usage_in_max",
237 			"tres_usage_in_max_taskid",
238 			"tres_usage_in_max_nodeid",
239 			"tres_usage_in_ave",
240 			"tres_usage_out_max",
241 			"tres_usage_out_max_taskid",
242 			"tres_usage_out_max_nodeid",
243 			"tres_usage_out_ave"
244 		};
245 
246 		enum {
247 			STEP_REQ_INX,
248 			STEP_REQ_STEPID,
249 			STEP_REQ_MAX_DISK_READ,
250 			STEP_REQ_MAX_DISK_READ_TASK,
251 			STEP_REQ_MAX_DISK_READ_NODE,
252 			STEP_REQ_AVE_DISK_READ,
253 			STEP_REQ_MAX_DISK_WRITE,
254 			STEP_REQ_MAX_DISK_WRITE_TASK,
255 			STEP_REQ_MAX_DISK_WRITE_NODE,
256 			STEP_REQ_AVE_DISK_WRITE,
257 			STEP_REQ_MAX_VSIZE,
258 			STEP_REQ_MAX_VSIZE_TASK,
259 			STEP_REQ_MAX_VSIZE_NODE,
260 			STEP_REQ_AVE_VSIZE,
261 			STEP_REQ_MAX_RSS,
262 			STEP_REQ_MAX_RSS_TASK,
263 			STEP_REQ_MAX_RSS_NODE,
264 			STEP_REQ_AVE_RSS,
265 			STEP_REQ_MAX_PAGES,
266 			STEP_REQ_MAX_PAGES_TASK,
267 			STEP_REQ_MAX_PAGES_NODE,
268 			STEP_REQ_AVE_PAGES,
269 			STEP_REQ_MIN_CPU,
270 			STEP_REQ_MIN_CPU_TASK,
271 			STEP_REQ_MIN_CPU_NODE,
272 			STEP_REQ_AVE_CPU,
273 			STEP_REQ_TRES_USAGE_IN_MAX,
274 			STEP_REQ_TRES_USAGE_IN_MAX_TASKID,
275 			STEP_REQ_TRES_USAGE_IN_MAX_NODEID,
276 			STEP_REQ_TRES_USAGE_IN_AVE,
277 			STEP_REQ_TRES_USAGE_OUT_MAX,
278 			STEP_REQ_TRES_USAGE_OUT_MAX_TASKID,
279 			STEP_REQ_TRES_USAGE_OUT_MAX_NODEID,
280 			STEP_REQ_TRES_USAGE_OUT_AVE,
281 			STEP_REQ_COUNT
282 		};
283 
284 		jobacctinfo_t *jobacct = NULL;
285 		char *tres_usage_in_ave;
286 		char *tres_usage_in_max;
287 		char *tres_usage_in_max_nodeid;
288 		char *tres_usage_in_max_taskid;
289 		char *tres_usage_out_ave;
290 		char *tres_usage_out_max;
291 		char *tres_usage_out_max_nodeid;
292 		char *tres_usage_out_max_taskid;
293 		int cnt = 0;
294 		uint32_t tmp32;
295 		double tmpd, div = 1024;
296 		char *extra = NULL;
297 		uint32_t flags = TRES_STR_FLAG_SIMPLE |
298 			TRES_STR_FLAG_ALLOW_REAL;
299 
300 		snprintf(table_name, sizeof(table_name), "\"%s_%s\"",
301 			 cluster_name, step_table);
302 		if (mysql_db_create_table(mysql_conn, table_name,
303 					  step_table_fields_17_11,
304 					  ", primary key (job_db_inx, id_step))")
305 		    == SLURM_ERROR)
306 			return SLURM_ERROR;
307 
308 		xstrfmtcat(tmp, "%s", step_req_inx[0]);
309 		for (i = 1; i < STEP_REQ_COUNT; i++) {
310 			xstrfmtcat(tmp, ", %s", step_req_inx[i]);
311 		}
312 
313 		query = xstrdup_printf(
314 			"select %s from \"%s_%s\"",
315 			tmp, cluster_name, step_table);
316 		xfree(tmp);
317 
318 		if (debug_flags & DEBUG_FLAG_DB_QUERY)
319 			DB_DEBUG(mysql_conn->conn, "query\n%s", query);
320 		result = mysql_db_query_ret(mysql_conn, query, 0);
321 		xfree(query);
322 
323 		if (!result)
324 			return SLURM_ERROR;
325 
326 		while ((row = mysql_fetch_row(result))) {
327 			jobacct = jobacctinfo_create(NULL);
328 
329 			/* Just in case something is already there */
330 			_set_tres_value(row[STEP_REQ_TRES_USAGE_IN_MAX],
331 					jobacct->tres_usage_in_max);
332 			_set_tres_value(row[STEP_REQ_TRES_USAGE_IN_MAX_TASKID],
333 					jobacct->tres_usage_in_max_taskid);
334 			_set_tres_value(row[STEP_REQ_TRES_USAGE_IN_MAX_NODEID],
335 					jobacct->tres_usage_in_max_nodeid);
336 			_set_tres_value(row[STEP_REQ_TRES_USAGE_IN_AVE],
337 					jobacct->tres_usage_in_tot);
338 			_set_tres_value(row[STEP_REQ_TRES_USAGE_OUT_MAX],
339 					jobacct->tres_usage_out_max);
340 			_set_tres_value(row[STEP_REQ_TRES_USAGE_OUT_MAX_TASKID],
341 					jobacct->tres_usage_out_max_taskid);
342 			_set_tres_value(row[STEP_REQ_TRES_USAGE_OUT_MAX_NODEID],
343 					jobacct->tres_usage_out_max_nodeid);
344 			_set_tres_value(row[STEP_REQ_TRES_USAGE_OUT_AVE],
345 					jobacct->tres_usage_out_tot);
346 
347 			/* TRES_CPU */
348 			tmp32 = slurm_atoul(row[STEP_REQ_MIN_CPU]);
349 			if (tmp32 != NO_VAL) {
350 				jobacct->tres_usage_in_min[TRES_ARRAY_CPU] =
351 					tmp32;
352 				jobacct->tres_usage_in_min[TRES_ARRAY_CPU] *=
353 					CPU_TIME_ADJ;
354 				jobacct->tres_usage_in_min_nodeid[
355 					TRES_ARRAY_CPU] =
356 					slurm_atoull(
357 						row[STEP_REQ_MIN_CPU_NODE]);
358 				jobacct->tres_usage_in_min_taskid[
359 					TRES_ARRAY_CPU] =
360 					slurm_atoull(
361 						row[STEP_REQ_MIN_CPU_TASK]);
362 				tmpd = atof(row[STEP_REQ_AVE_CPU]);
363 				jobacct->tres_usage_in_tot[TRES_ARRAY_CPU] =
364 					(uint64_t)(tmpd * CPU_TIME_ADJ);
365 			}
366 
367 			/* TRES_MEM */
368 			tmpd = atof(row[STEP_REQ_MAX_RSS]);
369 			if (tmpd) {
370 				jobacct->tres_usage_in_max[TRES_ARRAY_MEM] =
371 					(uint64_t)(tmpd * div);
372 				jobacct->tres_usage_in_max_nodeid[
373 					TRES_ARRAY_MEM] =
374 					slurm_atoull(
375 						row[STEP_REQ_MAX_RSS_NODE]);
376 				jobacct->tres_usage_in_max_taskid[
377 					TRES_ARRAY_MEM] =
378 					slurm_atoull(
379 						row[STEP_REQ_MAX_RSS_TASK]);
380 				tmpd = atof(row[STEP_REQ_AVE_RSS]);
381 				jobacct->tres_usage_in_tot[TRES_ARRAY_MEM] =
382 					(uint64_t)(tmpd * div);
383 			}
384 
385 			/* TRES_VMEM */
386 			tmpd = atof(row[STEP_REQ_MAX_VSIZE]);
387 			if (tmpd) {
388 				jobacct->tres_usage_in_max[TRES_ARRAY_VMEM] =
389 					(uint64_t)(tmpd * div);
390 				jobacct->tres_usage_in_max_nodeid[
391 					TRES_ARRAY_VMEM] =
392 					slurm_atoull(
393 						row[STEP_REQ_MAX_VSIZE_NODE]);
394 				jobacct->tres_usage_in_max_taskid[
395 					TRES_ARRAY_VMEM] =
396 					slurm_atoull(
397 						row[STEP_REQ_MAX_VSIZE_TASK]);
398 				tmpd = atof(row[STEP_REQ_AVE_VSIZE]);
399 				jobacct->tres_usage_in_tot[TRES_ARRAY_VMEM] =
400 					(uint64_t)(tmpd * div);
401 			}
402 
403 			/* TRES_PAGES */
404 			tmp32 = slurm_atoul(row[STEP_REQ_MAX_PAGES]);
405 			if (tmp32) {
406 				jobacct->tres_usage_in_max[TRES_ARRAY_PAGES] =
407 					tmp32;
408 				jobacct->tres_usage_in_max_nodeid[
409 					TRES_ARRAY_PAGES] =
410 					slurm_atoull(
411 						row[STEP_REQ_MAX_PAGES_NODE]);
412 				jobacct->tres_usage_in_max_taskid[
413 					TRES_ARRAY_PAGES] =
414 					slurm_atoull(
415 						row[STEP_REQ_MAX_PAGES_TASK]);
416 				jobacct->tres_usage_in_tot[TRES_ARRAY_PAGES] =
417 					(uint64_t)atof(row[STEP_REQ_AVE_PAGES]);
418 			}
419 
420 			/* TRES_FS_DISK (READ/IN) */
421 			tmpd = atof(row[STEP_REQ_MAX_DISK_READ]);
422 			if (tmpd) {
423 				jobacct->tres_usage_in_max[TRES_ARRAY_FS_DISK] =
424 					(uint64_t)(tmpd * div);
425 				jobacct->tres_usage_in_max_nodeid[
426 					TRES_ARRAY_FS_DISK] =
427 					slurm_atoull(
428 						row[STEP_REQ_MAX_DISK_READ_NODE]);
429 				jobacct->tres_usage_in_max_taskid[
430 					TRES_ARRAY_FS_DISK] =
431 					slurm_atoull(
432 						row[STEP_REQ_MAX_DISK_READ_TASK]);
433 				tmpd = atof(row[STEP_REQ_AVE_DISK_READ]);
434 				jobacct->tres_usage_in_tot[TRES_ARRAY_FS_DISK] =
435 					(uint64_t)(tmpd * div);
436 			}
437 			/* TRES_FS_DISK (WRITE/OUT) */
438 			tmpd = atof(row[STEP_REQ_MAX_DISK_WRITE]);
439 			if (tmpd) {
440 				jobacct->tres_usage_out_max[
441 					TRES_ARRAY_FS_DISK] =
442 					(uint64_t)(tmpd * div);
443 				jobacct->tres_usage_out_max_nodeid[
444 					TRES_ARRAY_FS_DISK] =
445 					slurm_atoull(
446 						row[STEP_REQ_MAX_DISK_READ_NODE]);
447 				jobacct->tres_usage_out_max_taskid[
448 					TRES_ARRAY_FS_DISK] =
449 					slurm_atoull(
450 						row[STEP_REQ_MAX_DISK_READ_TASK]);
451 				tmpd = atof(row[STEP_REQ_AVE_DISK_WRITE]);
452 				jobacct->tres_usage_out_tot[
453 					TRES_ARRAY_FS_DISK] =
454 					(uint64_t)(tmpd * div);
455 			}
456 
457 			tres_usage_in_max = assoc_mgr_make_tres_str_from_array(
458 				jobacct->tres_usage_in_max, flags, true);
459 			tres_usage_in_max_nodeid =
460 				assoc_mgr_make_tres_str_from_array(
461 				jobacct->tres_usage_in_max_nodeid, flags, true);
462 			tres_usage_in_max_taskid =
463 				assoc_mgr_make_tres_str_from_array(
464 				jobacct->tres_usage_in_max_taskid, flags, true);
465 			tres_usage_in_ave = assoc_mgr_make_tres_str_from_array(
466 				jobacct->tres_usage_in_tot, flags, true);
467 			tres_usage_out_max = assoc_mgr_make_tres_str_from_array(
468 				jobacct->tres_usage_out_max, flags, true);
469 			tres_usage_out_max_nodeid =
470 				assoc_mgr_make_tres_str_from_array(
471 				jobacct->tres_usage_out_max_nodeid,
472 				flags, true);
473 			tres_usage_out_max_taskid =
474 				assoc_mgr_make_tres_str_from_array(
475 				jobacct->tres_usage_out_max_taskid,
476 				flags, true);
477 			tres_usage_out_ave = assoc_mgr_make_tres_str_from_array(
478 				jobacct->tres_usage_out_tot, flags, true);
479 
480 			jobacctinfo_destroy(jobacct);
481 
482 			if (tres_usage_in_max) {
483 				xstrfmtcat(extra, "%stres_usage_in_max='%s'",
484 					   extra ? ", " : "",
485 					   tres_usage_in_max);
486 				xfree(tres_usage_in_max);
487 			}
488 
489 			if (tres_usage_in_max_nodeid) {
490 				xstrfmtcat(extra,
491 					   "%stres_usage_in_max_nodeid='%s'",
492 					   extra ? ", " : "",
493 					   tres_usage_in_max_nodeid);
494 				xfree(tres_usage_in_max_nodeid);
495 			}
496 			if (tres_usage_in_max_taskid) {
497 				xstrfmtcat(extra,
498 					   "%stres_usage_in_max_taskid='%s'",
499 					   extra ? ", " : "",
500 					   tres_usage_in_max_taskid);
501 				xfree(tres_usage_in_max_taskid);
502 			}
503 			if (tres_usage_in_ave) {
504 				xstrfmtcat(extra, "%stres_usage_in_ave='%s'",
505 					   extra ? ", " : "",
506 					   tres_usage_in_ave);
507 				xfree(tres_usage_in_ave);
508 			}
509 
510 			if (tres_usage_out_max) {
511 				xstrfmtcat(extra, "%stres_usage_out_max='%s'",
512 					   extra ? ", " : "",
513 					   tres_usage_out_max);
514 				xfree(tres_usage_out_max);
515 			}
516 
517 			if (tres_usage_out_max_nodeid) {
518 				xstrfmtcat(extra,
519 					   "%stres_usage_out_max_nodeid='%s'",
520 					   extra ? ", " : "",
521 					   tres_usage_out_max_nodeid);
522 				xfree(tres_usage_out_max_nodeid);
523 			}
524 			if (tres_usage_out_max_taskid) {
525 				xstrfmtcat(extra,
526 					   "%stres_usage_out_max_taskid='%s'",
527 					   extra ? ", " : "",
528 					   tres_usage_out_max_taskid);
529 				xfree(tres_usage_out_max_taskid);
530 			}
531 			if (tres_usage_out_ave) {
532 				xstrfmtcat(extra, "%stres_usage_out_ave='%s'",
533 					   extra ? ", " : "",
534 					   tres_usage_out_ave);
535 				xfree(tres_usage_out_ave);
536 			}
537 
538 			if (!extra)
539 				continue;
540 
541 			xstrfmtcat(query, "update \"%s_%s\" set %s where job_db_inx=%s and id_step=%s;",
542 				   cluster_name, step_table, extra,
543 				   row[STEP_REQ_INX],
544 				   row[STEP_REQ_STEPID]);
545 			xfree(extra);
546 
547 			if (cnt > 1000) {
548 				cnt = 0;
549 				if (debug_flags & DEBUG_FLAG_DB_QUERY)
550 					DB_DEBUG(mysql_conn->conn, "query\n%s",
551 						 query);
552 				rc = mysql_db_query(mysql_conn, query);
553 				xfree(query);
554 				if (rc != SLURM_SUCCESS) {
555 					error("%s: Can't convert %s_%s info: %m",
556 					      __func__,
557 					      cluster_name, step_table);
558 					break;
559 				}
560 			} else
561 				cnt++;
562 		}
563 		mysql_free_result(result);
564 	}
565 
566 	if (query) {
567 		if (debug_flags & DEBUG_FLAG_DB_QUERY)
568 			DB_DEBUG(mysql_conn->conn, "query\n%s", query);
569 
570 		rc = mysql_db_query(mysql_conn, query);
571 		xfree(query);
572 		if (rc != SLURM_SUCCESS)
573 			error("%s: Can't convert %s_%s info: %m",
574 			      __func__, cluster_name, step_table);
575 	}
576 
577 	return rc;
578 }
579 
_set_db_curr_ver(mysql_conn_t * mysql_conn)580 static int _set_db_curr_ver(mysql_conn_t *mysql_conn)
581 {
582 	char *query;
583 	MYSQL_RES *result = NULL;
584 	MYSQL_ROW row;
585 	int rc = SLURM_SUCCESS;
586 
587 	if (db_curr_ver != NO_VAL)
588 		return SLURM_SUCCESS;
589 
590 	query = xstrdup_printf("select version from %s", convert_version_table);
591 	debug4("%d(%s:%d) query\n%s", mysql_conn->conn,
592 	       THIS_FILE, __LINE__, query);
593 	if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
594 		xfree(query);
595 		return SLURM_ERROR;
596 	}
597 	xfree(query);
598 	row = mysql_fetch_row(result);
599 
600 	if (row) {
601 		db_curr_ver = slurm_atoul(row[0]);
602 		mysql_free_result(result);
603 	} else {
604 		int tmp_ver = 0;
605 		mysql_free_result(result);
606 
607 		/* no valid clusters, just return */
608 		if (as_mysql_total_cluster_list &&
609 		    !list_count(as_mysql_total_cluster_list))
610 			tmp_ver = CONVERT_VERSION;
611 
612 		query = xstrdup_printf("insert into %s (version) values (%d);",
613 				       convert_version_table, tmp_ver);
614 		debug4("(%s:%d) query\n%s", THIS_FILE, __LINE__, query);
615 		rc = mysql_db_query(mysql_conn, query);
616 		xfree(query);
617 		if (rc != SLURM_SUCCESS)
618 			return SLURM_ERROR;
619 		db_curr_ver = tmp_ver;
620 	}
621 
622 	return rc;
623 }
624 
as_mysql_convert_tables_pre_create(mysql_conn_t * mysql_conn)625 extern int as_mysql_convert_tables_pre_create(mysql_conn_t *mysql_conn)
626 {
627 	int rc = SLURM_SUCCESS;
628 	ListIterator itr;
629 	char *cluster_name;
630 
631 	xassert(as_mysql_total_cluster_list);
632 
633 	if ((rc = _set_db_curr_ver(mysql_conn)) != SLURM_SUCCESS)
634 		return rc;
635 
636 	if (db_curr_ver == CONVERT_VERSION) {
637 		debug4("%s: No conversion needed, Horray!", __func__);
638 		return SLURM_SUCCESS;
639 	} else if (backup_dbd) {
640 		/*
641 		 * We do not want to create/check the database if we are the
642 		 * backup (see Bug 3827). This is only handled on the primary.
643 		 *
644 		 * To avoid situations where someone might upgrade the database
645 		 * through the backup we want to fatal so they know what
646 		 * happened instead of potentially starting with the older
647 		 * database.
648 		 */
649 		fatal("Backup DBD can not convert database, please start the primary DBD before starting the backup.");
650 		return SLURM_ERROR;
651 	}
652 
653 	if (db_curr_ver < 6) {
654 		/*
655 		 * We have to fake it here to make things work correctly since
656 		 * the assoc_mgr isn't set up yet.
657 		 */
658 		List tres_list = as_mysql_get_tres(mysql_conn, getuid(), NULL);
659 		assoc_mgr_post_tres_list(tres_list);
660 	}
661 
662 	/* make it up to date */
663 	itr = list_iterator_create(as_mysql_total_cluster_list);
664 	while ((cluster_name = list_next(itr))) {
665 		info("pre-converting job table for %s", cluster_name);
666 		if ((rc = _convert_job_table_pre(mysql_conn, cluster_name)
667 		     != SLURM_SUCCESS))
668 			break;
669 		info("pre-converting step table for %s", cluster_name);
670 		if ((rc = _convert_step_table_pre(mysql_conn, cluster_name)
671 		     != SLURM_SUCCESS))
672 			break;
673 	}
674 	list_iterator_destroy(itr);
675 
676 	if (db_curr_ver < 6)
677 		assoc_mgr_fini(false);
678 
679 	return rc;
680 }
681 
as_mysql_convert_tables_post_create(mysql_conn_t * mysql_conn)682 extern int as_mysql_convert_tables_post_create(mysql_conn_t *mysql_conn)
683 {
684 	int rc = SLURM_SUCCESS;
685 	return rc;
686 }
687 
as_mysql_convert_non_cluster_tables_post_create(mysql_conn_t * mysql_conn)688 extern int as_mysql_convert_non_cluster_tables_post_create(
689 	mysql_conn_t *mysql_conn)
690 {
691 	int rc = SLURM_SUCCESS;
692 
693 	if ((rc = _set_db_curr_ver(mysql_conn)) != SLURM_SUCCESS)
694 		return rc;
695 
696 	if (db_curr_ver == CONVERT_VERSION) {
697 		debug4("%s: No conversion needed, Horray!", __func__);
698 		return SLURM_SUCCESS;
699 	}
700 
701 	if (db_curr_ver < 7) {
702 		/*
703 		 * In 19.05 we changed the name of the TRES bb/cray to be
704 		 * bb/datawarp.
705 		 */
706 		char *query = xstrdup_printf(
707 			"update %s set name='datawarp' where type='bb' and name='cray'",
708 			tres_table);
709 		rc = mysql_db_query(mysql_conn, query);
710 		xfree(query);
711 	}
712 
713 
714 	if (rc == SLURM_SUCCESS) {
715 		char *query = xstrdup_printf(
716 			"update %s set version=%d, mod_time=UNIX_TIMESTAMP()",
717 			convert_version_table, CONVERT_VERSION);
718 
719 		info("Conversion done: success!");
720 
721 		debug4("(%s:%d) query\n%s", THIS_FILE, __LINE__, query);
722 		rc = mysql_db_query(mysql_conn, query);
723 		xfree(query);
724 	}
725 
726 	return rc;
727 }
728