54
55
#include "error_numbers.h"
56
57
#include "str_util.h"
58
#include "str_replace.h"
57
59
#include "filesys.h"
58
60
#include "strings.h"
61
#include "svn_version.h"
60
63
#include "sched_config.h"
61
64
#include "sched_util.h"
62
65
#include "sched_msgs.h"
66
67
#define LOCKFILE "file_deleter.out"
67
68
#define PIDFILE "file_deleter.pid"
69
#define SLEEP_INTERVAL 5
70
#define DEFAULT_SLEEP_INTERVAL 5
70
71
#define RESULTS_PER_WU 4 // an estimate of redundancy
72
int id_modulus=0, id_remainder=0;
73
int id_modulus=0, id_remainder=0, appid=0;
73
74
bool dont_retry_errors = false;
74
75
bool dont_delete_antiques = false;
75
76
bool dont_delete_batches = false;
76
77
int antique_delay = ANTIQUE_DELAY;
78
int antique_interval = ANTIQUE_INTERVAL;
79
int antique_limit = ANTIQUE_LIMIT;
77
80
bool do_input_files = true;
78
81
bool do_output_files = true;
82
int sleep_interval = DEFAULT_SLEEP_INTERVAL;
82
"file_deleter: deletes files that are no longer needed.\n"
84
"default operation:\n"
85
"1) enumerate N WUs and M results (N,M compile params)\n"
86
" that are ready to file-delete, and try to delete their files\n"
87
"2) if the enums didn't yield anything, sleep for K seconds\n"
89
"4) every 1 hour, enumerate everything in state FILE_DELETE_ERROR\n"
90
" and try to delete it.\n"
91
"5) after 1 hour, and every 24 hours thereafter,\n"
92
" scan for and delete all files in the upload directories\n"
93
" that are older than any WU in the database,\n"
94
" and were created at least one month ago.\n"
95
" This deletes files uploaded by hosts after the WU was deleted.\n"
100
" set debug output level (1/2/3)\n"
102
" handle only WUs with ID mod M == R\n"
104
" instead of sleeping in 2), exit\n"
105
"-dont_retry_error\n"
107
"-dont_delete_antiques\n"
109
"-preserve_result_files\n"
110
" update the DB, but don't delete output files.\n"
112
"-preserve_wu_files\n"
113
" update the DB, but don't delete input files.\n"
115
"-dont_delete_batches\n"
116
" don't delete anything with positive batch number\n"
117
"-input_files_only\n"
118
" delete only input (download) files\n"
119
"-output_files_only\n"
120
" delete only output (upload) files\n"
84
void usage(char *name) {
85
fprintf(stderr, "Deletes files that are no longer needed.\n\n"
86
"Default operation:\n"
87
"1) enumerate N WUs and M results (N,M compile params)\n"
88
" that are ready to file-delete, and try to delete their files\n"
89
"2) if the enums didn't yield anything, sleep for K seconds\n"
91
"4) every 1 hour, enumerate everything in state FILE_DELETE_ERROR\n"
92
" and try to delete it.\n"
93
"5) after 1 hour, and every 24 hours thereafter,\n"
94
" scan for and delete all files in the upload directories\n"
95
" that are older than any WU in the database,\n"
96
" and were created at least one month ago.\n"
97
" This deletes files uploaded by hosts after the WU was deleted.\n\n"
98
"Usage: %s [OPTION]...\n\n"
100
" -d N | --debug_level N set debug output level (1 to 4)\n"
101
" --mod M R handle only WUs with ID mod M == R\n"
102
" --appid ID handle only WUs of a particular app\n"
103
" --one_pass instead of sleeping in 2), exit\n"
104
" --delete_antiques_now do 5) immediately\n"
105
" --dont_retry_error don't do 4)\n"
106
" --dont_delete_antiques don't do 5)\n"
107
" --delete_antiques_interval change the interval between delete antique passes (in seconds, defaults to 24h)\n"
108
" --delete_antiques_limit change the maximum number of files deleted in one delete antique pass (defaults to 50000)\n"
109
" --preserve_result_files update the DB, but don't delete output files.\n"
111
" --preserve_wu_files update the DB, but don't delete input files.\n"
113
" --dont_delete_batches don't delete anything with positive batch number\n"
114
" --input_files_only delete only input (download) files\n"
115
" --output_files_only delete only output (upload) files\n"
116
" [ -h | --help ] shows this help text\n"
117
" [ -v | --version ] shows version information\n",
125
// Given a filename, find its full path in the upload directory hierarchy\n"
126
// Return an error if file isn't there.\n"
122
// Given a filename, find its full path in the upload directory hierarchy
123
// Return ERR_OPENDIR if dir isn't there (possibly recoverable error),
124
// ERR_NOT_FOUND if dir is there but not file
128
126
int get_file_path(
129
127
const char *filename, char* upload_dir, int fanout, char* path
131
dir_hier_path(filename, upload_dir, fanout, path);
129
dir_hier_path(filename, upload_dir, fanout, path, true);
132
130
if (boinc_file_exists(path)) {
135
return ERR_NOT_FOUND;
133
char* p = strrchr(path, '/');
135
if (boinc_file_exists(path)) {
136
return ERR_NOT_FOUND;
296
did_something = true;
299
if (!preserve_wu_files) {
331
if (preserve_wu_files) {
300
334
retval = wu_delete_files(wu);
303
wu.file_delete_state = FILE_DELETE_ERROR;
337
new_state = FILE_DELETE_ERROR;
304
338
log_messages.printf(MSG_CRITICAL,
305
"[WU#%d] update failed: %d\n", wu.id, retval
339
"[WU#%d] file deletion failed: %d\n", wu.id, retval
308
wu.file_delete_state = FILE_DELETE_DONE;
342
new_state = FILE_DELETE_DONE;
310
sprintf(buf, "file_delete_state=%d", wu.file_delete_state);
311
retval= wu.update_field(buf);
344
if (new_state != wu.file_delete_state) {
345
sprintf(buf, "file_delete_state=%d", new_state);
346
retval = wu.update_field(buf);
348
log_messages.printf(MSG_CRITICAL,
349
"[WU#%d] update failed: %d\n", wu.id, retval
352
log_messages.printf(MSG_DEBUG,
353
"[WU#%d] file_delete_state updated\n", wu.id
355
did_something = true;
330
did_something = true;
332
if (!preserve_result_files) {
376
if (preserve_result_files) {
333
379
retval = result_delete_files(result);
336
result.file_delete_state = FILE_DELETE_ERROR;
382
new_state = FILE_DELETE_ERROR;
337
383
log_messages.printf(MSG_CRITICAL,
338
"[RESULT#%d] update failed: %d\n", result.id, retval
384
"[RESULT#%d] file deletion failed: %d\n", result.id, retval
341
result.file_delete_state = FILE_DELETE_DONE;
387
new_state = FILE_DELETE_DONE;
343
sprintf(buf, "file_delete_state=%d", result.file_delete_state);
344
retval= result.update_field(buf);
389
if (new_state != result.file_delete_state) {
390
sprintf(buf, "file_delete_state=%d", new_state);
391
retval = result.update_field(buf);
393
log_messages.printf(MSG_CRITICAL,
394
"[RESULT#%d] update failed: %d\n", result.id, retval
397
log_messages.printf(MSG_DEBUG,
398
"[RESULT#%d] file_delete_state updated\n", result.id
400
did_something = true;
347
405
return did_something;
350
408
struct FILE_RECORD {
352
410
int date_modified;
582
643
bool one_pass = false;
647
check_stop_daemons();
585
check_stop_daemons();
586
650
for (i=1; i<argc; i++) {
587
if (!strcmp(argv[i], "-one_pass")) {
651
if (is_arg(argv[i], "one_pass")) {
589
} else if (!strcmp(argv[i], "-dont_retry_errors")) {
653
} else if (is_arg(argv[i], "dont_retry_errors")) {
590
654
dont_retry_errors = true;
591
} else if (!strcmp(argv[i], "-preserve_wu_files")) {
655
} else if (is_arg(argv[i], "preserve_wu_files")) {
592
656
preserve_wu_files = true;
593
} else if (!strcmp(argv[i], "-preserve_result_files")) {
657
} else if (is_arg(argv[i], "preserve_result_files")) {
594
658
preserve_result_files = true;
595
} else if (!strcmp(argv[i], "-d")) {
596
log_messages.set_debug_level(atoi(argv[++i]));
597
} else if (!strcmp(argv[i], "-mod")) {
659
} else if (is_arg(argv[i], "app")) {
660
strcpy(app.name, argv[++i]);
661
} else if (is_arg(argv[i], "appid")) {
663
log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
667
appid = atoi(argv[i]);
668
} else if (is_arg(argv[i], "d") || is_arg(argv[i], "debug_level")) {
670
log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
674
int dl = atoi(argv[i]);
675
log_messages.set_debug_level(dl);
676
if (dl == 4) g_print_queries = true;
677
} else if (is_arg(argv[i], "mod")) {
678
if (!argv[i+1] || !argv[i+2]) {
679
log_messages.printf(MSG_CRITICAL, "%s requires two arguments\n\n", argv[i]);
598
683
id_modulus = atoi(argv[++i]);
599
684
id_remainder = atoi(argv[++i]);
600
} else if (!strcmp(argv[i], "-dont_delete_antiques")) {
685
} else if (is_arg(argv[i], "dont_delete_antiques")) {
601
686
dont_delete_antiques = true;
602
} else if (!strcmp(argv[i], "-dont_delete_batches")) {
687
} else if (is_arg(argv[i], "delete_antiques_interval")) {
688
antique_interval = atoi(argv[++i]);
689
} else if (is_arg(argv[i], "delete_antiques_limit")) {
690
antique_limit = atoi(argv[++i]);
691
} else if (is_arg(argv[i], "dont_delete_batches")) {
603
692
dont_delete_batches = true;
604
} else if (!strcmp(argv[i], "-delete_antiques_now")) {
693
} else if (is_arg(argv[i], "delete_antiques_now")) {
605
694
antique_delay = 0;
606
} else if (!strcmp(argv[i], "-input_files_only")) {
695
} else if (is_arg(argv[i], "input_files_only")) {
607
696
do_output_files = false;
608
697
dont_delete_antiques = true;
609
} else if (!strcmp(argv[i], "-output_files_only")) {
698
} else if (is_arg(argv[i], "output_files_only")) {
610
699
do_input_files = false;
611
} else if (!strcmp(argv[i], "-help")) {
700
} else if (is_arg(argv[i], "sleep_interval")) {
702
log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
706
sleep_interval = atoi(argv[i]);
707
} else if (is_arg(argv[i], "h") || is_arg(argv[i], "help")) {
710
} else if (is_arg(argv[i], "v") || is_arg(argv[i], "version")) {
711
printf("%s\n", SVN_VERSION);
614
log_messages.printf(MSG_CRITICAL,
615
"Unrecognized arg: %s\n", argv[i]
714
log_messages.printf(MSG_CRITICAL, "unknown command line argument: %s\n\n", argv[i]);