~ubuntu-branches/ubuntu/precise/slurm-llnl/precise

« back to all changes in this revision

Viewing changes to src/plugins/accounting_storage/mysql/as_mysql_usage.c

  • Committer: Bazaar Package Importer
  • Author(s): Gennaro Oliva
  • Date: 2011-04-08 11:21:17 UTC
  • mfrom: (3.3.16 sid)
  • Revision ID: james.westby@ubuntu.com-20110408112117-nfnyq9dtm55hqoaw
Tags: 2.2.4-1
* New upstream releases 
* Cleaning spare file and directories, not belonging to the sources
  generated by the building process and not removed by distclean.
  Added debian/clean with spare files and rm -rf inside debian/rules
  for directories.
* Added new packages libslurm-perl, libslurmdb-perl, slurm-llnl-torque
  (Closes: #575822) thanks to Julien Blache

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************\
 
2
 *  as_mysql_usage.c - functions dealing with usage.
 
3
 *****************************************************************************
 
4
 *
 
5
 *  Copyright (C) 2004-2007 The Regents of the University of California.
 
6
 *  Copyright (C) 2008-2010 Lawrence Livermore National Security.
 
7
 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
 
8
 *  Written by Danny Auble <da@llnl.gov>
 
9
 *
 
10
 *  This file is part of SLURM, a resource management program.
 
11
 *  For details, see <https://computing.llnl.gov/linux/slurm/>.
 
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
 
 
40
#include "as_mysql_usage.h"
 
41
#include "as_mysql_rollup.h"
 
42
 
 
43
time_t global_last_rollup = 0;
 
44
pthread_mutex_t rollup_lock = PTHREAD_MUTEX_INITIALIZER;
 
45
 
 
46
static pthread_mutex_t usage_rollup_lock = PTHREAD_MUTEX_INITIALIZER;
 
47
 
 
48
typedef struct {
 
49
        uint16_t archive_data;
 
50
        char *cluster_name;
 
51
        mysql_conn_t *mysql_conn;
 
52
        int *rc;
 
53
        int *rolledup;
 
54
        pthread_mutex_t *rolledup_lock;
 
55
        pthread_cond_t *rolledup_cond;
 
56
        time_t sent_end;
 
57
        time_t sent_start;
 
58
} local_rollup_t;
 
59
 
 
60
static void *_cluster_rollup_usage(void *arg)
 
61
{
 
62
        local_rollup_t *local_rollup = (local_rollup_t *)arg;
 
63
        int rc = SLURM_SUCCESS;
 
64
        char timer_str[128];
 
65
        mysql_conn_t mysql_conn;
 
66
        MYSQL_RES *result = NULL;
 
67
        MYSQL_ROW row;
 
68
        char *query = NULL;
 
69
        struct tm start_tm;
 
70
        struct tm end_tm;
 
71
        time_t my_time = local_rollup->sent_end;
 
72
        time_t last_hour = local_rollup->sent_start;
 
73
        time_t last_day = local_rollup->sent_start;
 
74
        time_t last_month = local_rollup->sent_start;
 
75
        time_t hour_start;
 
76
        time_t hour_end;
 
77
        time_t day_start;
 
78
        time_t day_end;
 
79
        time_t month_start;
 
80
        time_t month_end;
 
81
        DEF_TIMERS;
 
82
 
 
83
        char *update_req_inx[] = {
 
84
                "hourly_rollup",
 
85
                "daily_rollup",
 
86
                "monthly_rollup"
 
87
        };
 
88
 
 
89
        enum {
 
90
                UPDATE_HOUR,
 
91
                UPDATE_DAY,
 
92
                UPDATE_MONTH,
 
93
                UPDATE_COUNT
 
94
        };
 
95
 
 
96
 
 
97
        memset(&mysql_conn, 0, sizeof(mysql_conn_t));
 
98
        mysql_conn.rollback = 1;
 
99
        mysql_conn.conn = local_rollup->mysql_conn->conn;
 
100
        slurm_mutex_init(&mysql_conn.lock);
 
101
 
 
102
        /* Each thread needs it's own connection we can't use the one
 
103
         * sent from the parent thread. */
 
104
        rc = check_connection(&mysql_conn);
 
105
 
 
106
        if (rc != SLURM_SUCCESS)
 
107
                goto end_it;
 
108
 
 
109
        if (!local_rollup->sent_start) {
 
110
                char *tmp = NULL;
 
111
                int i=0;
 
112
                xstrfmtcat(tmp, "%s", update_req_inx[i]);
 
113
                for(i=1; i<UPDATE_COUNT; i++) {
 
114
                        xstrfmtcat(tmp, ", %s", update_req_inx[i]);
 
115
                }
 
116
                query = xstrdup_printf("select %s from \"%s_%s\"",
 
117
                                       tmp, local_rollup->cluster_name,
 
118
                                       last_ran_table);
 
119
                xfree(tmp);
 
120
 
 
121
                debug4("%d(%s:%d) query\n%s", mysql_conn.conn,
 
122
                       THIS_FILE, __LINE__, query);
 
123
                if (!(result = mysql_db_query_ret(&mysql_conn, query, 0))) {
 
124
                        xfree(query);
 
125
                        rc = SLURM_ERROR;
 
126
                        goto end_it;
 
127
                }
 
128
 
 
129
                xfree(query);
 
130
                row = mysql_fetch_row(result);
 
131
                if (row) {
 
132
                        last_hour = slurm_atoul(row[UPDATE_HOUR]);
 
133
                        last_day = slurm_atoul(row[UPDATE_DAY]);
 
134
                        last_month = slurm_atoul(row[UPDATE_MONTH]);
 
135
                        mysql_free_result(result);
 
136
                } else {
 
137
                        time_t now = time(NULL);
 
138
                        time_t lowest = now;
 
139
 
 
140
                        mysql_free_result(result);
 
141
 
 
142
                        query = xstrdup_printf(
 
143
                                "select time_start from \"%s_%s\" "
 
144
                                "where node_name='' order by "
 
145
                                "time_start asc limit 1;",
 
146
                                local_rollup->cluster_name, event_table);
 
147
                        debug3("%d(%s:%d) query\n%s", mysql_conn.conn,
 
148
                               THIS_FILE, __LINE__, query);
 
149
                        if (!(result = mysql_db_query_ret(
 
150
                                      &mysql_conn, query, 0))) {
 
151
                                xfree(query);
 
152
                                rc = SLURM_ERROR;
 
153
                                goto end_it;
 
154
                        }
 
155
                        xfree(query);
 
156
                        if ((row = mysql_fetch_row(result))) {
 
157
                                time_t check = slurm_atoul(row[0]);
 
158
                                if (check < lowest)
 
159
                                        lowest = check;
 
160
                        }
 
161
                        mysql_free_result(result);
 
162
 
 
163
                        /* If we don't have any events like adding a
 
164
                         * cluster this will not work correctly, so we
 
165
                         * will insert now as a starting point.
 
166
                         */
 
167
 
 
168
                        query = xstrdup_printf(
 
169
                                "insert into \"%s_%s\" "
 
170
                                "(hourly_rollup, daily_rollup, monthly_rollup) "
 
171
                                "values (%ld, %ld, %ld);",
 
172
                                local_rollup->cluster_name, last_ran_table,
 
173
                                lowest, lowest, lowest);
 
174
 
 
175
                        debug3("%d(%s:%d) query\n%s", mysql_conn.conn,
 
176
                               THIS_FILE, __LINE__, query);
 
177
                        rc = mysql_db_query(&mysql_conn, query);
 
178
                        xfree(query);
 
179
                        if (rc != SLURM_SUCCESS) {
 
180
                                rc = SLURM_ERROR;
 
181
                                goto end_it;
 
182
                        }
 
183
 
 
184
                        if (lowest == now) {
 
185
                                debug("Cluster %s not registered, "
 
186
                                      "not doing rollup",
 
187
                                      local_rollup->cluster_name);
 
188
                                rc = SLURM_SUCCESS;
 
189
                                goto end_it;
 
190
                        }
 
191
 
 
192
                        last_hour = last_day = last_month = lowest;
 
193
                }
 
194
        }
 
195
 
 
196
        if (!my_time)
 
197
                my_time = time(NULL);
 
198
 
 
199
        /* test month gap */
 
200
/*      last_hour = 1212299999; */
 
201
/*      last_day = 1212217200; */
 
202
/*      last_month = 1212217200; */
 
203
/*      my_time = 1212307200; */
 
204
 
 
205
/*      last_hour = 1211475599; */
 
206
/*      last_day = 1211475599; */
 
207
/*      last_month = 1211475599; */
 
208
 
 
209
//      last_hour = 1211403599;
 
210
        //      last_hour = 1206946800;
 
211
//      last_day = 1207033199;
 
212
//      last_day = 1197033199;
 
213
//      last_month = 1204358399;
 
214
 
 
215
        if (!localtime_r(&last_hour, &start_tm)) {
 
216
                error("Couldn't get localtime from hour start %ld", last_hour);
 
217
                rc = SLURM_ERROR;
 
218
                goto end_it;
 
219
        }
 
220
 
 
221
        if (!localtime_r(&my_time, &end_tm)) {
 
222
                error("Couldn't get localtime from hour end %ld", my_time);
 
223
                rc = SLURM_ERROR;
 
224
                goto end_it;
 
225
        }
 
226
 
 
227
        /* Below and anywhere in a rollup plugin when dealing with
 
228
         * epoch times we need to set the tm_isdst = -1 so we don't
 
229
         * have to worry about the time changes.  Not setting it to -1
 
230
         * will cause problems in the day and month with the date change.
 
231
         */
 
232
 
 
233
        start_tm.tm_sec = 0;
 
234
        start_tm.tm_min = 0;
 
235
        start_tm.tm_isdst = -1;
 
236
        hour_start = mktime(&start_tm);
 
237
 
 
238
        end_tm.tm_sec = 0;
 
239
        end_tm.tm_min = 0;
 
240
        end_tm.tm_isdst = -1;
 
241
        hour_end = mktime(&end_tm);
 
242
 
 
243
/*      info("hour start %s", ctime(&hour_start)); */
 
244
/*      info("hour end %s", ctime(&hour_end)); */
 
245
/*      info("diff is %d", hour_end-hour_start); */
 
246
 
 
247
        slurm_mutex_lock(&rollup_lock);
 
248
        global_last_rollup = hour_end;
 
249
        slurm_mutex_unlock(&rollup_lock);
 
250
 
 
251
        /* set up the day period */
 
252
        if (!localtime_r(&last_day, &start_tm)) {
 
253
                error("Couldn't get localtime from day %ld", last_day);
 
254
                rc = SLURM_ERROR;
 
255
                goto end_it;
 
256
        }
 
257
 
 
258
        start_tm.tm_sec = 0;
 
259
        start_tm.tm_min = 0;
 
260
        start_tm.tm_hour = 0;
 
261
        start_tm.tm_isdst = -1;
 
262
        day_start = mktime(&start_tm);
 
263
 
 
264
        end_tm.tm_hour = 0;
 
265
        end_tm.tm_isdst = -1;
 
266
        day_end = mktime(&end_tm);
 
267
 
 
268
/*      info("day start %s", ctime(&day_start)); */
 
269
/*      info("day end %s", ctime(&day_end)); */
 
270
/*      info("diff is %d", day_end-day_start); */
 
271
 
 
272
        /* set up the month period */
 
273
        if (!localtime_r(&last_month, &start_tm)) {
 
274
                error("Couldn't get localtime from month %ld", last_month);
 
275
                rc = SLURM_ERROR;
 
276
                goto end_it;
 
277
        }
 
278
 
 
279
        start_tm.tm_sec = 0;
 
280
        start_tm.tm_min = 0;
 
281
        start_tm.tm_hour = 0;
 
282
        start_tm.tm_mday = 1;
 
283
        start_tm.tm_isdst = -1;
 
284
        month_start = mktime(&start_tm);
 
285
 
 
286
        end_tm.tm_sec = 0;
 
287
        end_tm.tm_min = 0;
 
288
        end_tm.tm_hour = 0;
 
289
        end_tm.tm_mday = 1;
 
290
        end_tm.tm_isdst = -1;
 
291
        month_end = mktime(&end_tm);
 
292
 
 
293
/*      info("month start %s", ctime(&month_start)); */
 
294
/*      info("month end %s", ctime(&month_end)); */
 
295
/*      info("diff is %d", month_end-month_start); */
 
296
 
 
297
        if ((hour_end - hour_start) > 0) {
 
298
                START_TIMER;
 
299
                rc = as_mysql_hourly_rollup(&mysql_conn,
 
300
                                            local_rollup->cluster_name,
 
301
                                            hour_start,
 
302
                                            hour_end,
 
303
                                            local_rollup->archive_data);
 
304
                snprintf(timer_str, sizeof(timer_str),
 
305
                         "hourly_rollup for %s", local_rollup->cluster_name);
 
306
                END_TIMER3(timer_str, 5000000);
 
307
                if (rc != SLURM_SUCCESS)
 
308
                        goto end_it;
 
309
        }
 
310
 
 
311
        if ((day_end - day_start) > 0) {
 
312
                START_TIMER;
 
313
                rc = as_mysql_daily_rollup(&mysql_conn,
 
314
                                           local_rollup->cluster_name,
 
315
                                           day_start,
 
316
                                           day_end,
 
317
                                           local_rollup->archive_data);
 
318
                snprintf(timer_str, sizeof(timer_str),
 
319
                         "daily_rollup for %s", local_rollup->cluster_name);
 
320
                END_TIMER3(timer_str, 5000000);
 
321
                if (rc != SLURM_SUCCESS)
 
322
                        goto end_it;
 
323
        }
 
324
 
 
325
        if ((month_end - month_start) > 0) {
 
326
                START_TIMER;
 
327
                rc = as_mysql_monthly_rollup(&mysql_conn,
 
328
                                             local_rollup->cluster_name,
 
329
                                             month_start,
 
330
                                             month_end,
 
331
                                             local_rollup->archive_data);
 
332
                snprintf(timer_str, sizeof(timer_str),
 
333
                         "monthly_rollup for %s", local_rollup->cluster_name);
 
334
                END_TIMER3(timer_str, 5000000);
 
335
                if (rc != SLURM_SUCCESS)
 
336
                        goto end_it;
 
337
        }
 
338
 
 
339
        if ((hour_end - hour_start) > 0) {
 
340
                /* If we have a sent_end do not update the last_run_table */
 
341
                if (!local_rollup->sent_end)
 
342
                        query = xstrdup_printf(
 
343
                                "update \"%s_%s\" set hourly_rollup=%ld",
 
344
                                local_rollup->cluster_name,
 
345
                                last_ran_table, hour_end);
 
346
        } else
 
347
                debug2("No need to roll cluster %s this hour %ld <= %ld",
 
348
                       local_rollup->cluster_name, hour_end, hour_start);
 
349
 
 
350
        if ((day_end - day_start) > 0) {
 
351
                if (query && !local_rollup->sent_end)
 
352
                        xstrfmtcat(query, ", daily_rollup=%ld", day_end);
 
353
                else if (!local_rollup->sent_end)
 
354
                        query = xstrdup_printf(
 
355
                                "update \"%s_%s\" set daily_rollup=%ld",
 
356
                                local_rollup->cluster_name,
 
357
                                last_ran_table, day_end);
 
358
        } else
 
359
                debug2("No need to roll cluster %s this day %ld <= %ld",
 
360
                       local_rollup->cluster_name, day_end, day_start);
 
361
 
 
362
        if ((month_end - month_start) > 0) {
 
363
                if (query && !local_rollup->sent_end)
 
364
                        xstrfmtcat(query, ", monthly_rollup=%ld", month_end);
 
365
                else if (!local_rollup->sent_end)
 
366
                        query = xstrdup_printf(
 
367
                                "update \"%s_%s\" set monthly_rollup=%ld",
 
368
                                local_rollup->cluster_name,
 
369
                                last_ran_table, month_end);
 
370
        } else
 
371
                debug2("No need to roll cluster %s this month %ld <= %ld",
 
372
                       local_rollup->cluster_name, month_end, month_start);
 
373
 
 
374
        if (query) {
 
375
                debug3("%d(%s:%d) query\n%s",
 
376
                       mysql_conn.conn, THIS_FILE, __LINE__, query);
 
377
                rc = mysql_db_query(&mysql_conn, query);
 
378
                xfree(query);
 
379
        }
 
380
end_it:
 
381
        if (rc == SLURM_SUCCESS) {
 
382
                if (mysql_db_commit(&mysql_conn)) {
 
383
                        error("Couldn't commit rollup of cluster %s",
 
384
                              local_rollup->cluster_name);
 
385
                        rc = SLURM_ERROR;
 
386
                }
 
387
        } else {
 
388
                error("Cluster %s rollup failed", local_rollup->cluster_name);
 
389
                if (mysql_db_rollback(&mysql_conn))
 
390
                        error("rollback failed");
 
391
        }
 
392
 
 
393
        mysql_db_close_db_connection(&mysql_conn);
 
394
        slurm_mutex_destroy(&mysql_conn.lock);
 
395
 
 
396
        slurm_mutex_lock(local_rollup->rolledup_lock);
 
397
        (*local_rollup->rolledup)++;
 
398
        if ((rc != SLURM_SUCCESS) && ((*local_rollup->rc) == SLURM_SUCCESS))
 
399
                (*local_rollup->rc) = rc;
 
400
        pthread_cond_signal(local_rollup->rolledup_cond);
 
401
        slurm_mutex_unlock(local_rollup->rolledup_lock);
 
402
        xfree(local_rollup);
 
403
 
 
404
        return NULL;
 
405
}
 
406
 
 
407
 
 
408
static int _get_cluster_usage(mysql_conn_t *mysql_conn, uid_t uid,
 
409
                              slurmdb_cluster_rec_t *cluster_rec,
 
410
                              slurmdbd_msg_type_t type,
 
411
                              time_t start, time_t end)
 
412
{
 
413
        int rc = SLURM_SUCCESS;
 
414
        int i=0;
 
415
        MYSQL_RES *result = NULL;
 
416
        MYSQL_ROW row;
 
417
        char *tmp = NULL;
 
418
        char *my_usage_table = cluster_day_table;
 
419
        char *query = NULL;
 
420
        char *cluster_req_inx[] = {
 
421
                "alloc_cpu_secs",
 
422
                "down_cpu_secs",
 
423
                "pdown_cpu_secs",
 
424
                "idle_cpu_secs",
 
425
                "resv_cpu_secs",
 
426
                "over_cpu_secs",
 
427
                "cpu_count",
 
428
                "time_start"
 
429
        };
 
430
 
 
431
        enum {
 
432
                CLUSTER_ACPU,
 
433
                CLUSTER_DCPU,
 
434
                CLUSTER_PDCPU,
 
435
                CLUSTER_ICPU,
 
436
                CLUSTER_RCPU,
 
437
                CLUSTER_OCPU,
 
438
                CLUSTER_CPU_COUNT,
 
439
                CLUSTER_START,
 
440
                CLUSTER_COUNT
 
441
        };
 
442
 
 
443
        if (!cluster_rec->name || !cluster_rec->name[0]) {
 
444
                error("We need a cluster name to set data for");
 
445
                return SLURM_ERROR;
 
446
        }
 
447
 
 
448
        if (set_usage_information(&my_usage_table, type, &start, &end)
 
449
            != SLURM_SUCCESS) {
 
450
                return SLURM_ERROR;
 
451
        }
 
452
 
 
453
        xfree(tmp);
 
454
        i=0;
 
455
        xstrfmtcat(tmp, "%s", cluster_req_inx[i]);
 
456
        for(i=1; i<CLUSTER_COUNT; i++) {
 
457
                xstrfmtcat(tmp, ", %s", cluster_req_inx[i]);
 
458
        }
 
459
 
 
460
        query = xstrdup_printf(
 
461
                "select %s from \"%s_%s\" where (time_start < %ld "
 
462
                "&& time_start >= %ld)",
 
463
                tmp, cluster_rec->name, my_usage_table, end, start);
 
464
 
 
465
        xfree(tmp);
 
466
        debug4("%d(%s:%d) query\n%s",
 
467
               mysql_conn->conn, THIS_FILE, __LINE__, query);
 
468
        if (!(result = mysql_db_query_ret(
 
469
                      mysql_conn, query, 0))) {
 
470
                xfree(query);
 
471
                return SLURM_ERROR;
 
472
        }
 
473
        xfree(query);
 
474
 
 
475
        if (!cluster_rec->accounting_list)
 
476
                cluster_rec->accounting_list =
 
477
                        list_create(slurmdb_destroy_cluster_accounting_rec);
 
478
 
 
479
        while ((row = mysql_fetch_row(result))) {
 
480
                slurmdb_cluster_accounting_rec_t *accounting_rec =
 
481
                        xmalloc(sizeof(slurmdb_cluster_accounting_rec_t));
 
482
                accounting_rec->alloc_secs = slurm_atoull(row[CLUSTER_ACPU]);
 
483
                accounting_rec->down_secs = slurm_atoull(row[CLUSTER_DCPU]);
 
484
                accounting_rec->pdown_secs = slurm_atoull(row[CLUSTER_PDCPU]);
 
485
                accounting_rec->idle_secs = slurm_atoull(row[CLUSTER_ICPU]);
 
486
                accounting_rec->over_secs = slurm_atoull(row[CLUSTER_OCPU]);
 
487
                accounting_rec->resv_secs = slurm_atoull(row[CLUSTER_RCPU]);
 
488
                accounting_rec->cpu_count = slurm_atoul(row[CLUSTER_CPU_COUNT]);
 
489
                accounting_rec->period_start = slurm_atoul(row[CLUSTER_START]);
 
490
                list_append(cluster_rec->accounting_list, accounting_rec);
 
491
        }
 
492
        mysql_free_result(result);
 
493
 
 
494
        return rc;
 
495
}
 
496
 
 
497
 
 
498
 
 
499
/* checks should already be done before this to see if this is a valid
 
500
   user or not.
 
501
*/
 
502
extern int get_usage_for_list(mysql_conn_t *mysql_conn,
 
503
                              slurmdbd_msg_type_t type, List object_list,
 
504
                              char *cluster_name, time_t start, time_t end)
 
505
{
 
506
        int rc = SLURM_SUCCESS;
 
507
        int i=0;
 
508
        MYSQL_RES *result = NULL;
 
509
        MYSQL_ROW row;
 
510
        char *tmp = NULL;
 
511
        char *my_usage_table = NULL;
 
512
        char *query = NULL;
 
513
        List usage_list = NULL;
 
514
        char *id_str = NULL;
 
515
        ListIterator itr = NULL, u_itr = NULL;
 
516
        void *object = NULL;
 
517
        slurmdb_association_rec_t *assoc = NULL;
 
518
        slurmdb_wckey_rec_t *wckey = NULL;
 
519
        slurmdb_accounting_rec_t *accounting_rec = NULL;
 
520
 
 
521
        /* Since for id in association table we
 
522
           use t3 and in wckey table we use t1 we can't define it here */
 
523
        char **usage_req_inx = NULL;
 
524
 
 
525
        enum {
 
526
                USAGE_ID,
 
527
                USAGE_START,
 
528
                USAGE_ACPU,
 
529
                USAGE_COUNT
 
530
        };
 
531
 
 
532
 
 
533
        if (!object_list) {
 
534
                error("We need an object to set data for getting usage");
 
535
                return SLURM_ERROR;
 
536
        }
 
537
 
 
538
        if (check_connection(mysql_conn) != SLURM_SUCCESS)
 
539
                return ESLURM_DB_CONNECTION;
 
540
 
 
541
        switch (type) {
 
542
        case DBD_GET_ASSOC_USAGE:
 
543
        {
 
544
                char *temp_usage[] = {
 
545
                        "t3.id_assoc",
 
546
                        "t1.time_start",
 
547
                        "t1.alloc_cpu_secs"
 
548
                };
 
549
                usage_req_inx = temp_usage;
 
550
 
 
551
                itr = list_iterator_create(object_list);
 
552
                while ((assoc = list_next(itr))) {
 
553
                        if (id_str)
 
554
                                xstrfmtcat(id_str, " || t3.id_assoc=%d",
 
555
                                           assoc->id);
 
556
                        else
 
557
                                xstrfmtcat(id_str, "t3.id_assoc=%d", assoc->id);
 
558
                }
 
559
                list_iterator_destroy(itr);
 
560
 
 
561
                my_usage_table = assoc_day_table;
 
562
                break;
 
563
        }
 
564
        case DBD_GET_WCKEY_USAGE:
 
565
        {
 
566
                char *temp_usage[] = {
 
567
                        "id_wckey",
 
568
                        "time_start",
 
569
                        "alloc_cpu_secs"
 
570
                };
 
571
                usage_req_inx = temp_usage;
 
572
 
 
573
                itr = list_iterator_create(object_list);
 
574
                while ((wckey = list_next(itr))) {
 
575
                        if (id_str)
 
576
                                xstrfmtcat(id_str, " || id_wckey=%d",
 
577
                                           wckey->id);
 
578
                        else
 
579
                                xstrfmtcat(id_str, "id_wckey=%d", wckey->id);
 
580
                }
 
581
                list_iterator_destroy(itr);
 
582
 
 
583
                my_usage_table = wckey_day_table;
 
584
                break;
 
585
        }
 
586
        default:
 
587
                error("Unknown usage type %d", type);
 
588
                return SLURM_ERROR;
 
589
                break;
 
590
        }
 
591
 
 
592
        if (set_usage_information(&my_usage_table, type, &start, &end)
 
593
            != SLURM_SUCCESS) {
 
594
                xfree(id_str);
 
595
                return SLURM_ERROR;
 
596
        }
 
597
 
 
598
        xfree(tmp);
 
599
        i=0;
 
600
        xstrfmtcat(tmp, "%s", usage_req_inx[i]);
 
601
        for(i=1; i<USAGE_COUNT; i++) {
 
602
                xstrfmtcat(tmp, ", %s", usage_req_inx[i]);
 
603
        }
 
604
        switch (type) {
 
605
        case DBD_GET_ASSOC_USAGE:
 
606
                query = xstrdup_printf(
 
607
                        "select %s from \"%s_%s\" as t1, "
 
608
                        "\"%s_%s\" as t2, \"%s_%s\" as t3 "
 
609
                        "where (t1.time_start < %ld && t1.time_start >= %ld) "
 
610
                        "&& t1.id_assoc=t2.id_assoc && (%s) && "
 
611
                        "t2.lft between t3.lft and t3.rgt "
 
612
                        "order by t3.id_assoc, time_start;",
 
613
                        tmp, cluster_name, my_usage_table,
 
614
                        cluster_name, assoc_table, cluster_name, assoc_table,
 
615
                        end, start, id_str);
 
616
                break;
 
617
        case DBD_GET_WCKEY_USAGE:
 
618
                query = xstrdup_printf(
 
619
                        "select %s from \"%s_%s\" "
 
620
                        "where (time_start < %ld && time_start >= %ld) "
 
621
                        "&& (%s) order by id_wckey, time_start;",
 
622
                        tmp, cluster_name, my_usage_table, end, start, id_str);
 
623
                break;
 
624
        default:
 
625
                error("Unknown usage type %d", type);
 
626
                xfree(id_str);
 
627
                xfree(tmp);
 
628
                return SLURM_ERROR;
 
629
                break;
 
630
        }
 
631
        xfree(id_str);
 
632
        xfree(tmp);
 
633
 
 
634
        debug4("%d(%s:%d) query\n%s",
 
635
               mysql_conn->conn, THIS_FILE, __LINE__, query);
 
636
        if (!(result = mysql_db_query_ret(
 
637
                      mysql_conn, query, 0))) {
 
638
                xfree(query);
 
639
                return SLURM_ERROR;
 
640
        }
 
641
        xfree(query);
 
642
 
 
643
        usage_list = list_create(slurmdb_destroy_accounting_rec);
 
644
 
 
645
        while ((row = mysql_fetch_row(result))) {
 
646
                slurmdb_accounting_rec_t *accounting_rec =
 
647
                        xmalloc(sizeof(slurmdb_accounting_rec_t));
 
648
                accounting_rec->id = slurm_atoul(row[USAGE_ID]);
 
649
                accounting_rec->period_start = slurm_atoul(row[USAGE_START]);
 
650
                accounting_rec->alloc_secs = slurm_atoull(row[USAGE_ACPU]);
 
651
                list_append(usage_list, accounting_rec);
 
652
        }
 
653
        mysql_free_result(result);
 
654
 
 
655
        u_itr = list_iterator_create(usage_list);
 
656
        itr = list_iterator_create(object_list);
 
657
        while ((object = list_next(itr))) {
 
658
                int found = 0;
 
659
                int id = 0;
 
660
                List acct_list = NULL;
 
661
 
 
662
                switch (type) {
 
663
                case DBD_GET_ASSOC_USAGE:
 
664
                        assoc = (slurmdb_association_rec_t *)object;
 
665
                        if (!assoc->accounting_list)
 
666
                                assoc->accounting_list = list_create(
 
667
                                        slurmdb_destroy_accounting_rec);
 
668
                        acct_list = assoc->accounting_list;
 
669
                        id = assoc->id;
 
670
                        break;
 
671
                case DBD_GET_WCKEY_USAGE:
 
672
                        wckey = (slurmdb_wckey_rec_t *)object;
 
673
                        if (!wckey->accounting_list)
 
674
                                wckey->accounting_list = list_create(
 
675
                                        slurmdb_destroy_accounting_rec);
 
676
                        acct_list = wckey->accounting_list;
 
677
                        id = wckey->id;
 
678
                        break;
 
679
                default:
 
680
                        continue;
 
681
                        break;
 
682
                }
 
683
 
 
684
                while ((accounting_rec = list_next(u_itr))) {
 
685
                        if (id == accounting_rec->id) {
 
686
                                list_append(acct_list, accounting_rec);
 
687
                                list_remove(u_itr);
 
688
                                found = 1;
 
689
                        } else if (found) {
 
690
                                /* here we know the
 
691
                                   list is in id order so
 
692
                                   if the next record
 
693
                                   isn't the correct id
 
694
                                   just continue since
 
695
                                   there is no reason to
 
696
                                   go through the rest of
 
697
                                   the list when we know
 
698
                                   it isn't going to be
 
699
                                   the correct id */
 
700
                                break;
 
701
                        }
 
702
                }
 
703
                list_iterator_reset(u_itr);
 
704
        }
 
705
        list_iterator_destroy(itr);
 
706
        list_iterator_destroy(u_itr);
 
707
 
 
708
        if (list_count(usage_list))
 
709
                error("we have %d records not added "
 
710
                      "to the association list",
 
711
                      list_count(usage_list));
 
712
        list_destroy(usage_list);
 
713
 
 
714
 
 
715
        return rc;
 
716
}
 
717
 
 
718
extern int as_mysql_get_usage(mysql_conn_t *mysql_conn, uid_t uid,
 
719
                              void *in, slurmdbd_msg_type_t type,
 
720
                              time_t start, time_t end)
 
721
{
 
722
        int rc = SLURM_SUCCESS;
 
723
        int i=0, is_admin=1;
 
724
        MYSQL_RES *result = NULL;
 
725
        MYSQL_ROW row;
 
726
        char *tmp = NULL;
 
727
        char *my_usage_table = NULL;
 
728
        slurmdb_association_rec_t *slurmdb_assoc = in;
 
729
        slurmdb_wckey_rec_t *slurmdb_wckey = in;
 
730
        char *query = NULL;
 
731
        char *username = NULL;
 
732
        uint16_t private_data = 0;
 
733
        slurmdb_user_rec_t user;
 
734
        List *my_list;
 
735
        uint32_t id = NO_VAL;
 
736
        char *cluster_name = NULL;
 
737
        char **usage_req_inx = NULL;
 
738
 
 
739
        enum {
 
740
                USAGE_ID,
 
741
                USAGE_START,
 
742
                USAGE_ACPU,
 
743
                USAGE_COUNT
 
744
        };
 
745
 
 
746
        switch (type) {
 
747
        case DBD_GET_ASSOC_USAGE:
 
748
        {
 
749
                char *temp_usage[] = {
 
750
                        "t3.id_assoc",
 
751
                        "t1.time_start",
 
752
                        "t1.alloc_cpu_secs"
 
753
                };
 
754
                usage_req_inx = temp_usage;
 
755
 
 
756
                id = slurmdb_assoc->id;
 
757
                cluster_name = slurmdb_assoc->cluster;
 
758
                username = slurmdb_assoc->user;
 
759
                my_list = &slurmdb_assoc->accounting_list;
 
760
                my_usage_table = assoc_day_table;
 
761
                break;
 
762
        }
 
763
        case DBD_GET_WCKEY_USAGE:
 
764
        {
 
765
                char *temp_usage[] = {
 
766
                        "id_wckey",
 
767
                        "time_start",
 
768
                        "alloc_cpu_secs"
 
769
                };
 
770
                usage_req_inx = temp_usage;
 
771
 
 
772
                id = slurmdb_wckey->id;
 
773
                cluster_name = slurmdb_wckey->cluster;
 
774
                username = slurmdb_wckey->user;
 
775
                my_list = &slurmdb_wckey->accounting_list;
 
776
                my_usage_table = wckey_day_table;
 
777
                break;
 
778
        }
 
779
        case DBD_GET_CLUSTER_USAGE:
 
780
        {
 
781
                return _get_cluster_usage(mysql_conn, uid, in,
 
782
                                          type, start, end);
 
783
                break;
 
784
        }
 
785
        default:
 
786
                error("Unknown usage type %d", type);
 
787
                return SLURM_ERROR;
 
788
                break;
 
789
        }
 
790
 
 
791
        if (!id) {
 
792
                error("We need an id to set data for getting usage");
 
793
                return SLURM_ERROR;
 
794
        } else if (!cluster_name) {
 
795
                error("We need a cluster_name to set data for getting usage");
 
796
                return SLURM_ERROR;
 
797
        }
 
798
 
 
799
        if (check_connection(mysql_conn) != SLURM_SUCCESS)
 
800
                return ESLURM_DB_CONNECTION;
 
801
 
 
802
        memset(&user, 0, sizeof(slurmdb_user_rec_t));
 
803
        user.uid = uid;
 
804
 
 
805
        private_data = slurm_get_private_data();
 
806
        if (private_data & PRIVATE_DATA_USAGE) {
 
807
                if (!(is_admin = is_user_min_admin_level(
 
808
                              mysql_conn, uid, SLURMDB_ADMIN_OPERATOR))) {
 
809
                        ListIterator itr = NULL;
 
810
                        slurmdb_coord_rec_t *coord = NULL;
 
811
 
 
812
                        if (username && !strcmp(slurmdb_assoc->user, user.name))
 
813
                                goto is_user;
 
814
 
 
815
                        if (type != DBD_GET_ASSOC_USAGE)
 
816
                                goto bad_user;
 
817
 
 
818
                        if (!slurmdb_assoc->acct) {
 
819
                                debug("No account name given "
 
820
                                      "in association.");
 
821
                                goto bad_user;
 
822
                        }
 
823
 
 
824
                        if (!is_user_any_coord(mysql_conn, &user)) {
 
825
                                debug4("This user is not a coordinator.");
 
826
                                goto bad_user;
 
827
                        }
 
828
 
 
829
                        /* Existance of user.coord_accts is checked in
 
830
                           is_user_any_coord.
 
831
                        */
 
832
                        itr = list_iterator_create(user.coord_accts);
 
833
                        while ((coord = list_next(itr)))
 
834
                                if (!strcasecmp(coord->name,
 
835
                                                slurmdb_assoc->acct))
 
836
                                        break;
 
837
                        list_iterator_destroy(itr);
 
838
 
 
839
                        if (coord)
 
840
                                goto is_user;
 
841
 
 
842
                bad_user:
 
843
                        errno = ESLURM_ACCESS_DENIED;
 
844
                        return SLURM_ERROR;
 
845
                }
 
846
        }
 
847
is_user:
 
848
 
 
849
        if (set_usage_information(&my_usage_table, type, &start, &end)
 
850
            != SLURM_SUCCESS) {
 
851
                return SLURM_ERROR;
 
852
        }
 
853
 
 
854
        xfree(tmp);
 
855
        i=0;
 
856
        xstrfmtcat(tmp, "%s", usage_req_inx[i]);
 
857
        for(i=1; i<USAGE_COUNT; i++) {
 
858
                xstrfmtcat(tmp, ", %s", usage_req_inx[i]);
 
859
        }
 
860
        switch (type) {
 
861
        case DBD_GET_ASSOC_USAGE:
 
862
                query = xstrdup_printf(
 
863
                        "select %s from \"%s_%s\" as t1, "
 
864
                        "\"%s_%s\" as t2, \"%s_%s\" as t3 "
 
865
                        "where (t1.time_start < %ld && t1.time_start >= %ld) "
 
866
                        "&& t1.id_assoc=t2.id_assoc && t3.id_assoc=%d && "
 
867
                        "t2.lft between t3.lft and t3.rgt "
 
868
                        "order by t3.id_assoc, time_start;",
 
869
                        tmp, cluster_name, my_usage_table,
 
870
                        cluster_name, cluster_name, assoc_table, assoc_table,
 
871
                        end, start, id);
 
872
                break;
 
873
        case DBD_GET_WCKEY_USAGE:
 
874
                query = xstrdup_printf(
 
875
                        "select %s from \"%s_%s\" "
 
876
                        "where (time_start < %ld && time_start >= %ld) "
 
877
                        "&& id_wckey=%d order by id_wckey, time_start;",
 
878
                        tmp, cluster_name, my_usage_table, end, start, id);
 
879
                break;
 
880
        default:
 
881
                error("Unknown usage type %d", type);
 
882
                return SLURM_ERROR;
 
883
                break;
 
884
        }
 
885
 
 
886
        xfree(tmp);
 
887
        debug4("%d(%s:%d) query\n%s",
 
888
               mysql_conn->conn, THIS_FILE, __LINE__, query);
 
889
        if (!(result = mysql_db_query_ret(
 
890
                      mysql_conn, query, 0))) {
 
891
                xfree(query);
 
892
                return SLURM_ERROR;
 
893
        }
 
894
        xfree(query);
 
895
 
 
896
        if (!(*my_list))
 
897
                (*my_list) = list_create(slurmdb_destroy_accounting_rec);
 
898
 
 
899
        while ((row = mysql_fetch_row(result))) {
 
900
                slurmdb_accounting_rec_t *accounting_rec =
 
901
                        xmalloc(sizeof(slurmdb_accounting_rec_t));
 
902
                accounting_rec->id = slurm_atoul(row[USAGE_ID]);
 
903
                accounting_rec->period_start = slurm_atoul(row[USAGE_START]);
 
904
                accounting_rec->alloc_secs = slurm_atoull(row[USAGE_ACPU]);
 
905
                list_append((*my_list), accounting_rec);
 
906
        }
 
907
        mysql_free_result(result);
 
908
 
 
909
        return rc;
 
910
}
 
911
 
 
912
extern int as_mysql_roll_usage(mysql_conn_t *mysql_conn,
 
913
                               time_t sent_start, time_t sent_end,
 
914
                               uint16_t archive_data)
 
915
{
 
916
        int rc = SLURM_SUCCESS;
 
917
        int rolledup = 0;
 
918
        char *cluster_name = NULL;
 
919
        ListIterator itr;
 
920
        pthread_mutex_t rolledup_lock = PTHREAD_MUTEX_INITIALIZER;
 
921
        pthread_cond_t rolledup_cond;
 
922
        //DEF_TIMERS;
 
923
 
 
924
        if (check_connection(mysql_conn) != SLURM_SUCCESS)
 
925
                return ESLURM_DB_CONNECTION;
 
926
 
 
927
        slurm_mutex_lock(&usage_rollup_lock);
 
928
 
 
929
        slurm_mutex_init(&rolledup_lock);
 
930
        pthread_cond_init(&rolledup_cond, NULL);
 
931
 
 
932
        //START_TIMER;
 
933
        slurm_mutex_lock(&as_mysql_cluster_list_lock);
 
934
        itr = list_iterator_create(as_mysql_cluster_list);
 
935
        while ((cluster_name = list_next(itr))) {
 
936
                /* pthread_t rollup_tid; */
 
937
                /* pthread_attr_t rollup_attr; */
 
938
                local_rollup_t *local_rollup = xmalloc(sizeof(local_rollup_t));
 
939
 
 
940
                local_rollup->archive_data = archive_data;
 
941
                local_rollup->cluster_name = cluster_name;
 
942
 
 
943
                local_rollup->mysql_conn = mysql_conn;
 
944
                local_rollup->rc = &rc;
 
945
                local_rollup->rolledup = &rolledup;
 
946
                local_rollup->rolledup_lock = &rolledup_lock;
 
947
                local_rollup->rolledup_cond = &rolledup_cond;
 
948
 
 
949
                local_rollup->sent_end = sent_end;
 
950
                local_rollup->sent_start = sent_start;
 
951
 
 
952
                /* _cluster_rollup_usage is responsible for freeing
 
953
                   this local_rollup */
 
954
                _cluster_rollup_usage(local_rollup);
 
955
                /* It turns out doing this with threads only buys a
 
956
                   very small victory, and can skew the timings.  So
 
957
                   just doing them one after the other isn't too bad.
 
958
                   If you really want to do this in threads you can
 
959
                   just uncomment this, and comment the call above.
 
960
                */
 
961
                /* slurm_attr_init(&rollup_attr); */
 
962
                /* if (pthread_create(&rollup_tid, &rollup_attr, */
 
963
                /*                 _cluster_rollup_usage, */
 
964
                /*                 (void *)local_rollup)) */
 
965
                /*      fatal("pthread_create: %m"); */
 
966
                /* slurm_attr_destroy(&rollup_attr); */
 
967
        }
 
968
        slurm_mutex_lock(&rolledup_lock);
 
969
        list_iterator_destroy(itr);
 
970
        slurm_mutex_unlock(&as_mysql_cluster_list_lock);
 
971
 
 
972
        while (rolledup < list_count(as_mysql_cluster_list)) {
 
973
                pthread_cond_wait(&rolledup_cond, &rolledup_lock);
 
974
                debug2("Got %d rolled up", rolledup);
 
975
        }
 
976
        slurm_mutex_unlock(&rolledup_lock);
 
977
        debug2("Everything rolled up");
 
978
        slurm_mutex_destroy(&rolledup_lock);
 
979
        pthread_cond_destroy(&rolledup_cond);
 
980
        /* END_TIMER; */
 
981
        /* info("total time was %s", TIME_STR); */
 
982
 
 
983
        slurm_mutex_unlock(&usage_rollup_lock);
 
984
 
 
985
        return rc;
 
986
}