2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: driver.c 6512 2007-05-24 17:00:24Z ian $
29 * controlling process for the Amanda backup system
33 * XXX possibly modify tape queue to be cognizant of how much room is left on
34 * tape. Probably not effective though, should do this in planner.
47 #include "server_util.h"
48 #include "timestamp.h"
50 #define driver_debug(i, ...) do { \
51 if ((i) <= debug_driver) { \
52 dbprintf(__VA_ARGS__); \
56 #define hold_debug(i, ...) do { \
57 if ((i) <= debug_holding) { \
58 dbprintf(__VA_ARGS__); \
62 static disklist_t waitq; // dle waiting estimate result
63 static disklist_t runq; // dle waiting to be dumped to holding disk
64 static disklist_t directq; // dle waiting to be dumped directly to tape
65 static disklist_t tapeq; // dle on holding disk waiting to be written
67 static disklist_t roomq; // dle waiting for more space on holding disk
68 static int pending_aborts;
69 static disk_t *taper_disk;
70 static int degraded_mode;
71 static off_t reserved_space;
72 static off_t total_disksize;
73 static char *dumper_program;
74 static char *chunker_program;
75 static int inparallel;
76 static int nodump = 0;
77 static off_t tape_length = (off_t)0;
78 static off_t tape_left = (off_t)0;
79 static int current_tape = 0;
80 static int conf_taperalgo;
81 static int conf_runtapes;
82 static time_t sleep_time;
83 static int idle_reason;
84 static char *driver_timestamp;
85 static char *hd_driver_timestamp;
86 static am_host_t *flushhost = NULL;
87 static int need_degraded=0;
88 static holdalloc_t *holdalloc;
89 static int num_holdalloc;
90 static event_handle_t *dumpers_ev_time = NULL;
91 static event_handle_t *schedule_ev_read = NULL;
92 static int conf_flush_threshold_dumped;
93 static int conf_flush_threshold_scheduled;
94 static int conf_taperflush;
95 static off_t flush_threshold_dumped;
96 static off_t flush_threshold_scheduled;
97 static off_t taperflush;
98 static int schedule_done; // 1 if we don't wait for a
99 // schedule from the planner
100 static int force_flush; // All dump are terminated, we
101 // must now respect taper_flush
103 static int wait_children(int count);
104 static void wait_for_children(void);
105 static void allocate_bandwidth(netif_t *ip, unsigned long kps);
106 static int assign_holdingdisk(assignedhd_t **holdp, disk_t *diskp);
107 static void adjust_diskspace(disk_t *diskp, cmd_t cmd);
108 static void delete_diskspace(disk_t *diskp);
109 static assignedhd_t **build_diskspace(char *destname);
110 static int client_constrained(disk_t *dp);
111 static void deallocate_bandwidth(netif_t *ip, unsigned long kps);
112 static void dump_schedule(disklist_t *qp, char *str);
113 static void dump_to_tape(disk_t *dp);
114 static assignedhd_t **find_diskspace(off_t size, int *cur_idle,
115 assignedhd_t *preferred);
116 static unsigned long free_kps(netif_t *ip);
117 static off_t free_space(void);
118 static void dumper_chunker_result(disk_t *dp);
119 static void dumper_taper_result(disk_t *dp);
120 static void file_taper_result(disk_t *dp);
121 static void handle_dumper_result(void *);
122 static void handle_chunker_result(void *);
123 static void handle_dumpers_time(void *);
124 static void handle_taper_result(void *);
126 static void holdingdisk_state(char *time_str);
127 static dumper_t *idle_dumper(void);
128 static void interface_state(char *time_str);
129 static int queue_length(disklist_t q);
130 static disklist_t read_flush(void);
131 static void read_schedule(void *cookie);
132 static void short_dump_state(void);
133 static void startaflush(void);
134 static void start_degraded_mode(disklist_t *queuep);
135 static void start_some_dumps(disklist_t *rq);
136 static void continue_port_dumps(void);
137 static void update_failed_dump(disk_t *);
140 TAPE_ACTION_NO_ACTION = 0,
141 TAPE_ACTION_NEW_TAPE = (1 << 0),
142 TAPE_ACTION_NO_NEW_TAPE = (1 << 1),
143 TAPE_ACTION_START_A_FLUSH = (1 << 2)
146 static TapeAction tape_action(char **why_no_new_tape);
148 static const char *idle_strings[] = {
151 #define IDLE_NO_DUMPERS 1
153 #define IDLE_START_WAIT 2
155 #define IDLE_NO_HOLD 3
157 #define IDLE_CLIENT_CONSTRAINED 4
158 T_("client-constrained"),
159 #define IDLE_NO_BANDWIDTH 5
161 #define IDLE_NO_DISKSPACE 6
175 struct fs_usage fsusage;
178 unsigned long reserve = 100;
182 char **result_argv = NULL;
189 config_overrides_t *cfg_ovr = NULL;
190 char *cfg_opt = NULL;
191 holdalloc_t *ha, *ha_last;
194 * Configure program for internationalization:
195 * 1) Only set the message locale for now.
196 * 2) Set textdomain for all amanda related programs to "amanda"
197 * We don't want to be forced to support dozens of message catalogs.
199 setlocale(LC_MESSAGES, "C");
200 textdomain("amanda");
204 setvbuf(stdout, (char *)NULL, (int)_IOLBF, 0);
205 setvbuf(stderr, (char *)NULL, (int)_IOLBF, 0);
209 dbopen(DBG_SUBDIR_SERVER);
211 atexit(wait_for_children);
213 /* Don't die when child closes pipe */
214 signal(SIGPIPE, SIG_IGN);
216 add_amanda_log_handler(amanda_log_stderr);
217 add_amanda_log_handler(amanda_log_trace_log);
221 cfg_ovr = extract_commandline_config_overrides(&argc, &argv);
225 set_config_overrides(cfg_ovr);
226 config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
228 conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
229 read_diskfile(conf_diskfile, &origq);
230 disable_skip_disk(&origq);
231 amfree(conf_diskfile);
233 if (config_errors(NULL) >= CFGERR_WARNINGS) {
234 config_print_errors();
235 if (config_errors(NULL) >= CFGERR_ERRORS) {
236 g_critical(_("errors processing config file"));
240 log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
241 g_printf(_("%s: pid %ld executable %s version %s\n"),
242 get_pname(), (long) getpid(), argv[0], VERSION);
245 if(strncmp(argv[2], "nodump", 6) == 0) {
250 safe_cd(); /* do this *after* config_init */
252 check_running_as(RUNNING_AS_DUMPUSER);
254 dbrename(get_config_name(), DBG_SUBDIR_SERVER);
256 amfree(driver_timestamp);
257 /* read timestamp from stdin */
258 while ((line = agets(stdin)) != NULL) {
263 if ( line == NULL ) {
264 error(_("Did not get DATE line from planner"));
267 driver_timestamp = alloc(15);
268 strncpy(driver_timestamp, &line[5], 14);
269 driver_timestamp[14] = '\0';
271 log_add(L_START,_("date %s"), driver_timestamp);
273 gethostname(hostname, SIZEOF(hostname));
274 log_add(L_STATS,_("hostname %s"), hostname);
276 /* check that we don't do many dump in a day and usetimestamps is off */
277 if(strlen(driver_timestamp) == 8) {
279 char *conf_logdir = getconf_str(CNF_LOGDIR);
280 char *logfile = vstralloc(conf_logdir, "/log.",
281 driver_timestamp, ".0", NULL);
282 char *oldlogfile = vstralloc(conf_logdir, "/oldlog/log.",
283 driver_timestamp, ".0", NULL);
284 if(access(logfile, F_OK) == 0 || access(oldlogfile, F_OK) == 0) {
285 log_add(L_WARNING, _("WARNING: This is not the first amdump run today. Enable the usetimestamps option in the configuration file if you want to run amdump more than once per calendar day."));
290 hd_driver_timestamp = get_timestamp_from_time(0);
293 hd_driver_timestamp = stralloc(driver_timestamp);
296 taper_program = vstralloc(amlibexecdir, "/", "taper", NULL);
297 dumper_program = vstralloc(amlibexecdir, "/", "dumper", NULL);
298 chunker_program = vstralloc(amlibexecdir, "/", "chunker", NULL);
300 conf_taperalgo = getconf_taperalgo(CNF_TAPERALGO);
301 conf_tapetype = getconf_str(CNF_TAPETYPE);
302 conf_runtapes = getconf_int(CNF_RUNTAPES);
303 tape = lookup_tapetype(conf_tapetype);
304 tape_length = tapetype_get_length(tape);
305 g_printf("driver: tape size %lld\n", (long long)tape_length);
306 conf_flush_threshold_dumped = getconf_int(CNF_FLUSH_THRESHOLD_DUMPED);
307 conf_flush_threshold_scheduled = getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED);
308 conf_taperflush = getconf_int(CNF_TAPERFLUSH);
310 flush_threshold_dumped = (conf_flush_threshold_dumped * tape_length) / 100;
311 flush_threshold_scheduled = (conf_flush_threshold_scheduled * tape_length) / 100;
312 taperflush = (conf_taperflush *tape_length) / 100;
314 driver_debug(1, _("flush_threshold_dumped: %lld\n"), (long long)flush_threshold_dumped);
315 driver_debug(1, _("flush_threshold_scheduled: %lld\n"), (long long)flush_threshold_scheduled);
316 driver_debug(1, _("taperflush: %lld\n"), (long long)taperflush);
318 /* set up any configuration-dependent variables */
320 inparallel = getconf_int(CNF_INPARALLEL);
322 reserve = (unsigned long)getconf_int(CNF_RESERVE);
324 total_disksize = (off_t)0;
327 for (il = getconf_identlist(CNF_HOLDINGDISK), dsk = 0;
329 il = il->next, dsk++) {
330 hdp = lookup_holdingdisk(il->data);
331 ha = alloc(SIZEOF(holdalloc_t));
334 /* link the list in the same order as getconf_holdingdisks's results */
343 ha->allocated_dumpers = 0;
344 ha->allocated_space = (off_t)0;
345 ha->disksize = holdingdisk_get_disksize(hdp);
348 if(get_fs_usage(holdingdisk_get_diskdir(hdp), NULL, &fsusage) == -1
349 || access(holdingdisk_get_diskdir(hdp), W_OK) == -1) {
350 log_add(L_WARNING, _("WARNING: ignoring holding disk %s: %s\n"),
351 holdingdisk_get_diskdir(hdp), strerror(errno));
356 /* do the division first to avoid potential integer overflow */
357 if (fsusage.fsu_bavail_top_bit_set)
360 kb_avail = fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize;
362 if(ha->disksize > (off_t)0) {
363 if(ha->disksize > kb_avail) {
365 _("WARNING: %s: %lld KB requested, "
366 "but only %lld KB available."),
367 holdingdisk_get_diskdir(hdp),
368 (long long)ha->disksize,
369 (long long)kb_avail);
370 ha->disksize = kb_avail;
373 /* ha->disksize is negative; use all but that amount */
374 else if(kb_avail < -ha->disksize) {
376 _("WARNING: %s: not %lld KB free."),
377 holdingdisk_get_diskdir(hdp),
378 (long long)-ha->disksize);
379 ha->disksize = (off_t)0;
383 ha->disksize += kb_avail;
385 g_printf(_("driver: adding holding disk %d dir %s size %lld chunksize %lld\n"),
386 dsk, holdingdisk_get_diskdir(hdp),
387 (long long)ha->disksize,
388 (long long)(holdingdisk_get_chunksize(hdp)));
390 newdir = newvstralloc(newdir,
391 holdingdisk_get_diskdir(hdp), "/", hd_driver_timestamp,
393 if(!mkholdingdir(newdir)) {
394 ha->disksize = (off_t)0;
396 total_disksize += ha->disksize;
399 reserved_space = total_disksize * (off_t)(reserve / 100);
401 g_printf(_("reserving %lld out of %lld for degraded-mode dumps\n"),
402 (long long)reserved_space, (long long)free_space());
406 if(inparallel > MAX_DUMPERS) inparallel = MAX_DUMPERS;
408 /* taper takes a while to get going, so start it up right away */
411 if(conf_runtapes > 0) {
412 startup_tape_process(taper_program);
413 taper_cmd(START_TAPER, driver_timestamp, NULL, 0, NULL);
416 /* fire up the dumpers now while we are waiting */
417 if(!nodump) startup_dump_processes(dumper_program, inparallel, driver_timestamp);
420 * Read schedule from stdin. Usually, this is a pipe from planner,
421 * so the effect is that we wait here for the planner to
422 * finish, but meanwhile the taper is rewinding the tape, reading
423 * the label, checking it, writing a new label and all that jazz
424 * in parallel with the planner.
432 taper_state = TAPER_STATE_DEFAULT;
433 tapeq = read_flush();
435 roomq.head = roomq.tail = NULL;
437 log_add(L_STATS, _("startup time %s"), walltime_str(curclock()));
439 g_printf(_("driver: start time %s inparallel %d bandwidth %lu diskspace %lld "), walltime_str(curclock()), inparallel,
440 free_kps(NULL), (long long)free_space());
441 g_printf(_(" dir %s datestamp %s driver: drain-ends tapeq %s big-dumpers %s\n"),
442 "OBSOLETE", driver_timestamp, taperalgo2str(conf_taperalgo),
443 getconf_str(CNF_DUMPORDER));
446 /* ok, planner is done, now lets see if the tape is ready */
448 if (conf_runtapes > 0) {
449 cmd = getresult(taper, 1, &result_argc, &result_argv);
450 if (cmd != TAPER_OK) {
451 /* no tape, go into degraded mode: dump to holding disk */
458 tape_left = tape_length;
460 amfree(taper_input_error);
461 amfree(taper_tape_error);
463 taper_ev_read = NULL;
465 schedule_done = nodump;
468 if(!need_degraded) startaflush();
471 schedule_ev_read = event_register((event_id_t)0, EV_READFD, read_schedule, NULL);
478 /* mv runq to directq */
479 while (!empty(runq)) {
480 diskp = dequeue_disk(&runq);
481 headqueue_disk(&directq, diskp);
484 /* handle any remaining dumps by dumping directly to tape, if possible */
485 while(!empty(directq) && taper > 0) {
486 time_t sleep_time = 100000000;
487 disk_t *sleep_diskp = NULL;
488 time_t now = time(0);
490 /* Find one we can do immediately or the sonner */
491 for (diskp = directq.head; diskp != NULL; diskp = diskp->next) {
492 if (diskp->to_holdingdisk == HOLD_REQUIRED ||
496 } else if (diskp->host->start_t - now < sleep_time &&
497 diskp->start_t -now < sleep_time) {
498 if (diskp->host->start_t > diskp->start_t)
499 sleep_time = diskp->host->start_t - now;
501 sleep_time = diskp->start_t - now;
508 remove_disk(&directq, diskp);
510 if (diskp->to_holdingdisk == HOLD_REQUIRED) {
511 char *qname = quote_string(diskp->name);
512 log_add(L_FAIL, "%s %s %s %d [%s]",
513 diskp->host->hostname, qname, sched(diskp)->datestamp,
515 _("can't dump required holdingdisk"));
518 else if (!degraded_mode) {
519 taper_state |= TAPER_STATE_DUMP_TO_TAPE;
522 taper_state &= ~TAPER_STATE_DUMP_TO_TAPE;
525 char *qname = quote_string(diskp->name);
526 log_add(L_FAIL, "%s %s %s %d [%s]",
527 diskp->host->hostname, qname, sched(diskp)->datestamp,
530 _("can't do degraded dump without holding disk") :
531 diskp->to_holdingdisk != HOLD_NEVER ?
532 _("out of holding space in degraded mode") :
533 _("can't dump 'holdingdisk never' dle in degraded mode"));
538 /* fill up the tape or start new one for taperflush */
542 short_dump_state(); /* for amstatus */
544 g_printf(_("driver: QUITTING time %s telling children to quit\n"),
545 walltime_str(curclock()));
549 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
551 dumper_cmd(dumper, QUIT, NULL, NULL);
556 taper_cmd(QUIT, NULL, NULL, 0, NULL);
559 /* wait for all to die */
563 holding_cleanup(NULL, NULL);
567 check_unfree_serial();
568 g_printf(_("driver: FINISHED time %s\n"), walltime_str(curclock()));
570 log_add(L_FINISH,_("date %s time %s"), driver_timestamp, walltime_str(curclock()));
571 log_add(L_INFO, "pid-done %ld", (long)getpid());
572 amfree(driver_timestamp);
574 amfree(dumper_program);
575 amfree(taper_program);
577 g_strfreev(result_argv);
584 /* sleep up to count seconds, and wait for terminating child process */
585 /* if sleep is negative, this function will not timeout */
586 /* exit once all child process are finished or the timout expired */
587 /* return 0 if no more children to wait */
588 /* return 1 if some children are still alive */
590 wait_children(int count)
602 pid = waitpid((pid_t)-1, &retstat, WNOHANG);
606 if (! WIFEXITED(retstat)) {
608 code = WTERMSIG(retstat);
609 } else if (WEXITSTATUS(retstat) != 0) {
611 code = WEXITSTATUS(retstat);
614 for (dumper = dmptable; dumper < dmptable + inparallel;
616 if (pid == dumper->pid) {
617 who = stralloc(dumper->name);
621 if (dumper->chunker && pid == dumper->chunker->pid) {
622 who = stralloc(dumper->chunker->name);
623 dumper->chunker->pid = -1;
627 if (who == NULL && pid == taper_pid) {
628 who = stralloc("taper");
631 if(what != NULL && who == NULL) {
632 who = stralloc("unknown");
635 log_add(L_WARNING, _("%s pid %u exited with %s %d\n"), who,
636 (unsigned)pid, what, code);
637 g_printf(_("driver: %s pid %u exited with %s %d\n"), who,
638 (unsigned)pid, what, code);
642 } while (pid > 0 || wait_errno == EINTR);
647 } while ((errno != ECHILD) && (count != 0));
648 return (errno != ECHILD);
652 kill_children(int signal)
657 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
658 if (!dumper->down && dumper->pid > 1) {
659 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
660 dumper->name, (unsigned)dumper->pid);
661 if (kill(dumper->pid, signal) == -1 && errno == ESRCH) {
663 dumper->chunker->pid = 0;
665 if (dumper->chunker && dumper->chunker->pid > 1) {
666 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
667 dumper->chunker->name,
668 (unsigned)dumper->chunker->pid);
669 if (kill(dumper->chunker->pid, signal) == -1 &&
671 dumper->chunker->pid = 0;
678 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
679 "taper", (unsigned)taper_pid);
680 if (kill(taper_pid, signal) == -1 && errno == ESRCH)
686 wait_for_children(void)
691 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
692 if (dumper->pid > 1 && dumper->fd >= 0) {
693 dumper_cmd(dumper, QUIT, NULL, NULL);
694 if (dumper->chunker && dumper->chunker->pid > 1 &&
695 dumper->chunker->fd >= 0)
696 chunker_cmd(dumper->chunker, QUIT, NULL, NULL);
701 if(taper_pid > 1 && taper > 0) {
702 taper_cmd(QUIT, NULL, NULL, 0, NULL);
705 if(wait_children(60) == 0)
708 kill_children(SIGHUP);
709 if(wait_children(60) == 0)
712 kill_children(SIGKILL);
713 if(wait_children(-1) == 0)
726 TapeAction result_tape_action;
727 char *why_no_new_tape;
729 result_tape_action = tape_action(&why_no_new_tape);
731 if (result_tape_action & TAPE_ACTION_NEW_TAPE) {
732 taper_state &= ~TAPER_STATE_WAIT_FOR_TAPE;
733 taper_cmd(NEW_TAPE, NULL, NULL, 0, NULL);
734 } else if (result_tape_action & TAPE_ACTION_NO_NEW_TAPE) {
735 taper_state &= ~TAPER_STATE_WAIT_FOR_TAPE;
736 taper_cmd(NO_NEW_TAPE, why_no_new_tape, NULL, 0, NULL);
737 start_degraded_mode(&runq);
740 if (!degraded_mode && !taper_busy && !empty(tapeq) &&
741 (result_tape_action & TAPE_ACTION_START_A_FLUSH)) {
743 datestamp = sched(tapeq.head)->datestamp;
744 switch(conf_taperalgo) {
746 dp = dequeue_disk(&tapeq);
750 while (fit != NULL) {
751 extra_tapes = (fit->tape_splitsize > (off_t)0) ?
752 conf_runtapes - current_tape : 0;
753 if(sched(fit)->act_size <= (tape_left +
754 tape_length * (off_t)extra_tapes) &&
755 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
763 if(dp) remove_disk(&tapeq, dp);
766 fit = dp = tapeq.head;
767 while (fit != NULL) {
768 if(sched(fit)->act_size > sched(dp)->act_size &&
769 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
774 if(dp) remove_disk(&tapeq, dp);
776 case ALGO_LARGESTFIT:
778 while (fit != NULL) {
779 extra_tapes = (fit->tape_splitsize > (off_t)0) ?
780 conf_runtapes - current_tape : 0;
781 if(sched(fit)->act_size <=
782 (tape_left + tape_length * (off_t)extra_tapes) &&
783 (!dp || sched(fit)->act_size > sched(dp)->act_size) &&
784 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
789 if(dp) remove_disk(&tapeq, dp);
795 remove_disk(&tapeq, dp);
798 if(!dp) { /* ALGO_SMALLEST, or default if nothing fit. */
799 if(conf_taperalgo != ALGO_SMALLEST) {
801 _("driver: startaflush: Using SMALLEST because nothing fit\n"));
803 fit = dp = tapeq.head;
804 while (fit != NULL) {
805 if(sched(fit)->act_size < sched(dp)->act_size &&
806 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
811 if(dp) remove_disk(&tapeq, dp);
813 if(taper_ev_read == NULL) {
814 taper_ev_read = event_register((event_id_t)taper, EV_READFD,
815 handle_taper_result, NULL);
820 amfree(taper_input_error);
821 amfree(taper_tape_error);
822 taper_result = LAST_TOK;
823 taper_sendresult = 0;
824 taper_first_label = NULL;
826 taper_state &= ~TAPER_STATE_DUMP_TO_TAPE;
828 qname = quote_string(dp->name);
829 taper_cmd(FILE_WRITE, dp, sched(dp)->destname, sched(dp)->level,
830 sched(dp)->datestamp);
831 g_fprintf(stderr,_("driver: startaflush: %s %s %s %lld %lld\n"),
832 taperalgo2str(conf_taperalgo), dp->host->hostname, qname,
833 (long long)sched(taper_disk)->act_size,
834 (long long)tape_left);
835 if(sched(dp)->act_size <= tape_left)
836 tape_left -= sched(dp)->act_size;
838 tape_left = (off_t)0;
841 error(_("FATAL: Taper marked busy and no work found."));
845 } else if(!taper_busy && taper_ev_read != NULL) {
846 event_release(taper_ev_read);
847 taper_ev_read = NULL;
857 /* first, check if host is too busy */
859 if(dp->host->inprogress >= dp->host->maxdumps) {
863 /* next, check conflict with other dumps on same spindle */
865 if(dp->spindle == -1) { /* but spindle -1 never conflicts by def. */
869 for(dp2 = dp->host->disks; dp2 != NULL; dp2 = dp2->hostnext)
870 if(dp2->inprogress && dp2->spindle == dp->spindle) {
882 disk_t *diskp, *delayed_diskp, *diskp_accept;
884 assignedhd_t **holdp=NULL, **holdp_accept;
885 const time_t now = time(NULL);
893 int busy_dumpers = 0;
895 idle_reason = IDLE_NO_DUMPERS;
898 if(dumpers_ev_time != NULL) {
899 event_release(dumpers_ev_time);
900 dumpers_ev_time = NULL;
903 for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
909 for (dumper = dmptable; dumper < dmptable+inparallel; dumper++) {
911 if( dumper->busy || dumper->down) {
915 if (dumper->ev_read != NULL) {
916 event_release(dumper->ev_read);
917 dumper->ev_read = NULL;
921 * A potential problem with starting from the bottom of the dump time
922 * distribution is that a slave host will have both one of the shortest
923 * and one of the longest disks, so starting its shortest disk first will
924 * tie up the host and eliminate its longest disk from consideration the
925 * first pass through. This could cause a big delay in starting that long
926 * disk, which could drag out the whole night's dumps.
928 * While starting from the top of the dump time distribution solves the
929 * above problem, this turns out to be a bad idea, because the big dumps
930 * will almost certainly pack the holding disk completely, leaving no
931 * room for even one small dump to start. This ends up shutting out the
932 * small-end dumpers completely (they stay idle).
934 * The introduction of multiple simultaneous dumps to one host alleviates
935 * the biggest&smallest dumps problem: both can be started at the
941 delayed_diskp = NULL;
945 dumporder = getconf_str(CNF_DUMPORDER);
946 if(strlen(dumporder) > (size_t)(dumper-dmptable)) {
947 dumptype = dumporder[dumper-dmptable];
950 if(dumper-dmptable < 3)
956 for(diskp = rq->head; diskp != NULL; diskp = diskp->next) {
957 assert(diskp->host != NULL && sched(diskp) != NULL);
959 if (diskp->host->start_t > now) {
960 cur_idle = max(cur_idle, IDLE_START_WAIT);
961 if (delayed_diskp == NULL || sleep_time > diskp->host->start_t) {
962 delayed_diskp = diskp;
963 sleep_time = diskp->host->start_t;
965 } else if(diskp->start_t > now) {
966 cur_idle = max(cur_idle, IDLE_START_WAIT);
967 if (delayed_diskp == NULL || sleep_time > diskp->start_t) {
968 delayed_diskp = diskp;
969 sleep_time = diskp->start_t;
971 } else if (diskp->host->netif->curusage > 0 &&
972 sched(diskp)->est_kps > free_kps(diskp->host->netif)) {
973 cur_idle = max(cur_idle, IDLE_NO_BANDWIDTH);
974 } else if(sched(diskp)->no_space) {
975 cur_idle = max(cur_idle, IDLE_NO_DISKSPACE);
976 } else if (diskp->to_holdingdisk == HOLD_NEVER) {
977 cur_idle = max(cur_idle, IDLE_NO_HOLD);
979 find_diskspace(sched(diskp)->est_size, &cur_idle, NULL)) == NULL) {
980 cur_idle = max(cur_idle, IDLE_NO_DISKSPACE);
981 if (empty(tapeq) && busy_dumpers == 0) {
982 remove_disk(rq, diskp);
983 enqueue_disk(&directq, diskp);
985 } else if (client_constrained(diskp)) {
986 free_assignedhd(holdp);
987 cur_idle = max(cur_idle, IDLE_CLIENT_CONSTRAINED);
990 /* disk fits, dump it */
991 int accept = !diskp_accept;
994 case 's': accept = (sched(diskp)->est_size < sched(diskp_accept)->est_size);
996 case 'S': accept = (sched(diskp)->est_size > sched(diskp_accept)->est_size);
998 case 't': accept = (sched(diskp)->est_time < sched(diskp_accept)->est_time);
1000 case 'T': accept = (sched(diskp)->est_time > sched(diskp_accept)->est_time);
1002 case 'b': accept = (sched(diskp)->est_kps < sched(diskp_accept)->est_kps);
1004 case 'B': accept = (sched(diskp)->est_kps > sched(diskp_accept)->est_kps);
1006 default: log_add(L_WARNING, _("Unknown dumporder character \'%c\', using 's'.\n"),
1008 accept = (sched(diskp)->est_size < sched(diskp_accept)->est_size);
1013 if( !diskp_accept || !degraded_mode || diskp->priority >= diskp_accept->priority) {
1014 if(holdp_accept) free_assignedhd(holdp_accept);
1015 diskp_accept = diskp;
1016 holdp_accept = holdp;
1019 free_assignedhd(holdp);
1023 free_assignedhd(holdp);
1028 diskp = diskp_accept;
1029 holdp = holdp_accept;
1031 idle_reason = max(idle_reason, cur_idle);
1032 if (diskp == NULL && idle_reason == IDLE_NO_DISKSPACE) {
1033 /* continue flush waiting for new tape */
1038 * If we have no disk at this point, and there are disks that
1039 * are delayed, then schedule a time event to call this dumper
1040 * with the disk with the shortest delay.
1042 if (diskp == NULL && delayed_diskp != NULL) {
1043 assert(sleep_time > now);
1045 dumpers_ev_time = event_register((event_id_t)sleep_time, EV_TIME,
1046 handle_dumpers_time, &runq);
1048 } else if (diskp != NULL) {
1049 sched(diskp)->act_size = (off_t)0;
1050 allocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1051 sched(diskp)->activehd = assign_holdingdisk(holdp, diskp);
1053 sched(diskp)->destname = newstralloc(sched(diskp)->destname,
1054 sched(diskp)->holdp[0]->destname);
1055 diskp->host->inprogress++; /* host is now busy */
1056 diskp->inprogress = 1;
1057 sched(diskp)->dumper = dumper;
1058 sched(diskp)->timestamp = now;
1059 amfree(diskp->dataport_list);
1061 dumper->busy = 1; /* dumper is now busy */
1062 dumper->dp = diskp; /* link disk to dumper */
1063 remove_disk(rq, diskp); /* take it off the run queue */
1065 sched(diskp)->origsize = (off_t)-1;
1066 sched(diskp)->dumpsize = (off_t)-1;
1067 sched(diskp)->dumptime = (time_t)0;
1068 sched(diskp)->tapetime = (time_t)0;
1069 chunker = dumper->chunker;
1070 chunker->result = LAST_TOK;
1071 dumper->result = LAST_TOK;
1072 startup_chunk_process(chunker,chunker_program);
1073 chunker_cmd(chunker, START, NULL, driver_timestamp);
1074 chunker->dumper = dumper;
1075 chunker_cmd(chunker, PORT_WRITE, diskp, NULL);
1076 cmd = getresult(chunker->fd, 1, &result_argc, &result_argv);
1078 assignedhd_t **h=NULL;
1080 char *qname = quote_string(diskp->name);
1082 g_printf(_("driver: did not get PORT from %s for %s:%s\n"),
1083 chunker->name, diskp->host->hostname, qname);
1087 deallocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1088 h = sched(diskp)->holdp;
1089 activehd = sched(diskp)->activehd;
1090 h[activehd]->used = 0;
1091 h[activehd]->disk->allocated_dumpers--;
1092 adjust_diskspace(diskp, DONE);
1093 delete_diskspace(diskp);
1094 diskp->host->inprogress--;
1095 diskp->inprogress = 0;
1096 sched(diskp)->dumper = NULL;
1099 sched(diskp)->dump_attempted++;
1100 free_serial_dp(diskp);
1101 if(sched(diskp)->dump_attempted < 2)
1102 enqueue_disk(rq, diskp);
1105 dumper->ev_read = event_register((event_id_t)dumper->fd, EV_READFD,
1106 handle_dumper_result, dumper);
1107 chunker->ev_read = event_register((event_id_t)chunker->fd, EV_READFD,
1108 handle_chunker_result, chunker);
1109 dumper->output_port = atoi(result_argv[1]);
1110 amfree(diskp->dataport_list);
1111 diskp->dataport_list = stralloc(result_argv[2]);
1113 if (diskp->host->pre_script == 0) {
1114 for (dp=diskp->host->disks; dp != NULL; dp = dp->hostnext) {
1115 run_server_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
1116 get_config_name(), dp, -1);
1118 diskp->host->pre_script = 1;
1120 run_server_scripts(EXECUTE_ON_PRE_DLE_BACKUP,
1121 get_config_name(), diskp,
1122 sched(diskp)->level);
1123 dumper_cmd(dumper, PORT_DUMP, diskp, NULL);
1125 diskp->host->start_t = now + 15;
1128 g_strfreev(result_argv);
1135 * This gets called when a dumper is delayed for some reason. It may
1136 * be because a disk has a delayed start, or amanda is constrained
1137 * by network or disk limits.
1141 handle_dumpers_time(
1144 disklist_t *runq = cookie;
1145 event_release(dumpers_ev_time);
1146 dumpers_ev_time = NULL;
1147 start_some_dumps(runq);
1158 g_printf(_("dump of driver schedule %s:\n--------\n"), str);
1160 for(dp = qp->head; dp != NULL; dp = dp->next) {
1161 qname = quote_string(dp->name);
1162 g_printf(" %-20s %-25s lv %d t %5lu s %lld p %d\n",
1163 dp->host->hostname, qname, sched(dp)->level,
1164 sched(dp)->est_time,
1165 (long long)sched(dp)->est_size, sched(dp)->priority);
1168 g_printf("--------\n");
1172 start_degraded_mode(
1173 /*@keep@*/ disklist_t *queuep)
1177 off_t est_full_size;
1180 newq.head = newq.tail = 0;
1182 dump_schedule(queuep, _("before start degraded mode"));
1184 est_full_size = (off_t)0;
1185 while(!empty(*queuep)) {
1186 dp = dequeue_disk(queuep);
1188 qname = quote_string(dp->name);
1189 if(sched(dp)->level != 0)
1190 /* go ahead and do the disk as-is */
1191 enqueue_disk(&newq, dp);
1193 if (reserved_space + est_full_size + sched(dp)->est_size
1194 <= total_disksize) {
1195 enqueue_disk(&newq, dp);
1196 est_full_size += sched(dp)->est_size;
1198 else if(sched(dp)->degr_level != -1) {
1199 sched(dp)->level = sched(dp)->degr_level;
1200 sched(dp)->dumpdate = sched(dp)->degr_dumpdate;
1201 sched(dp)->est_nsize = sched(dp)->degr_nsize;
1202 sched(dp)->est_csize = sched(dp)->degr_csize;
1203 sched(dp)->est_time = sched(dp)->degr_time;
1204 sched(dp)->est_kps = sched(dp)->degr_kps;
1205 enqueue_disk(&newq, dp);
1208 log_add(L_FAIL, "%s %s %s %d [%s]",
1209 dp->host->hostname, qname, sched(dp)->datestamp,
1210 sched(dp)->level, sched(dp)->degr_mesg);
1216 /*@i@*/ *queuep = newq;
1219 dump_schedule(queuep, _("after start degraded mode"));
1224 continue_port_dumps(void)
1228 int active_dumpers=0, busy_dumpers=0, i;
1231 /* First we try to grant diskspace to some dumps waiting for it. */
1232 for( dp = roomq.head; dp; dp = ndp ) {
1234 /* find last holdingdisk used by this dump */
1235 for( i = 0, h = sched(dp)->holdp; h[i+1]; i++ ) {
1236 (void)h; /* Quiet lint */
1238 /* find more space */
1239 h = find_diskspace( sched(dp)->est_size - sched(dp)->act_size,
1240 &active_dumpers, h[i] );
1242 for(dumper = dmptable; dumper < dmptable + inparallel &&
1243 dumper->dp != dp; dumper++) {
1244 (void)dp; /* Quiet lint */
1246 assert( dumper < dmptable + inparallel );
1247 sched(dp)->activehd = assign_holdingdisk( h, dp );
1248 chunker_cmd( dumper->chunker, CONTINUE, dp, NULL );
1250 remove_disk( &roomq, dp );
1254 /* So for some disks there is less holding diskspace available than
1255 * was asked for. Possible reasons are
1256 * a) diskspace has been allocated for other dumps which are
1257 * still running or already being written to tape
1258 * b) all other dumps have been suspended due to lack of diskspace
1259 * Case a) is not a problem. We just wait for the diskspace to
1260 * be freed by moving the current disk to a queue.
1261 * If case b) occurs, we have a deadlock situation. We select
1262 * a dump from the queue to be aborted and abort it. It will
1263 * be retried directly to tape.
1265 for(dp=NULL, dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
1266 if( dumper->busy ) {
1268 if( !find_disk(&roomq, dumper->dp) ) {
1271 sched(dp)->est_size > sched(dumper->dp)->est_size ) {
1276 if((dp != NULL) && (active_dumpers == 0) && (busy_dumpers > 0) &&
1277 ((!taper_busy && empty(tapeq)) || degraded_mode) &&
1278 pending_aborts == 0 ) { /* case b */
1279 sched(dp)->no_space = 1;
1280 /* At this time, dp points to the dump with the smallest est_size.
1281 * We abort that dump, hopefully not wasting too much time retrying it.
1283 remove_disk( &roomq, dp );
1284 chunker_cmd(sched(dp)->dumper->chunker, ABORT, NULL, _("Not enough holding disk space"));
1285 dumper_cmd( sched(dp)->dumper, ABORT, NULL, _("Not enough holding disk space"));
1292 handle_taper_result(
1293 void *cookie G_GNUC_UNUSED)
1302 assert(cookie == NULL);
1303 amfree(taper_input_error);
1304 amfree(taper_tape_error);
1310 cmd = getresult(taper, 1, &result_argc, &result_argv);
1314 case FAILED: /* FAILED <handle> INPUT-* TAPE-* <input err mesg> <tape err mesg> */
1315 if(result_argc != 6) {
1316 error(_("error: [taper FAILED result_argc != 6: %d"), result_argc);
1320 dp = serial2disk(result_argv[1]);
1321 assert(dp == taper_disk);
1323 free_serial(result_argv[1]);
1325 qname = quote_string(dp->name);
1326 g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1327 walltime_str(curclock()), dp->host->hostname, qname);
1330 if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
1331 taper_input_error = newstralloc(taper_input_error, result_argv[4]);
1332 } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
1333 taper_tape_error = newstralloc(taper_tape_error,
1334 _("Taper protocol error"));
1335 taper_result = FAILED;
1336 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1337 dp->host->hostname, qname, sched(dp)->datestamp,
1338 sched(dp)->level, taper_tape_error);
1342 if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
1343 taper_tape_error = newstralloc(taper_tape_error, result_argv[5]);
1344 } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
1345 taper_tape_error = newstralloc(taper_tape_error,
1346 _("Taper protocol error"));
1347 taper_result = FAILED;
1348 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1349 dp->host->hostname, qname, sched(dp)->datestamp,
1350 sched(dp)->level, taper_tape_error);
1360 case PARTIAL: /* PARTIAL <handle> INPUT-* TAPE-* <stat mess> <input err mesg> <tape err mesg>*/
1361 case DONE: /* DONE <handle> INPUT-GOOD TAPE-GOOD <stat mess> <input err mesg> <tape err mesg> */
1362 if(result_argc != 7) {
1363 error(_("error: [taper PARTIAL result_argc != 7: %d"), result_argc);
1367 dp = serial2disk(result_argv[1]);
1368 assert(dp == taper_disk);
1370 free_serial(result_argv[1]);
1372 qname = quote_string(dp->name);
1373 g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1374 walltime_str(curclock()), dp->host->hostname, qname);
1377 if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
1378 taper_input_error = newstralloc(taper_input_error, result_argv[5]);
1379 } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
1380 taper_tape_error = newstralloc(taper_tape_error,
1381 _("Taper protocol error"));
1382 taper_result = FAILED;
1383 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1384 dp->host->hostname, qname, sched(dp)->datestamp,
1385 sched(dp)->level, taper_tape_error);
1389 if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
1390 taper_tape_error = newstralloc(taper_tape_error, result_argv[6]);
1391 } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
1392 taper_tape_error = newstralloc(taper_tape_error,
1393 _("Taper protocol error"));
1394 taper_result = FAILED;
1395 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1396 dp->host->hostname, qname, sched(dp)->datestamp,
1397 sched(dp)->level, taper_tape_error);
1402 s = strstr(result_argv[4], " kb ");
1405 sched(dp)->dumpsize = atol(s);
1413 case PARTDONE: /* PARTDONE <handle> <label> <fileno> <kbytes> <stat> */
1414 dp = serial2disk(result_argv[1]);
1415 assert(dp == taper_disk);
1416 if (result_argc != 6) {
1417 error(_("error [taper PARTDONE result_argc != 6: %d]"),
1421 if (!taper_first_label) {
1422 taper_first_label = stralloc(result_argv[2]);
1423 taper_first_fileno = OFF_T_ATOI(result_argv[3]);
1425 taper_written = OFF_T_ATOI(result_argv[4]);
1426 if (taper_written > sched(taper_disk)->act_size)
1427 sched(taper_disk)->act_size = taper_written;
1431 case REQUEST_NEW_TAPE: /* REQUEST-NEW-TAPE <handle> */
1432 if (result_argc != 2) {
1433 error(_("error [taper REQUEST_NEW_TAPE result_argc != 2: %d]"),
1437 taper_state &= ~TAPER_STATE_TAPE_STARTED;
1439 if (current_tape >= conf_runtapes) {
1440 char *usermsg = g_strdup_printf(_("%d tapes filled; runtapes=%d "
1441 "does not allow additional tapes"), current_tape, conf_runtapes);
1442 taper_cmd(NO_NEW_TAPE, usermsg, NULL, 0, NULL);
1445 _("Out of tapes; going into degraded mode."));
1446 start_degraded_mode(&runq);
1448 TapeAction result_tape_action;
1449 char *why_no_new_tape;
1451 taper_state |= TAPER_STATE_WAIT_FOR_TAPE;
1452 result_tape_action = tape_action(&why_no_new_tape);
1453 if (result_tape_action & TAPE_ACTION_NEW_TAPE) {
1454 taper_cmd(NEW_TAPE, NULL, NULL, 0, NULL);
1455 taper_state &= ~TAPER_STATE_WAIT_FOR_TAPE;
1456 } else if (result_tape_action & TAPE_ACTION_NO_NEW_TAPE) {
1457 taper_cmd(NO_NEW_TAPE, why_no_new_tape, NULL, 0, NULL);
1458 taper_state &= ~TAPER_STATE_WAIT_FOR_TAPE;
1459 start_degraded_mode(&runq);
1464 case NEW_TAPE: /* NEW-TAPE <handle> <label> */
1465 if (result_argc != 3) {
1466 error(_("error [taper NEW_TAPE result_argc != 3: %d]"),
1471 /* Update our tape counter and reset tape_left */
1473 tape_left = tape_length;
1474 taper_state |= TAPER_STATE_TAPE_STARTED;
1477 case NO_NEW_TAPE: /* NO-NEW-TAPE <handle> */
1478 if (result_argc != 2) {
1479 error(_("error [taper NO_NEW_TAPE result_argc != 2: %d]"),
1483 start_degraded_mode(&runq);
1486 case DUMPER_STATUS: /* DUMPER-STATUS <handle> */
1487 if (result_argc != 2) {
1488 error(_("error [taper DUMPER_STATUS result_argc != 2: %d]"),
1492 dp = serial2disk(result_argv[1]);
1493 if (taper_dumper->result == LAST_TOK) {
1494 taper_sendresult = 1;
1496 if( taper_dumper->result == DONE) {
1497 taper_cmd(DONE, dp, NULL, 0, NULL);
1499 taper_cmd(FAILED, dp, NULL, 0, NULL);
1504 case TAPE_ERROR: /* TAPE-ERROR <handle> <err mess> */
1505 dp = serial2disk(result_argv[1]);
1507 free_serial(result_argv[1]);
1508 qname = quote_string(dp->name);
1509 g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1510 walltime_str(curclock()), dp->host->hostname, qname);
1513 q = quote_string(result_argv[2]);
1514 log_add(L_WARNING, _("Taper error: %s"), q);
1516 taper_tape_error = newstralloc(taper_tape_error, result_argv[2]);
1521 log_add(L_WARNING, _("Taper protocol error"));
1522 taper_tape_error = newstralloc(taper_tape_error, "BOGUS");
1525 * Since we received a taper error, we can't send anything more
1526 * to the taper. Go into degraded mode to try to get everthing
1527 * onto disk. Later, these dumps can be flushed to a new tape.
1528 * The tape queue is zapped so that it appears empty in future
1529 * checks. If there are dumps waiting for diskspace to be freed,
1534 _("going into degraded mode because of taper component error."));
1536 start_degraded_mode(&runq);
1537 tapeq.head = tapeq.tail = NULL;
1539 if(taper_ev_read != NULL) {
1540 event_release(taper_ev_read);
1541 taper_ev_read = NULL;
1543 if(cmd != TAPE_ERROR) aclose(taper);
1549 error(_("driver received unexpected token (%s) from taper"),
1554 g_strfreev(result_argv);
1556 if (taper_result != LAST_TOK) {
1558 if (taper_dumper->result != LAST_TOK) {
1559 // Dumper already returned it's result
1560 dumper_taper_result(taper_disk);
1563 file_taper_result(taper_disk);
1567 } while(areads_dataready(taper));
1575 char *qname = quote_string(dp->name);
1577 if (taper_result == DONE) {
1578 update_info_taper(dp, taper_first_label, taper_first_fileno,
1582 sched(dp)->taper_attempted += 1;
1584 if (taper_input_error) {
1585 g_printf("driver: taper failed %s %s: %s\n",
1586 dp->host->hostname, qname, taper_input_error);
1587 if (strcmp(sched(dp)->datestamp, driver_timestamp) == 0) {
1588 if(sched(dp)->taper_attempted >= 2) {
1589 log_add(L_FAIL, _("%s %s %s %d [too many taper retries after holding disk error: %s]"),
1590 dp->host->hostname, qname, sched(dp)->datestamp,
1591 sched(dp)->level, taper_input_error);
1592 g_printf("driver: taper failed %s %s, too many taper retry after holding disk error\n",
1593 dp->host->hostname, qname);
1594 amfree(sched(dp)->destname);
1595 amfree(sched(dp)->dumpdate);
1596 amfree(sched(dp)->degr_dumpdate);
1597 amfree(sched(dp)->degr_mesg);
1598 amfree(sched(dp)->datestamp);
1601 log_add(L_INFO, _("%s %s %s %d [Will retry dump because of holding disk error: %s]"),
1602 dp->host->hostname, qname, sched(dp)->datestamp,
1603 sched(dp)->level, taper_input_error);
1604 g_printf("driver: taper will retry %s %s because of holding disk error\n",
1605 dp->host->hostname, qname);
1606 if (dp->to_holdingdisk != HOLD_REQUIRED) {
1607 dp->to_holdingdisk = HOLD_NEVER;
1608 sched(dp)->dump_attempted -= 1;
1609 headqueue_disk(&directq, dp);
1611 amfree(sched(dp)->destname);
1612 amfree(sched(dp)->dumpdate);
1613 amfree(sched(dp)->degr_dumpdate);
1614 amfree(sched(dp)->degr_mesg);
1615 amfree(sched(dp)->datestamp);
1620 amfree(sched(dp)->destname);
1621 amfree(sched(dp)->dumpdate);
1622 amfree(sched(dp)->degr_dumpdate);
1623 amfree(sched(dp)->degr_mesg);
1624 amfree(sched(dp)->datestamp);
1627 } else if (taper_tape_error) {
1628 g_printf("driver: taper failed %s %s with tape error: %s\n",
1629 dp->host->hostname, qname, taper_tape_error);
1630 if(sched(dp)->taper_attempted >= 2) {
1631 log_add(L_FAIL, _("%s %s %s %d [too many taper retries]"),
1632 dp->host->hostname, qname, sched(dp)->datestamp,
1634 g_printf("driver: taper failed %s %s, too many taper retry\n",
1635 dp->host->hostname, qname);
1636 amfree(sched(dp)->destname);
1637 amfree(sched(dp)->dumpdate);
1638 amfree(sched(dp)->degr_dumpdate);
1639 amfree(sched(dp)->degr_mesg);
1640 amfree(sched(dp)->datestamp);
1643 g_printf("driver: taper will retry %s %s\n",
1644 dp->host->hostname, qname);
1645 /* Re-insert into taper queue. */
1646 headqueue_disk(&tapeq, dp);
1648 } else if (taper_result != DONE) {
1649 g_printf("driver: taper failed %s %s without error\n",
1650 dp->host->hostname, qname);
1652 delete_diskspace(dp);
1653 amfree(sched(dp)->destname);
1654 amfree(sched(dp)->dumpdate);
1655 amfree(sched(dp)->degr_dumpdate);
1656 amfree(sched(dp)->degr_mesg);
1657 amfree(sched(dp)->datestamp);
1664 amfree(taper_input_error);
1665 amfree(taper_tape_error);
1668 /* continue with those dumps waiting for diskspace */
1669 continue_port_dumps();
1670 start_some_dumps(&runq);
1675 dumper_taper_result(
1682 dumper = sched(dp)->dumper;
1685 if(dumper->result == DONE && taper_result == DONE) {
1686 update_info_dumper(dp, sched(dp)->origsize,
1687 sched(dp)->dumpsize, sched(dp)->dumptime);
1688 update_info_taper(dp, taper_first_label, taper_first_fileno,
1690 qname = quote_string(dp->name); /*quote to take care of spaces*/
1692 log_add(L_STATS, _("estimate %s %s %s %d [sec %ld nkb %lld ckb %lld kps %lu]"),
1693 dp->host->hostname, qname, sched(dp)->datestamp,
1695 sched(dp)->est_time, (long long)sched(dp)->est_nsize,
1696 (long long)sched(dp)->est_csize,
1697 sched(dp)->est_kps);
1700 update_failed_dump(dp);
1703 is_partial = dumper->result != DONE || taper_result != DONE;
1705 sched(dp)->dump_attempted += 1;
1706 sched(dp)->taper_attempted += 1;
1708 if((dumper->result != DONE || taper_result != DONE) &&
1709 sched(dp)->dump_attempted <= 1 &&
1710 sched(dp)->taper_attempted <= 1) {
1711 enqueue_disk(&directq, dp);
1714 if(dumper->ev_read != NULL) {
1715 event_release(dumper->ev_read);
1716 dumper->ev_read = NULL;
1718 if(taper_ev_read != NULL) {
1719 event_release(taper_ev_read);
1720 taper_ev_read = NULL;
1723 amfree(taper_input_error);
1724 amfree(taper_tape_error);
1726 dp->host->inprogress -= 1;
1728 deallocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
1737 for(dumper = dmptable; dumper < dmptable+inparallel; dumper++)
1738 if(!dumper->busy && !dumper->down) return dumper;
1744 dumper_chunker_result(
1749 assignedhd_t **h=NULL;
1756 dumper = sched(dp)->dumper;
1757 chunker = dumper->chunker;
1761 h = sched(dp)->holdp;
1762 activehd = sched(dp)->activehd;
1764 if(dumper->result == DONE && chunker->result == DONE) {
1765 update_info_dumper(dp, sched(dp)->origsize,
1766 sched(dp)->dumpsize, sched(dp)->dumptime);
1767 qname = quote_string(dp->name);/*quote to take care of spaces*/
1769 log_add(L_STATS, _("estimate %s %s %s %d [sec %ld nkb %lld ckb %lld kps %lu]"),
1770 dp->host->hostname, qname, sched(dp)->datestamp,
1772 sched(dp)->est_time, (long long)sched(dp)->est_nsize,
1773 (long long)sched(dp)->est_csize,
1774 sched(dp)->est_kps);
1777 update_failed_dump(dp);
1780 deallocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
1782 is_partial = dumper->result != DONE || chunker->result != DONE;
1783 rename_tmp_holding(sched(dp)->destname, !is_partial);
1784 holding_set_origsize(sched(dp)->destname, sched(dp)->origsize);
1787 for( i = 0, h = sched(dp)->holdp; i < activehd; i++ ) {
1788 dummy += h[i]->used;
1791 size = holding_file_size(sched(dp)->destname, 0);
1792 h[activehd]->used = size - dummy;
1793 h[activehd]->disk->allocated_dumpers--;
1794 adjust_diskspace(dp, DONE);
1796 sched(dp)->dump_attempted += 1;
1798 if((dumper->result != DONE || chunker->result != DONE) &&
1799 sched(dp)->dump_attempted <= 1) {
1800 delete_diskspace(dp);
1801 if (sched(dp)->no_space) {
1802 enqueue_disk(&directq, dp);
1804 enqueue_disk(&runq, dp);
1807 else if(size > (off_t)DISK_BLOCK_KB) {
1808 enqueue_disk(&tapeq, dp);
1811 delete_diskspace(dp);
1815 dp->host->inprogress -= 1;
1818 waitpid(chunker->pid, NULL, 0 );
1819 aclose(chunker->fd);
1824 if (chunker->result == ABORT_FINISHED)
1826 continue_port_dumps();
1828 * Wakeup any dumpers that are sleeping because of network
1829 * or disk constraints.
1831 start_some_dumps(&runq);
1837 handle_dumper_result(
1840 /* uses global pending_aborts */
1841 dumper_t *dumper = cookie;
1842 disk_t *dp, *sdp, *dp1;
1848 assert(dumper != NULL);
1851 assert(sched(dp) != NULL);
1856 cmd = getresult(dumper->fd, 1, &result_argc, &result_argv);
1859 /* result_argv[1] always contains the serial number */
1860 sdp = serial2disk(result_argv[1]);
1862 error(_("Invalid serial number %s"), result_argv[1]);
1863 g_assert_not_reached();
1867 qname = quote_string(dp->name);
1870 case DONE: /* DONE <handle> <origsize> <dumpsize> <dumptime> <errstr> */
1871 if(result_argc != 6) {
1872 error(_("error [dumper DONE result_argc != 6: %d]"), result_argc);
1876 sched(dp)->origsize = OFF_T_ATOI(result_argv[2]);
1877 sched(dp)->dumptime = TIME_T_ATOI(result_argv[4]);
1879 g_printf(_("driver: finished-cmd time %s %s dumped %s:%s\n"),
1880 walltime_str(curclock()), dumper->name,
1881 dp->host->hostname, qname);
1884 dumper->result = cmd;
1888 case TRYAGAIN: /* TRY-AGAIN <handle> <errstr> */
1890 * Requeue this disk, and fall through to the FAILED
1893 if(sched(dp)->dump_attempted) {
1894 char *qname = quote_string(dp->name);
1895 char *qerr = quote_string(result_argv[2]);
1896 log_add(L_FAIL, _("%s %s %s %d [too many dumper retry: %s]"),
1897 dp->host->hostname, qname, sched(dp)->datestamp,
1898 sched(dp)->level, qerr);
1899 g_printf(_("driver: dump failed %s %s %s, too many dumper retry: %s\n"),
1900 result_argv[1], dp->host->hostname, qname, qerr);
1905 case FAILED: /* FAILED <handle> <errstr> */
1906 /*free_serial(result_argv[1]);*/
1907 dumper->result = cmd;
1910 case ABORT_FINISHED: /* ABORT-FINISHED <handle> */
1912 * We sent an ABORT from the NO-ROOM case because this dump
1913 * wasn't going to fit onto the holding disk. We now need to
1914 * clean up the remains of this image, and try to finish
1915 * other dumps that are waiting on disk space.
1917 assert(pending_aborts);
1918 /*free_serial(result_argv[1]);*/
1919 dumper->result = cmd;
1923 /* either EOF or garbage from dumper. Turn it off */
1924 log_add(L_WARNING, _("%s pid %ld is messed up, ignoring it.\n"),
1925 dumper->name, (long)dumper->pid);
1926 if (dumper->ev_read) {
1927 event_release(dumper->ev_read);
1928 dumper->ev_read = NULL;
1932 dumper->down = 1; /* mark it down so it isn't used again */
1934 /* if it was dumping something, zap it and try again */
1935 if(sched(dp)->dump_attempted) {
1936 log_add(L_FAIL, _("%s %s %s %d [%s died]"),
1937 dp->host->hostname, qname, sched(dp)->datestamp,
1938 sched(dp)->level, dumper->name);
1940 log_add(L_WARNING, _("%s died while dumping %s:%s lev %d."),
1941 dumper->name, dp->host->hostname, qname,
1944 dumper->result = cmd;
1951 g_strfreev(result_argv);
1957 run_server_scripts(EXECUTE_ON_POST_DLE_BACKUP,
1958 get_config_name(), dp, sched(dp)->level);
1959 /* check dump not yet started */
1960 for (dp1=runq.head; dp1 != NULL; dp1 = dp1->next) {
1961 if (dp1->host == dp->host)
1964 /* check direct to tape dump */
1965 for (dp1=directq.head; dp1 != NULL; dp1 = dp1->next) {
1966 if (dp1->host == dp->host)
1969 /* check dumping dle */
1970 for (dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
1971 if (dumper->busy && dumper->dp != dp &&
1972 dumper->dp->host == dp->host)
1975 if (last_dump && dp->host->post_script == 0) {
1976 if (dp->host->post_script == 0) {
1977 for (dp1=dp->host->disks; dp1 != NULL; dp1 = dp1->hostnext) {
1978 run_server_scripts(EXECUTE_ON_POST_HOST_BACKUP,
1979 get_config_name(), dp1, -1);
1981 dp->host->post_script = 1;
1986 /* send the dumper result to the chunker */
1987 if (dumper->chunker) {
1988 if (dumper->chunker->down == 0 && dumper->chunker->fd != -1 &&
1989 dumper->chunker->result == LAST_TOK) {
1991 chunker_cmd(dumper->chunker, DONE, dp, NULL);
1994 chunker_cmd(dumper->chunker, FAILED, dp, NULL);
1997 if( dumper->result != LAST_TOK &&
1998 dumper->chunker->result != LAST_TOK)
1999 dumper_chunker_result(dp);
2000 } else { /* send the dumper result to the taper */
2001 if (taper_sendresult) {
2003 taper_cmd(DONE, dp, NULL, 0, NULL);
2005 taper_cmd(FAILED, dp, NULL, 0, NULL);
2007 taper_sendresult = 0;
2010 if (taper_dumper && taper_result != LAST_TOK) {
2011 dumper_taper_result(dp);
2013 } while(areads_dataready(dumper->fd));
2018 handle_chunker_result(
2021 chunker_t *chunker = cookie;
2022 assignedhd_t **h=NULL;
2032 assert(chunker != NULL);
2033 dumper = chunker->dumper;
2034 assert(dumper != NULL);
2037 assert(sched(dp) != NULL);
2038 assert(sched(dp)->destname != NULL);
2039 assert(dp != NULL && sched(dp) != NULL && sched(dp)->destname);
2041 if(sched(dp)->holdp) {
2042 h = sched(dp)->holdp;
2043 activehd = sched(dp)->activehd;
2049 cmd = getresult(chunker->fd, 1, &result_argc, &result_argv);
2052 /* result_argv[1] always contains the serial number */
2053 sdp = serial2disk(result_argv[1]);
2055 error(_("Invalid serial number %s"), result_argv[1]);
2056 g_assert_not_reached();
2062 case PARTIAL: /* PARTIAL <handle> <dumpsize> <errstr> */
2063 case DONE: /* DONE <handle> <dumpsize> <errstr> */
2064 if(result_argc != 4) {
2065 error(_("error [chunker %s result_argc != 4: %d]"), cmdstr[cmd],
2069 /*free_serial(result_argv[1]);*/
2071 sched(dp)->dumpsize = (off_t)atof(result_argv[2]);
2073 qname = quote_string(dp->name);
2074 g_printf(_("driver: finished-cmd time %s %s chunked %s:%s\n"),
2075 walltime_str(curclock()), chunker->name,
2076 dp->host->hostname, qname);
2080 event_release(chunker->ev_read);
2082 chunker->result = cmd;
2086 case TRYAGAIN: /* TRY-AGAIN <handle> <errstr> */
2087 event_release(chunker->ev_read);
2089 chunker->result = cmd;
2092 case FAILED: /* FAILED <handle> <errstr> */
2093 /*free_serial(result_argv[1]);*/
2095 event_release(chunker->ev_read);
2097 chunker->result = cmd;
2101 case NO_ROOM: /* NO-ROOM <handle> <missing_size> */
2102 if (!h || activehd < 0) { /* should never happen */
2103 error(_("!h || activehd < 0"));
2106 h[activehd]->used -= OFF_T_ATOI(result_argv[2]);
2107 h[activehd]->reserved -= OFF_T_ATOI(result_argv[2]);
2108 h[activehd]->disk->allocated_space -= OFF_T_ATOI(result_argv[2]);
2109 h[activehd]->disk->disksize -= OFF_T_ATOI(result_argv[2]);
2112 case RQ_MORE_DISK: /* RQ-MORE-DISK <handle> */
2113 if (!h || activehd < 0) { /* should never happen */
2114 error(_("!h || activehd < 0"));
2117 h[activehd]->disk->allocated_dumpers--;
2118 h[activehd]->used = h[activehd]->reserved;
2119 if( h[++activehd] ) { /* There's still some allocated space left.
2120 * Tell the dumper about it. */
2121 sched(dp)->activehd++;
2122 chunker_cmd( chunker, CONTINUE, dp, NULL );
2123 } else { /* !h[++activehd] - must allocate more space */
2124 sched(dp)->act_size = sched(dp)->est_size; /* not quite true */
2125 sched(dp)->est_size = (sched(dp)->act_size/(off_t)20) * (off_t)21; /* +5% */
2126 sched(dp)->est_size = am_round(sched(dp)->est_size, (off_t)DISK_BLOCK_KB);
2127 if (sched(dp)->est_size < sched(dp)->act_size + 2*DISK_BLOCK_KB)
2128 sched(dp)->est_size += 2 * DISK_BLOCK_KB;
2129 h = find_diskspace( sched(dp)->est_size - sched(dp)->act_size,
2133 /* No diskspace available. The reason for this will be
2134 * determined in continue_port_dumps(). */
2135 enqueue_disk( &roomq, dp );
2136 continue_port_dumps();
2137 /* continue flush waiting for new tape */
2140 /* OK, allocate space for disk and have chunker continue */
2141 sched(dp)->activehd = assign_holdingdisk( h, dp );
2142 chunker_cmd( chunker, CONTINUE, dp, NULL );
2148 case ABORT_FINISHED: /* ABORT-FINISHED <handle> */
2150 * We sent an ABORT from the NO-ROOM case because this dump
2151 * wasn't going to fit onto the holding disk. We now need to
2152 * clean up the remains of this image, and try to finish
2153 * other dumps that are waiting on disk space.
2155 /*assert(pending_aborts);*/
2157 /*free_serial(result_argv[1]);*/
2159 event_release(chunker->ev_read);
2161 chunker->result = cmd;
2166 /* either EOF or garbage from chunker. Turn it off */
2167 log_add(L_WARNING, _("%s pid %ld is messed up, ignoring it.\n"),
2168 chunker->name, (long)chunker->pid);
2170 /* if it was dumping something, zap it and try again */
2171 g_assert(h && activehd >= 0);
2172 qname = quote_string(dp->name);
2173 if(sched(dp)->dump_attempted) {
2174 log_add(L_FAIL, _("%s %s %s %d [%s died]"),
2175 dp->host->hostname, qname, sched(dp)->datestamp,
2176 sched(dp)->level, chunker->name);
2178 log_add(L_WARNING, _("%s died while dumping %s:%s lev %d."),
2179 chunker->name, dp->host->hostname, qname,
2185 event_release(chunker->ev_read);
2187 chunker->result = cmd;
2194 g_strfreev(result_argv);
2196 if(chunker->result != LAST_TOK && chunker->dumper->result != LAST_TOK)
2197 dumper_chunker_result(dp);
2199 } while(areads_dataready(chunker->fd));
2209 char *hostname, *diskname, *datestamp;
2213 char *inpline = NULL;
2219 char *qdestname = NULL;
2220 char *conf_infofile;
2222 tq.head = tq.tail = NULL;
2224 conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE));
2225 if (open_infofile(conf_infofile)) {
2226 error(_("could not open info db \"%s\""), conf_infofile);
2230 for(line = 0; (inpline = agets(stdin)) != NULL; free(inpline)) {
2234 if (inpline[0] == '\0')
2240 skip_whitespace(s, ch); /* find the command */
2242 error(_("flush line %d: syntax error (no command)"), line);
2246 skip_non_whitespace(s, ch);
2249 if(strcmp(command,"ENDFLUSH") == 0) {
2253 if(strcmp(command,"FLUSH") != 0) {
2254 error(_("flush line %d: syntax error (%s != FLUSH)"), line, command);
2258 skip_whitespace(s, ch); /* find the hostname */
2260 error(_("flush line %d: syntax error (no hostname)"), line);
2264 skip_non_whitespace(s, ch);
2267 skip_whitespace(s, ch); /* find the diskname */
2269 error(_("flush line %d: syntax error (no diskname)"), line);
2273 skip_quoted_string(s, ch);
2274 s[-1] = '\0'; /* terminate the disk name */
2275 diskname = unquote_string(qname);
2277 skip_whitespace(s, ch); /* find the datestamp */
2279 error(_("flush line %d: syntax error (no datestamp)"), line);
2283 skip_non_whitespace(s, ch);
2286 skip_whitespace(s, ch); /* find the level number */
2287 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2288 error(_("flush line %d: syntax error (bad level)"), line);
2291 skip_integer(s, ch);
2293 skip_whitespace(s, ch); /* find the filename */
2295 error(_("flush line %d: syntax error (no filename)"), line);
2299 skip_quoted_string(s, ch);
2301 destname = unquote_string(qdestname);
2303 holding_file_get_dumpfile(destname, &file);
2304 if( file.type != F_DUMPFILE) {
2305 if( file.type != F_CONT_DUMPFILE )
2306 log_add(L_INFO, _("%s: ignoring cruft file."), destname);
2309 dumpfile_free_data(&file);
2313 if(strcmp(hostname, file.name) != 0 ||
2314 strcmp(diskname, file.disk) != 0 ||
2315 strcmp(datestamp, file.datestamp) != 0) {
2316 log_add(L_INFO, _("disk %s:%s not consistent with file %s"),
2317 hostname, diskname, destname);
2320 dumpfile_free_data(&file);
2325 dp = lookup_disk(file.name, file.disk);
2328 log_add(L_INFO, _("%s: disk %s:%s not in database, skipping it."),
2329 destname, file.name, file.disk);
2331 dumpfile_free_data(&file);
2335 if(file.dumplevel < 0 || file.dumplevel > 9) {
2336 log_add(L_INFO, _("%s: ignoring file with bogus dump level %d."),
2337 destname, file.dumplevel);
2339 dumpfile_free_data(&file);
2343 if (holding_file_size(destname,1) <= 0) {
2344 log_add(L_INFO, "%s: removing file with no data.", destname);
2345 holding_file_unlink(destname);
2347 dumpfile_free_data(&file);
2351 dp1 = (disk_t *)alloc(SIZEOF(disk_t));
2353 dp1->next = dp1->prev = NULL;
2355 /* add it to the flushhost list */
2357 flushhost = alloc(SIZEOF(am_host_t));
2358 flushhost->next = NULL;
2359 flushhost->hostname = stralloc("FLUSHHOST");
2360 flushhost->up = NULL;
2361 flushhost->features = NULL;
2363 dp1->hostnext = flushhost->disks;
2364 flushhost->disks = dp1;
2366 sp = (sched_t *) alloc(SIZEOF(sched_t));
2367 sp->destname = destname;
2368 sp->level = file.dumplevel;
2369 sp->dumpdate = NULL;
2370 sp->degr_dumpdate = NULL;
2371 sp->degr_mesg = NULL;
2372 sp->datestamp = stralloc(file.datestamp);
2373 sp->est_nsize = (off_t)0;
2374 sp->est_csize = (off_t)0;
2377 sp->origsize = file.orig_size;
2379 sp->degr_level = -1;
2380 sp->dump_attempted = 0;
2381 sp->taper_attempted = 0;
2382 sp->act_size = holding_file_size(destname, 0);
2383 sp->holdp = build_diskspace(destname);
2384 if(sp->holdp == NULL) continue;
2386 sp->timestamp = (time_t)0;
2388 dp1->up = (char *)sp;
2390 enqueue_disk(&tq, dp1);
2391 dumpfile_free_data(&file);
2405 int level, line, priority;
2406 char *dumpdate, *degr_dumpdate, *degr_mesg;
2408 time_t time, degr_time;
2409 time_t *time_p = &time;
2410 time_t *degr_time_p = °r_time;
2411 off_t nsize, csize, degr_nsize, degr_csize;
2412 unsigned long kps, degr_kps;
2413 char *hostname, *features, *diskname, *datestamp, *inpline = NULL;
2417 off_t flush_size = (off_t)0;
2422 long long degr_nsize_;
2423 long long degr_csize_;
2424 GPtrArray *errarray;
2426 (void)cookie; /* Quiet unused parameter warning */
2428 event_release(schedule_ev_read);
2430 /* read schedule from stdin */
2432 for(line = 0; (inpline = agets(stdin)) != NULL; free(inpline)) {
2433 if (inpline[0] == '\0')
2440 skip_whitespace(s, ch); /* find the command */
2442 error(_("schedule line %d: syntax error (no command)"), line);
2446 skip_non_whitespace(s, ch);
2449 if(strcmp(command,"DUMP") != 0) {
2450 error(_("schedule line %d: syntax error (%s != DUMP)"), line, command);
2454 skip_whitespace(s, ch); /* find the host name */
2456 error(_("schedule line %d: syntax error (no host name)"), line);
2460 skip_non_whitespace(s, ch);
2463 skip_whitespace(s, ch); /* find the feature list */
2465 error(_("schedule line %d: syntax error (no feature list)"), line);
2469 skip_non_whitespace(s, ch);
2472 skip_whitespace(s, ch); /* find the disk name */
2474 error(_("schedule line %d: syntax error (no disk name)"), line);
2478 skip_quoted_string(s, ch);
2479 s[-1] = '\0'; /* terminate the disk name */
2480 diskname = unquote_string(qname);
2482 skip_whitespace(s, ch); /* find the datestamp */
2484 error(_("schedule line %d: syntax error (no datestamp)"), line);
2488 skip_non_whitespace(s, ch);
2491 skip_whitespace(s, ch); /* find the priority number */
2492 if(ch == '\0' || sscanf(s - 1, "%d", &priority) != 1) {
2493 error(_("schedule line %d: syntax error (bad priority)"), line);
2496 skip_integer(s, ch);
2498 skip_whitespace(s, ch); /* find the level number */
2499 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2500 error(_("schedule line %d: syntax error (bad level)"), line);
2503 skip_integer(s, ch);
2505 skip_whitespace(s, ch); /* find the dump date */
2507 error(_("schedule line %d: syntax error (bad dump date)"), line);
2511 skip_non_whitespace(s, ch);
2514 skip_whitespace(s, ch); /* find the native size */
2516 if(ch == '\0' || sscanf(s - 1, "%lld", &nsize_) != 1) {
2517 error(_("schedule line %d: syntax error (bad nsize)"), line);
2520 nsize = (off_t)nsize_;
2521 skip_integer(s, ch);
2523 skip_whitespace(s, ch); /* find the compressed size */
2525 if(ch == '\0' || sscanf(s - 1, "%lld", &csize_) != 1) {
2526 error(_("schedule line %d: syntax error (bad csize)"), line);
2529 csize = (off_t)csize_;
2530 skip_integer(s, ch);
2532 skip_whitespace(s, ch); /* find the time number */
2533 if(ch == '\0' || sscanf(s - 1, "%lld", &time_) != 1) {
2534 error(_("schedule line %d: syntax error (bad estimated time)"), line);
2537 *time_p = (time_t)time_;
2538 skip_integer(s, ch);
2540 skip_whitespace(s, ch); /* find the kps number */
2541 if(ch == '\0' || sscanf(s - 1, "%lu", &kps) != 1) {
2542 error(_("schedule line %d: syntax error (bad kps)"), line);
2545 skip_integer(s, ch);
2547 degr_dumpdate = NULL; /* flag if degr fields found */
2548 skip_whitespace(s, ch); /* find the degr level number */
2552 skip_quoted_string(s, ch);
2553 s[-1] = '\0'; /* terminate degr mesg */
2554 degr_mesg = unquote_string(qname);
2556 degr_nsize = (off_t)0;
2557 degr_csize = (off_t)0;
2558 degr_time = (time_t)0;
2560 } else if (ch != '\0') {
2561 if(sscanf(s - 1, "%d", °r_level) != 1) {
2562 error(_("schedule line %d: syntax error (bad degr level)"), line);
2565 skip_integer(s, ch);
2567 skip_whitespace(s, ch); /* find the degr dump date */
2569 error(_("schedule line %d: syntax error (bad degr dump date)"), line);
2572 degr_dumpdate = s - 1;
2573 skip_non_whitespace(s, ch);
2576 skip_whitespace(s, ch); /* find the degr native size */
2577 degr_nsize_ = (off_t)0;
2578 if(ch == '\0' || sscanf(s - 1, "%lld", °r_nsize_) != 1) {
2579 error(_("schedule line %d: syntax error (bad degr nsize)"), line);
2582 degr_nsize = (off_t)degr_nsize_;
2583 skip_integer(s, ch);
2585 skip_whitespace(s, ch); /* find the degr compressed size */
2586 degr_csize_ = (off_t)0;
2587 if(ch == '\0' || sscanf(s - 1, "%lld", °r_csize_) != 1) {
2588 error(_("schedule line %d: syntax error (bad degr csize)"), line);
2591 degr_csize = (off_t)degr_csize_;
2592 skip_integer(s, ch);
2594 skip_whitespace(s, ch); /* find the degr time number */
2595 if(ch == '\0' || sscanf(s - 1, "%lld", &time_) != 1) {
2596 error(_("schedule line %d: syntax error (bad degr estimated time)"), line);
2599 *degr_time_p = (time_t)time_;
2600 skip_integer(s, ch);
2602 skip_whitespace(s, ch); /* find the degr kps number */
2603 if(ch == '\0' || sscanf(s - 1, "%lu", °r_kps) != 1) {
2604 error(_("schedule line %d: syntax error (bad degr kps)"), line);
2607 skip_integer(s, ch);
2609 error(_("schedule line %d: no degraded estimate or message"), line);
2612 dp = lookup_disk(hostname, diskname);
2615 _("schedule line %d: %s:'%s' not in disklist, ignored"),
2616 line, hostname, qname);
2621 sp = (sched_t *) alloc(SIZEOF(sched_t));
2624 sp->dumpdate = stralloc(dumpdate);
2625 sp->est_nsize = DISK_BLOCK_KB + nsize; /* include header */
2626 sp->est_csize = DISK_BLOCK_KB + csize; /* include header */
2627 /* round estimate to next multiple of DISK_BLOCK_KB */
2628 sp->est_csize = am_round(sp->est_csize, DISK_BLOCK_KB);
2629 sp->est_size = sp->est_csize;
2630 sp->est_time = time;
2632 sp->priority = priority;
2633 sp->datestamp = stralloc(datestamp);
2636 sp->degr_level = degr_level;
2637 sp->degr_dumpdate = stralloc(degr_dumpdate);
2638 sp->degr_nsize = DISK_BLOCK_KB + degr_nsize;
2639 sp->degr_csize = DISK_BLOCK_KB + degr_csize;
2640 /* round estimate to next multiple of DISK_BLOCK_KB */
2641 sp->degr_csize = am_round(sp->degr_csize, DISK_BLOCK_KB);
2642 sp->degr_time = degr_time;
2643 sp->degr_kps = degr_kps;
2644 sp->degr_mesg = NULL;
2646 sp->degr_level = -1;
2647 sp->degr_dumpdate = NULL;
2648 sp->degr_mesg = degr_mesg;
2652 sp->dump_attempted = 0;
2653 sp->taper_attempted = 0;
2658 sp->timestamp = (time_t)0;
2659 sp->destname = NULL;
2662 dp->up = (char *) sp;
2663 if(dp->host->features == NULL) {
2664 dp->host->features = am_string_to_feature(features);
2665 if (!dp->host->features) {
2667 _("Invalid feature string from client '%s'"),
2669 dp->host->features = am_set_default_feature_set();
2672 remove_disk(&waitq, dp);
2674 errarray = validate_optionstr(dp);
2675 if (errarray->len > 0) {
2677 for (i=0; i < errarray->len; i++) {
2678 log_add(L_FAIL, _("%s %s %s 0 [%s]"),
2679 dp->host->hostname, qname,
2681 (char *)g_ptr_array_index(errarray, i));
2686 if (dp->data_path == DATA_PATH_DIRECTTCP &&
2687 dp->to_holdingdisk == HOLD_AUTO) {
2688 /* planner already logged a warning. */
2689 dp->to_holdingdisk = HOLD_NEVER;
2692 if (dp->to_holdingdisk == HOLD_NEVER) {
2693 enqueue_disk(&directq, dp);
2695 enqueue_disk(&runq, dp);
2697 flush_size += sp->act_size;
2701 g_printf(_("driver: flush size %lld\n"), (long long)flush_size);
2704 log_add(L_WARNING, _("WARNING: got empty schedule from planner"));
2705 if(need_degraded==1) start_degraded_mode(&runq);
2707 start_some_dumps(&runq);
2711 static unsigned long
2719 unsigned long maxusage=0;
2720 unsigned long curusage=0;
2721 for(p = disklist_netifs(); p != NULL; p = p->next) {
2722 maxusage += interface_get_maxusage(p->config);
2723 curusage += p->curusage;
2725 if (maxusage >= curusage)
2726 res = maxusage - curusage;
2731 if ((unsigned long)interface_get_maxusage(ip->config) >= ip->curusage)
2732 res = interface_get_maxusage(ip->config) - ip->curusage;
2747 g_printf(_("driver: interface-state time %s"), time_str);
2749 for(ip = disklist_netifs(); ip != NULL; ip = ip->next) {
2750 g_printf(_(" if %s: free %lu"), interface_name(ip->config), free_kps(ip));
2760 ip->curusage += kps;
2764 deallocate_bandwidth(
2768 assert(kps <= ip->curusage);
2769 ip->curusage -= kps;
2780 total_free = (off_t)0;
2781 for(ha = holdalloc; ha != NULL; ha = ha->next) {
2782 diff = ha->disksize - ha->allocated_space;
2790 * We return an array of pointers to assignedhd_t. The array contains at
2791 * most one entry per holding disk. The list of pointers is terminated by
2792 * a NULL pointer. Each entry contains a pointer to a holdingdisk and
2793 * how much diskspace to use on that disk. Later on, assign_holdingdisk
2794 * will allocate the given amount of space.
2795 * If there is not enough room on the holdingdisks, NULL is returned.
2798 static assignedhd_t **
2802 assignedhd_t * pref)
2804 assignedhd_t **result = NULL;
2805 holdalloc_t *ha, *minp;
2809 off_t halloc, dalloc, hfree, dfree;
2811 (void)cur_idle; /* Quiet unused parameter warning */
2813 if (size < 2*DISK_BLOCK_KB)
2814 size = 2*DISK_BLOCK_KB;
2815 size = am_round(size, (off_t)DISK_BLOCK_KB);
2817 hold_debug(1, _("find_diskspace: want %lld K\n"),
2820 used = alloc(SIZEOF(*used) * num_holdalloc);/*disks used during this run*/
2821 memset( used, 0, (size_t)num_holdalloc );
2822 result = alloc(SIZEOF(assignedhd_t *) * (num_holdalloc + 1));
2825 while( i < num_holdalloc && size > (off_t)0 ) {
2826 /* find the holdingdisk with the fewest active dumpers and among
2827 * those the one with the biggest free space
2829 minp = NULL; minj = -1;
2830 for(j = 0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
2831 if( pref && pref->disk == ha && !used[j] &&
2832 ha->allocated_space <= ha->disksize - (off_t)DISK_BLOCK_KB) {
2837 else if( ha->allocated_space <= ha->disksize - (off_t)(2*DISK_BLOCK_KB) &&
2840 ha->allocated_dumpers < minp->allocated_dumpers ||
2841 (ha->allocated_dumpers == minp->allocated_dumpers &&
2842 ha->disksize-ha->allocated_space > minp->disksize-minp->allocated_space)) ) {
2849 if( !minp ) { break; } /* all holding disks are full */
2852 /* hfree = free space on the disk */
2853 hfree = minp->disksize - minp->allocated_space;
2855 /* dfree = free space for data, remove 1 header for each chunksize */
2856 dfree = hfree - (((hfree-(off_t)1)/holdingdisk_get_chunksize(minp->hdisk))+(off_t)1) * (off_t)DISK_BLOCK_KB;
2858 /* dalloc = space I can allocate for data */
2859 dalloc = ( dfree < size ) ? dfree : size;
2861 /* halloc = space to allocate, including 1 header for each chunksize */
2862 halloc = dalloc + (((dalloc-(off_t)1)/holdingdisk_get_chunksize(minp->hdisk))+(off_t)1) * (off_t)DISK_BLOCK_KB;
2864 hold_debug(1, _("find_diskspace: find diskspace: size %lld hf %lld df %lld da %lld ha %lld\n"),
2871 result[i] = alloc(SIZEOF(assignedhd_t));
2872 result[i]->disk = minp;
2873 result[i]->reserved = halloc;
2874 result[i]->used = (off_t)0;
2875 result[i]->destname = NULL;
2881 if(size != (off_t)0) { /* not enough space available */
2882 g_printf(_("find diskspace: not enough diskspace. Left with %lld K\n"), (long long)size);
2884 free_assignedhd(result);
2888 if (debug_holding > 1) {
2889 for( i = 0; result && result[i]; i++ ) {
2890 hold_debug(1, _("find_diskspace: find diskspace: selected %s free %lld reserved %lld dumpers %d\n"),
2891 holdingdisk_get_diskdir(result[i]->disk->hdisk),
2892 (long long)(result[i]->disk->disksize -
2893 result[i]->disk->allocated_space),
2894 (long long)result[i]->reserved,
2895 result[i]->disk->allocated_dumpers);
2904 assignedhd_t ** holdp,
2909 char *sfn = sanitise_filename(diskp->name);
2911 assignedhd_t **new_holdp;
2914 g_snprintf( lvl, SIZEOF(lvl), "%d", sched(diskp)->level );
2916 size = am_round(sched(diskp)->est_size - sched(diskp)->act_size,
2917 (off_t)DISK_BLOCK_KB);
2919 for( c = 0; holdp[c]; c++ )
2920 (void)c; /* count number of disks */
2922 /* allocate memory for sched(diskp)->holdp */
2923 for(j = 0; sched(diskp)->holdp && sched(diskp)->holdp[j]; j++)
2924 (void)j; /* Quiet lint */
2925 new_holdp = (assignedhd_t **)alloc(SIZEOF(assignedhd_t*)*(j+c+1));
2926 if (sched(diskp)->holdp) {
2927 memcpy(new_holdp, sched(diskp)->holdp, j * SIZEOF(*new_holdp));
2928 amfree(sched(diskp)->holdp);
2930 sched(diskp)->holdp = new_holdp;
2934 if( j > 0 ) { /* This is a request for additional diskspace. See if we can
2935 * merge assignedhd_t's */
2937 if( sched(diskp)->holdp[j-1]->disk == holdp[0]->disk ) { /* Yes! */
2938 sched(diskp)->holdp[j-1]->reserved += holdp[0]->reserved;
2939 holdp[0]->disk->allocated_space += holdp[0]->reserved;
2940 size = (holdp[0]->reserved>size) ? (off_t)0 : size-holdp[0]->reserved;
2941 qname = quote_string(diskp->name);
2942 hold_debug(1, _("assign_holdingdisk: merging holding disk %s to disk %s:%s, add %lld for reserved %lld, left %lld\n"),
2943 holdingdisk_get_diskdir(
2944 sched(diskp)->holdp[j-1]->disk->hdisk),
2945 diskp->host->hostname, qname,
2946 (long long)holdp[0]->reserved,
2947 (long long)sched(diskp)->holdp[j-1]->reserved,
2956 /* copy assignedhd_s to sched(diskp), adjust allocated_space */
2957 for( ; holdp[i]; i++ ) {
2958 holdp[i]->destname = newvstralloc( holdp[i]->destname,
2959 holdingdisk_get_diskdir(holdp[i]->disk->hdisk), "/",
2960 hd_driver_timestamp, "/",
2961 diskp->host->hostname, ".",
2964 sched(diskp)->holdp[j++] = holdp[i];
2965 holdp[i]->disk->allocated_space += holdp[i]->reserved;
2966 size = (holdp[i]->reserved > size) ? (off_t)0 :
2967 (size - holdp[i]->reserved);
2968 qname = quote_string(diskp->name);
2970 _("assign_holdingdisk: %d assigning holding disk %s to disk %s:%s, reserved %lld, left %lld\n"),
2971 i, holdingdisk_get_diskdir(holdp[i]->disk->hdisk),
2972 diskp->host->hostname, qname,
2973 (long long)holdp[i]->reserved,
2976 holdp[i] = NULL; /* so it doesn't get free()d... */
2978 sched(diskp)->holdp[j] = NULL;
2989 assignedhd_t **holdp;
2990 off_t total = (off_t)0;
2993 char *qname, *hqname, *qdest;
2995 (void)cmd; /* Quiet unused parameter warning */
2997 qname = quote_string(diskp->name);
2998 qdest = quote_string(sched(diskp)->destname);
2999 hold_debug(1, _("adjust_diskspace: %s:%s %s\n"),
3000 diskp->host->hostname, qname, qdest);
3002 holdp = sched(diskp)->holdp;
3004 assert(holdp != NULL);
3006 for( i = 0; holdp[i]; i++ ) { /* for each allocated disk */
3007 diff = holdp[i]->used - holdp[i]->reserved;
3008 total += holdp[i]->used;
3009 holdp[i]->disk->allocated_space += diff;
3010 hqname = quote_string(holdingdisk_name(holdp[i]->disk->hdisk));
3011 hold_debug(1, _("adjust_diskspace: hdisk %s done, reserved %lld used %lld diff %lld alloc %lld dumpers %d\n"),
3012 holdingdisk_name(holdp[i]->disk->hdisk),
3013 (long long)holdp[i]->reserved,
3014 (long long)holdp[i]->used,
3016 (long long)holdp[i]->disk->allocated_space,
3017 holdp[i]->disk->allocated_dumpers );
3018 holdp[i]->reserved += diff;
3022 sched(diskp)->act_size = total;
3024 hold_debug(1, _("adjust_diskspace: after: disk %s:%s used %lld\n"),
3025 diskp->host->hostname, qname,
3026 (long long)sched(diskp)->act_size);
3035 assignedhd_t **holdp;
3038 holdp = sched(diskp)->holdp;
3040 assert(holdp != NULL);
3042 for( i = 0; holdp[i]; i++ ) { /* for each disk */
3043 /* find all files of this dump on that disk, and subtract their
3044 * reserved sizes from the disk's allocated space
3046 holdp[i]->disk->allocated_space -= holdp[i]->used;
3049 holding_file_unlink(holdp[0]->destname); /* no need for the entire list,
3050 * because holding_file_unlink
3051 * will walk through all files
3052 * using cont_filename */
3053 free_assignedhd(sched(diskp)->holdp);
3054 sched(diskp)->holdp = NULL;
3055 sched(diskp)->act_size = (off_t)0;
3058 static assignedhd_t **
3065 char buffer[DISK_BLOCK_BYTES];
3067 assignedhd_t **result;
3070 char dirname[1000], *ch;
3072 char *filename = destname;
3074 memset(buffer, 0, sizeof(buffer));
3075 used = alloc(SIZEOF(off_t) * num_holdalloc);
3076 for(i=0;i<num_holdalloc;i++)
3078 result = alloc(SIZEOF(assignedhd_t *) * (num_holdalloc + 1));
3080 while(filename != NULL && filename[0] != '\0') {
3081 strncpy(dirname, filename, 999);
3083 ch = strrchr(dirname,'/');
3086 ch = strrchr(dirname,'/');
3093 g_fprintf(stderr,_("build_diskspace: bogus filename '%s'\n"), filename);
3099 for(j = 0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3100 if(strcmp(dirname, holdingdisk_get_diskdir(ha->hdisk))==0) {
3105 if(stat(filename, &finfo) == -1) {
3106 g_fprintf(stderr, _("stat %s: %s\n"), filename, strerror(errno));
3107 finfo.st_size = (off_t)0;
3109 used[j] += ((off_t)finfo.st_size+(off_t)1023)/(off_t)1024;
3110 if((fd = open(filename,O_RDONLY)) == -1) {
3111 g_fprintf(stderr,_("build_diskspace: open of %s failed: %s\n"),
3112 filename, strerror(errno));
3117 if ((buflen = full_read(fd, buffer, SIZEOF(buffer))) > 0) {;
3118 parse_file_header(buffer, &file, buflen);
3121 filename = file.cont_filename;
3124 for(j = 0, i=0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3125 if(used[j] != (off_t)0) {
3126 result[i] = alloc(SIZEOF(assignedhd_t));
3127 result[i]->disk = ha;
3128 result[i]->reserved = used[j];
3129 result[i]->used = used[j];
3130 result[i]->destname = stralloc(destname);
3148 g_printf(_("driver: hdisk-state time %s"), time_str);
3150 for(ha = holdalloc, dsk = 0; ha != NULL; ha = ha->next, dsk++) {
3151 diff = ha->disksize - ha->allocated_space;
3152 g_printf(_(" hdisk %d: free %lld dumpers %d"), dsk,
3153 (long long)diff, ha->allocated_dumpers);
3162 time_t save_timestamp = sched(dp)->timestamp;
3163 /* setting timestamp to 0 removes the current level from the
3164 * database, so that we ensure that it will not be bumped to the
3165 * next level on the next run. If we didn't do this, dumpdates or
3166 * gnutar-lists might have been updated already, and a bumped
3167 * incremental might be created. */
3168 sched(dp)->timestamp = 0;
3169 update_info_dumper(dp, (off_t)-1, (off_t)-1, (time_t)-1);
3170 sched(dp)->timestamp = save_timestamp;
3173 /* ------------------- */
3185 qname = quote_string(dp->name);
3186 g_printf(_("driver: dumping %s:%s directly to tape\n"),
3187 dp->host->hostname, qname);
3190 /* pick a dumper and fail if there are no idle dumpers */
3192 dumper = idle_dumper();
3194 g_printf(_("driver: no idle dumpers for %s:%s.\n"),
3195 dp->host->hostname, qname);
3197 log_add(L_WARNING, _("no idle dumpers for %s:%s.\n"),
3198 dp->host->hostname, qname);
3200 return; /* fatal problem */
3203 /* tell the taper to read from a port number of its choice */
3205 taper_cmd(PORT_WRITE, dp, NULL, sched(dp)->level, sched(dp)->datestamp);
3206 cmd = getresult(taper, 1, &result_argc, &result_argv);
3208 g_printf(_("driver: did not get PORT from taper for %s:%s\n"),
3209 dp->host->hostname, qname);
3211 log_add(L_WARNING, _("driver: did not get PORT from taper for %s:%s.\n"),
3212 dp->host->hostname, qname);
3214 return; /* fatal problem */
3218 /* copy port number */
3219 dumper->output_port = atoi(result_argv[1]);
3220 amfree(dp->dataport_list);
3221 dp->dataport_list = stralloc(result_argv[2]);
3224 dumper->chunker = NULL;
3225 dumper->result = LAST_TOK;
3226 taper_result = LAST_TOK;
3227 sched(dp)->dumper = dumper;
3229 if (dp->host->pre_script == 0) {
3230 for (dp1=dp->host->disks; dp1 != NULL; dp1 = dp1->hostnext) {
3231 run_server_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
3232 get_config_name(), dp1, -1);
3234 dp->host->pre_script = 1;
3236 run_server_scripts(EXECUTE_ON_PRE_DLE_BACKUP, get_config_name(), dp,
3239 /* tell the dumper to dump to a port */
3240 dumper_cmd(dumper, PORT_DUMP, dp, NULL);
3241 dp->host->start_t = time(NULL) + 15;
3242 amfree(dp->dataport_list);
3244 /* update statistics & print state */
3246 taper_busy = dumper->busy = 1;
3247 taper_input_error = NULL;
3248 taper_tape_error = NULL;
3249 taper_dumper = dumper;
3251 taper_first_label = NULL;
3253 taper_state |= TAPER_STATE_DUMP_TO_TAPE;
3254 sched(dp)->act_size = sched(dp)->est_size;
3255 dp->host->inprogress += 1;
3257 sched(dp)->timestamp = time((time_t *)0);
3258 allocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
3259 idle_reason = NOT_IDLE;
3263 dumper->ev_read = event_register(dumper->fd, EV_READFD,
3264 handle_dumper_result, dumper);
3265 taper_ev_read = event_register(taper, EV_READFD,
3266 handle_taper_result, NULL);
3268 g_strfreev(result_argv);
3278 for(len = 0, p = q.head; p != NULL; len++, p = p->next)
3279 (void)len; /* Quiet lint */
3284 short_dump_state(void)
3289 wall_time = walltime_str(curclock());
3291 g_printf(_("driver: state time %s "), wall_time);
3292 g_printf(_("free kps: %lu space: %lld taper: "),
3294 (long long)free_space());
3295 if(degraded_mode) g_printf(_("DOWN"));
3296 else if(!taper_busy) g_printf(_("idle"));
3297 else g_printf(_("writing"));
3299 for(i = 0; i < inparallel; i++) if(!dmptable[i].busy) nidle++;
3300 g_printf(_(" idle-dumpers: %d"), nidle);
3301 g_printf(_(" qlen tapeq: %d"), queue_length(tapeq));
3302 g_printf(_(" runq: %d"), queue_length(runq));
3303 g_printf(_(" roomq: %d"), queue_length(roomq));
3304 g_printf(_(" wakeup: %d"), (int)sleep_time);
3305 g_printf(_(" driver-idle: %s\n"), _(idle_strings[idle_reason]));
3306 interface_state(wall_time);
3307 holdingdisk_state(wall_time);
3311 static TapeAction tape_action(char **why_no_new_tape)
3313 TapeAction result = TAPE_ACTION_NO_ACTION;
3321 off_t dump_to_disk_size;
3322 int dump_to_disk_terminated;
3325 for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
3327 dumpers_size += sched(dumper->dp)->est_size;
3329 driver_debug(1, _("dumpers_size: %lld\n"), (long long)dumpers_size);
3332 for(dp = runq.head; dp != NULL; dp = dp->next) {
3333 runq_size += sched(dp)->est_size;
3335 driver_debug(1, _("runq_size: %lld\n"), (long long)runq_size);
3338 for(dp = directq.head; dp != NULL; dp = dp->next) {
3339 directq_size += sched(dp)->est_size;
3341 driver_debug(1, _("directq_size: %lld\n"), (long long)directq_size);
3344 for(dp = tapeq.head; dp != NULL; dp = dp->next) {
3345 tapeq_size += sched(dp)->act_size;
3348 tapeq_size += sched(taper_disk)->act_size - taper_written;
3350 driver_debug(1, _("tapeq_size: %lld\n"), (long long)tapeq_size);
3352 sched_size = runq_size + tapeq_size + dumpers_size;
3353 driver_debug(1, _("sched_size: %lld\n"), (long long)sched_size);
3355 dump_to_disk_size = dumpers_size + runq_size;
3356 driver_debug(1, _("dump_to_disk_size: %lld\n"), (long long)dump_to_disk_size);
3358 dump_to_disk_terminated = schedule_done && dump_to_disk_size == 0;
3360 // Changing conditionals can produce a driver hang, take care.
3362 // when to start writting to a new tape
3363 if ((taper_state & TAPER_STATE_WAIT_FOR_TAPE) &&
3364 ((taper_state & TAPER_STATE_DUMP_TO_TAPE) || // for dump to tape
3365 !empty(directq) || // if a dle is waiting for a dump to tape
3366 !empty(roomq) || // holding disk constraint
3367 idle_reason == IDLE_NO_DISKSPACE || // holding disk constraint
3368 (flush_threshold_dumped < tapeq_size && // flush-threshold-dumped &&
3369 flush_threshold_scheduled < sched_size) || // flush-threshold-scheduled
3370 (taperflush < tapeq_size && // taperflush
3371 (force_flush == 1 || // if force_flush
3372 dump_to_disk_terminated)) // or all dump to disk terminated
3374 result |= TAPE_ACTION_NEW_TAPE;
3375 // when to stop using new tape
3376 } else if ((taper_state & TAPER_STATE_WAIT_FOR_TAPE) &&
3377 (taperflush >= tapeq_size && // taperflush criteria not meet
3378 (force_flush == 1 || // if force_flush
3379 dump_to_disk_terminated)) // or all dump to disk terminated
3381 result |= TAPE_ACTION_NO_NEW_TAPE;
3382 *why_no_new_tape = _("taperflush criteria not met");
3385 // when to start a flush
3386 // We don't start a flush if taper_tape_started == 1 && dump_to_disk_terminated && force_flush == 0,
3387 // it is a criteria need to exit the first event_loop without flushing everything to tape,
3388 // they will be flush in another event_loop.
3389 if (!degraded_mode && !taper_busy && !empty(tapeq) &&
3390 (!((taper_state & TAPER_STATE_TAPE_STARTED) &&
3391 dump_to_disk_terminated && force_flush == 0) || // if tape already started and dump to disk not terminated
3392 ((taper_state & TAPER_STATE_TAPE_STARTED) &&
3393 force_flush == 1) || // if tape already started and force_flush
3394 !empty(roomq) || // holding disk constraint
3395 idle_reason == IDLE_NO_DISKSPACE || // holding disk constraint
3396 (flush_threshold_dumped < tapeq_size && // flush-threshold-dumped &&
3397 flush_threshold_scheduled < sched_size) || // flush-threshold-scheduled
3398 (force_flush == 1 && taperflush < tapeq_size))) { // taperflush if force_flush
3399 result |= TAPE_ACTION_START_A_FLUSH;
3413 g_printf("================\n");
3414 g_printf(_("driver state at time %s: %s\n"), walltime_str(curclock()), str);
3415 g_printf(_("free kps: %lu, space: %lld\n"),
3417 (long long)free_space());
3418 if(degraded_mode) g_printf(_("taper: DOWN\n"));
3419 else if(!taper_busy) g_printf(_("taper: idle\n"));
3420 else g_printf(_("taper: writing %s:%s.%d est size %lld\n"),
3421 taper_disk->host->hostname, taper_disk->name,
3422 sched(taper_disk)->level,
3423 (long long)sched(taper_disk)->est_size);
3424 for(i = 0; i < inparallel; i++) {
3425 dp = dmptable[i].dp;
3426 if(!dmptable[i].busy)
3427 g_printf(_("%s: idle\n"), dmptable[i].name);
3429 qname = quote_string(dp->name);
3430 g_printf(_("%s: dumping %s:%s.%d est kps %d size %lld time %lu\n"),
3431 dmptable[i].name, dp->host->hostname, qname, sched(dp)->level,
3432 sched(dp)->est_kps, (long long)sched(dp)->est_size, sched(dp)->est_time);
3435 dump_queue("TAPE", tapeq, 5, stdout);
3436 dump_queue("ROOM", roomq, 5, stdout);
3437 dump_queue("RUN ", runq, 5, stdout);
3438 g_printf("================\n");