~ubuntu-branches/ubuntu/precise/boinc/precise

« back to all changes in this revision

Viewing changes to sched/db_purge.cpp

Tags: 6.12.8+dfsg-1
* New upstream release.
* Simplified debian/rules

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
// db_purge options
19
19
//
20
20
// purge workunit and result records that are no longer needed.
21
 
// Specifically, purges WUs for which file_delete_state=DONE;
22
 
// this occurs only when it has been assimilated
23
 
// and all results have server_state=OVER.
 
21
// Specifically, purges WUs for which file_delete_state=DONE.
24
22
// Purging a WU means writing it and all its results
25
23
// to XML-format archive files, then deleting it and its results from the DB.
26
24
//
42
40
#include <time.h>
43
41
#include <errno.h>
44
42
 
45
 
using namespace std;
46
 
 
47
43
#include "boinc_db.h"
48
44
#include "util.h"
49
45
#include "filesys.h"
51
47
#include "sched_config.h"
52
48
#include "sched_util.h"
53
49
#include "sched_msgs.h"
 
50
#include "svn_version.h"
54
51
 
55
52
#include "error_numbers.h"
 
53
#include "str_util.h"
56
54
 
57
55
#define WU_FILENAME_PREFIX              "wu_archive"
58
56
#define RESULT_FILENAME_PREFIX          "result_archive"
70
68
FILE *wu_index_stream=NULL;
71
69
FILE *re_index_stream=NULL;
72
70
int time_int=0;
73
 
int min_age_days = 0;
 
71
double min_age_days = 0;
74
72
bool no_archive = false;
 
73
bool dont_delete = false;
 
74
bool daily_dir = false;
75
75
int purged_workunits = 0;
76
76
    // used if limiting the total number of workunits to eliminate
77
77
int max_number_workunits_to_purge = 0;
94
94
    return false;
95
95
}
96
96
 
 
97
void fail(const char* msg) {
 
98
    log_messages.printf(MSG_CRITICAL, msg);
 
99
    exit(1);
 
100
}
 
101
 
97
102
// Open an archive.  Only subtle thing is that if the user has
98
103
// asked for compression, then we popen(2) a pipe to gzip or zip.
99
104
// This does 'in place' compression.
102
107
    char path[256];
103
108
    char command[512];
104
109
 
 
110
    if (daily_dir) {
 
111
        time_t time_time = time_int;
 
112
        char dirname[32];
 
113
        strftime(dirname, sizeof(dirname), "%Y_%m_%d", gmtime(&time_time));
 
114
        strcpy(path, config.project_path("archives/%s",dirname));
 
115
        if (mkdir(path,0775)) {
 
116
            if(errno!=EEXIST) {
 
117
                char errstr[256];
 
118
                sprintf(errstr, "could not create directory '%s': %s\n",
 
119
                path, strerror(errno));
 
120
                fail(errstr);
 
121
            }
 
122
        }
 
123
        strcpy(path,
 
124
            config.project_path(
 
125
                "archives/%s/%s_%d.xml", dirname, filename_prefix, time_int
 
126
            )
 
127
        );
 
128
    } else {
 
129
        strcpy(path,
 
130
            config.project_path("archives/%s_%d.xml", filename_prefix, time_int)
 
131
        );
 
132
    }
105
133
    // append appropriate suffix for file type
106
 
    sprintf(path, "../archives/%s_%d.xml", filename_prefix, time_int);
107
134
    strcat(path, suffix[compression_type]);
108
135
 
109
136
    // and construct appropriate command if needed
119
146
        "Opening archive %s\n", path
120
147
    );
121
148
 
122
 
    // in the case with no compression, just open the file, else open
123
 
    // a pipe to the compression executable.
124
 
    //
 
149
    if (!(f = fopen(path,"w"))) {
 
150
        char buf[256];
 
151
        sprintf(buf, "Can't open archive file %s %s\n",
 
152
            path, errno?strerror(errno):""
 
153
        );
 
154
        fail(buf);
 
155
    }
125
156
    if (compression_type == COMPRESSION_NONE) {   
126
 
        if (!(f = fopen( path,"w"))) {
 
157
        // in the case with no compression, just open the file, else open
 
158
        // a pipe to the compression executable.
 
159
        //
 
160
    } else {
 
161
        fclose(f);
 
162
        f = popen(command,"w");
 
163
        if (!f) {
127
164
            log_messages.printf(MSG_CRITICAL,
128
 
                "Can't open archive file %s %s\n",
129
 
                path, errno?strerror(errno):""
 
165
                "Can't open pipe %s %s\n", 
 
166
                command, errno?strerror(errno):""
130
167
            );
131
 
            exit(3);
 
168
            exit(4);
132
169
        }
133
 
    } else if (!(f = popen(command,"w"))) {
134
 
        log_messages.printf(MSG_CRITICAL,
135
 
            "Can't open pipe %s %s\n", 
136
 
            command, errno?strerror(errno):""
137
 
        );
138
 
        exit(4);
139
170
    }
140
171
 
141
172
    // set buffering to line buffered, since we are outputing XML on a
163
194
    
164
195
    fp = NULL;
165
196
 
 
197
    // reconstruct the filename
 
198
    if (daily_dir) {
 
199
        time_t time_time = time_int;
 
200
        char dirname[32];
 
201
        strftime(dirname, sizeof(dirname), "%Y_%m_%d", gmtime(&time_time));
 
202
        strcpy(path,
 
203
            config.project_path(
 
204
                  "archives/%s/%s_%d.xml", dirname, filename, time_int
 
205
            )
 
206
        );
 
207
    } else {
 
208
        strcpy(path,
 
209
            config.project_path("archives/%s_%d.xml", filename, time_int)
 
210
        );
 
211
    }
166
212
    // append appropriate file type
167
 
    sprintf(path, "../archives/%s_%d.xml", filename, time_int);
168
213
    strcat(path, suffix[compression_type]);
169
214
    
170
215
    log_messages.printf(MSG_NORMAL,
226
271
}
227
272
 
228
273
int archive_result(DB_RESULT& result) {
229
 
    fprintf(re_stream,
 
274
    int n;
 
275
    n = fprintf(re_stream,
230
276
        "<result_archive>\n"
231
277
        "    <id>%d</id>\n",
232
278
        result.id
237
283
    char buf[BLOB_SIZE*6];
238
284
    xml_escape(result.stderr_out, buf, sizeof(buf));
239
285
 
240
 
    fprintf(
 
286
    if (n >= 0) n = fprintf(
241
287
        re_stream,
242
288
        "  <create_time>%d</create_time>\n"
243
289
        "  <workunitid>%d</workunitid>\n"
297
343
        result.mod_time
298
344
    );
299
345
 
300
 
    fprintf(re_stream,
 
346
    if (n >= 0) n = fprintf(re_stream,
301
347
        "</result_archive>\n"
302
348
    );
303
349
 
304
 
    fprintf(re_index_stream,
 
350
    if (n >= 0) n = fprintf(re_index_stream,
305
351
        "%d     %d\n",
306
352
        result.id, time_int
307
353
    );
 
354
    if (n < 0) fail("fprintf() failed\n");
308
355
 
309
356
    return 0;
310
357
}
311
358
 
312
359
int archive_wu(DB_WORKUNIT& wu) {
313
 
    fprintf(wu_stream,
 
360
    int n;
 
361
    n = fprintf(wu_stream,
314
362
        "<workunit_archive>\n"
315
363
        "    <id>%d</id>\n",
316
364
        wu.id
317
365
    );
318
 
    fprintf(wu_stream,
 
366
    if (n >= 0) n = fprintf(wu_stream,
319
367
        "  <create_time>%d</create_time>\n"
320
368
        "  <appid>%d</appid>\n"
321
369
        "  <name>%s</name>\n"
372
420
        wu.mod_time
373
421
    );
374
422
 
375
 
    fprintf(wu_stream,
 
423
    if (n >= 0) n = fprintf(wu_stream,
376
424
        "</workunit_archive>\n"
377
425
    );
378
426
 
379
 
    fprintf(wu_index_stream,
 
427
    if (n >= 0) n = fprintf(wu_index_stream,
380
428
        "%d     %d\n",
381
429
        wu.id, time_int
382
430
    );
383
431
 
 
432
    if (n < 0) fail("fprintf() failed\n");
 
433
 
384
434
    return 0;
385
435
}
386
436
 
400
450
                "Archived result [%d] to a file\n", result.id
401
451
            );
402
452
        }
403
 
        retval = result.delete_from_db();
404
 
        if (retval) return retval;
 
453
        if (!dont_delete) {
 
454
            retval = result.delete_from_db();
 
455
            if (retval) return retval;
 
456
        }
405
457
        log_messages.printf(MSG_DEBUG,
406
458
            "Purged result [%d] from database\n", result.id
407
459
        );
435
487
 
436
488
    if (min_age_days) {
437
489
        char timestamp[15];
438
 
        mysql_timestamp(dtime()-min_age_days*86400, timestamp);
 
490
        mysql_timestamp(dtime()-min_age_days*86400., timestamp);
439
491
        sprintf(buf,
440
492
            "where file_delete_state=%d and mod_time<'%s' limit %d",
441
493
            FILE_DELETE_DONE, timestamp, DB_QUERY_LIMIT
486
538
 
487
539
        // purge workunit from DB
488
540
        //
489
 
        retval= wu.delete_from_db();
490
 
        if (retval) {
491
 
            log_messages.printf(MSG_CRITICAL,
492
 
                "Can't delete workunit [%d] from database:%d\n", wu.id, retval
493
 
            );
494
 
            exit(6);
 
541
        if (!dont_delete) {
 
542
            retval= wu.delete_from_db();
 
543
            if (retval) {
 
544
                log_messages.printf(MSG_CRITICAL,
 
545
                    "Can't delete workunit [%d] from database:%d\n",
 
546
                    wu.id, retval
 
547
                );
 
548
                exit(6);
 
549
            }
495
550
        }
496
551
        log_messages.printf(MSG_DEBUG,
497
552
            "Purged workunit [%d] from database\n", wu.id
540
595
    }
541
596
}
542
597
 
543
 
void usage(char** argv) {
 
598
void usage(char* name) {
544
599
    fprintf(stderr,
545
600
        "Purge workunit and result records that are no longer needed.\n\n"
546
601
        "Usage: %s [options]\n"
547
 
        "    [-d N]               Set verbosity level (1, 2, 3=most verbose)\n"
548
 
        "    [-min_age_days N]    Purge Wus w/ mod time at least N days ago\n"
549
 
        "    [-max N]             Purge at more N WUs\n"
550
 
        "    [-zip]               Compuress output files using zip\n"
551
 
        "    [-gzip]              Compuress output files using gzip\n"
552
 
        "    [-no_archive]        Don't write output files, just purge\n"
553
 
        "    [-max_wu_per_file N] Write at most N WUs per output file\n"
554
 
        "    [-sleep N]           Sleep N sec after DB scan\n"
555
 
        "    [-one_pass]         Make one DB scan, then exit\n",
556
 
        argv[0]
 
602
        "    [-d N | --debug_level N]      Set verbosity level (1 to 4)\n"
 
603
        "    [--min_age_days N]            Purge Wus w/ mod time at least N days ago\n"
 
604
        "    [--max N]                     Purge at more N WUs\n"
 
605
        "    [--zip]                       Compuress output files using zip\n"
 
606
        "    [--gzip]                      uress output files using gzip\n"
 
607
        "    [--no_archive]                Don't write output files, just purge\n"
 
608
        "    [--daily_dir]                 Write archives in a new directory each day\n"
 
609
        "    [--max_wu_per_file N]         Write at most N WUs per output file\n"
 
610
        "    [--sleep N]                   Sleep N sec after DB scan\n"
 
611
        "    [--one_pass]                  Make one DB scan, then exit\n"
 
612
        "    [--dont_delete]               Don't actually delete anything from the DB (for testing only)\n"
 
613
        "    [--h | --help]                Show this help text\n"
 
614
        "    [--v | --version]             Show version information\n",
 
615
        name
557
616
    );
558
 
    exit(0);
559
617
}
560
618
 
561
619
int main(int argc, char** argv) {
566
624
    check_stop_daemons();
567
625
 
568
626
    for (i=1; i<argc; i++) {
569
 
        if (!strcmp(argv[i], "-one_pass")) {
 
627
        if (is_arg(argv[i], "one_pass")) {
570
628
            one_pass = true;
571
 
        } else if (!strcmp(argv[i], "-d")) {
572
 
            log_messages.set_debug_level(atoi(argv[++i]));
573
 
        } else if (!strcmp(argv[i], "-min_age_days")) {
574
 
            min_age_days = atoi(argv[++i]);
575
 
        } else if (!strcmp(argv[i], "-max")) {
576
 
            max_number_workunits_to_purge= atoi(argv[++i]);
577
 
        } else if (!strcmp(argv[i], "-zip")) {
 
629
        } else if (is_arg(argv[i], "dont_delete")) {
 
630
            dont_delete = true;
 
631
        } else if (is_arg(argv[i], "d") || is_arg(argv[i], "debug_level")) {
 
632
            if (!argv[++i]) {
 
633
                log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
 
634
                usage(argv[0]);
 
635
                exit(1);
 
636
            }
 
637
            int dl = atoi(argv[i]);
 
638
            log_messages.set_debug_level(dl);
 
639
            if (dl == 4) g_print_queries = true;
 
640
        } else if (is_arg(argv[i], "min_age_days")) {
 
641
            if (!argv[++i]) {
 
642
                log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
 
643
                usage(argv[0]);
 
644
                exit(1);
 
645
            }
 
646
            min_age_days = atof(argv[i]);
 
647
        } else if (is_arg(argv[i], "max")) {
 
648
            if (!argv[++i]) {
 
649
                log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
 
650
                usage(argv[0]);
 
651
                exit(1);
 
652
            }
 
653
            max_number_workunits_to_purge= atoi(argv[i]);
 
654
        } else if (is_arg(argv[i], "daily_dir")) {
 
655
            daily_dir=true;
 
656
        } else if (is_arg(argv[i], "zip")) {
578
657
            compression_type=COMPRESSION_ZIP;
579
 
        } else if (!strcmp(argv[i], "-gzip")) {
 
658
        } else if (is_arg(argv[i], "gzip")) {
580
659
            compression_type=COMPRESSION_GZIP;
581
 
        } else if (!strcmp(argv[i], "-max_wu_per_file")) {
582
 
            max_wu_per_file = atoi(argv[++i]);
583
 
        } else if (!strcmp(argv[i], "-no_archive")) {
 
660
        } else if (is_arg(argv[i], "max_wu_per_file")) {
 
661
            if(!argv[++i]) {
 
662
                log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
 
663
                usage(argv[0]);
 
664
                exit(1);
 
665
            }
 
666
            max_wu_per_file = atoi(argv[i]);
 
667
        } else if (is_arg(argv[i], "no_archive")) {
584
668
            no_archive = true;
585
 
        } else if (!strcmp(argv[i], "-sleep")) {
586
 
            sleep_sec = atoi(argv[++i]);
 
669
        } else if (is_arg(argv[i], "-sleep")) {
 
670
            if(!argv[++i]) {
 
671
                log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
 
672
                usage(argv[0]);
 
673
                exit(1);
 
674
            }
 
675
            sleep_sec = atoi(argv[i]);
587
676
            if (sleep_sec < 1 || sleep_sec > 86400) {
588
677
                log_messages.printf(MSG_CRITICAL,
589
678
                    "Unreasonable value of sleep interval: %d seconds\n",
590
679
                    sleep_sec
591
680
                );
592
 
                usage(argv);
 
681
                usage(argv[0]);
 
682
                exit(1);
593
683
            }
594
 
        } else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
595
 
            usage(argv);
 
684
        } else if (is_arg(argv[i], "--help") || is_arg(argv[i], "-help") || is_arg(argv[i], "-h")) {
 
685
            usage(argv[0]);
 
686
            return 0;
 
687
        } else if (is_arg(argv[i], "--version") || is_arg(argv[i], "-version")) {
 
688
            printf("%s\n", SVN_VERSION);
 
689
            exit(0);
596
690
        } else {
597
691
            log_messages.printf(MSG_CRITICAL,
598
 
                "Unrecognized arg: %s\n", argv[i]
 
692
                "unknown command line argument: %s\n\n", argv[i]
599
693
            );
600
 
            usage(argv);
 
694
            usage(argv[0]);
 
695
            exit(1);
601
696
        }
602
697
    }
603
698
 
604
 
    retval = config.parse_file("..");
 
699
    retval = config.parse_file();
605
700
    if (retval) {
606
701
        log_messages.printf(MSG_CRITICAL,
607
 
            "Can't parse config file\n"
 
702
            "Can't parse config.xml: %s\n", boincerror(retval)
608
703
        );
609
704
        exit(1);
610
705
    }
619
714
        exit(2);
620
715
    }
621
716
    install_stop_signal_handler();
622
 
    boinc_mkdir("../archives");
 
717
    boinc_mkdir(config.project_path("archives"));
623
718
 
624
719
    // on exit, either via the check_stop_daemons signal handler, or
625
720
    // through a regular call to exit, these functions will be called
632
727
        if (time_to_quit()) {
633
728
            break;
634
729
        }
635
 
        if (!do_pass()) {
636
 
            if (one_pass) break;
 
730
        if (!do_pass() && !one_pass) {
637
731
            log_messages.printf(MSG_NORMAL, "Sleeping....\n");
638
732
            sleep(sleep_sec);
639
733
        }
 
734
        if (one_pass) {
 
735
            break;
 
736
        }
640
737
    }
641
738
 
642
739
    // files and database are closed by exit handler
643
740
    exit(0);
644
741
}
645
742
 
646
 
const char *BOINC_RCSID_0c1c4336f1 = "$Id: db_purge.cpp 16136 2008-10-06 00:18:36Z davea $";
 
743
const char *BOINC_RCSID_0c1c4336f1 = "$Id: db_purge.cpp 22197 2010-08-11 18:52:11Z boincadm $";