2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: driver.c 6512 2007-05-24 17:00:24Z ian $
30 * controlling process for the Amanda backup system
34 * XXX possibly modify tape queue to be cognizant of how much room is left on
35 * tape. Probably not effective though, should do this in planner.
49 #include "server_util.h"
50 #include "timestamp.h"
52 #define driver_debug(i, ...) do { \
53 if ((i) <= debug_driver) { \
54 dbprintf(__VA_ARGS__); \
58 #define hold_debug(i, ...) do { \
59 if ((i) <= debug_holding) { \
60 dbprintf(__VA_ARGS__); \
64 static disklist_t waitq; // dle waiting estimate result
65 static disklist_t runq; // dle waiting to be dumped to holding disk
66 static disklist_t directq; // dle waiting to be dumped directly to tape
67 static disklist_t tapeq; // dle on holding disk waiting to be written
69 static disklist_t roomq; // dle waiting for more space on holding disk
70 static int pending_aborts;
71 static int degraded_mode;
72 static off_t reserved_space;
73 static off_t total_disksize;
74 static char *dumper_program;
75 static char *chunker_program;
76 static int inparallel;
77 static int nodump = 0;
78 static off_t tape_length = (off_t)0;
79 static int current_tape = 0;
80 static int conf_max_dle_by_volume;
81 static int conf_taperalgo;
82 static int conf_taper_parallel_write;
83 static int conf_runtapes;
84 static time_t sleep_time;
85 static int idle_reason;
86 static char *driver_timestamp;
87 static char *hd_driver_timestamp;
88 static am_host_t *flushhost = NULL;
89 static int need_degraded=0;
90 static holdalloc_t *holdalloc;
91 static int num_holdalloc;
92 static event_handle_t *dumpers_ev_time = NULL;
93 static event_handle_t *flush_ev_read = NULL;
94 static event_handle_t *schedule_ev_read = NULL;
95 static int conf_flush_threshold_dumped;
96 static int conf_flush_threshold_scheduled;
97 static int conf_taperflush;
98 static off_t flush_threshold_dumped;
99 static off_t flush_threshold_scheduled;
100 static off_t taperflush;
101 static int schedule_done; // 1 if we don't wait for a
102 // schedule from the planner
103 static int force_flush; // All dump are terminated, we
104 // must now respect taper_flush
105 static int taper_nb_scan_volume = 0;
106 static int nb_sent_new_tape = 0;
107 static int taper_started = 0;
108 static taper_t *last_started_taper;
110 static int wait_children(int count);
111 static void wait_for_children(void);
112 static void allocate_bandwidth(netif_t *ip, unsigned long kps);
113 static int assign_holdingdisk(assignedhd_t **holdp, disk_t *diskp);
114 static void adjust_diskspace(disk_t *diskp, cmd_t cmd);
115 static void delete_diskspace(disk_t *diskp);
116 static assignedhd_t **build_diskspace(char *destname);
117 static int client_constrained(disk_t *dp);
118 static void deallocate_bandwidth(netif_t *ip, unsigned long kps);
119 static void dump_schedule(disklist_t *qp, char *str);
120 static assignedhd_t **find_diskspace(off_t size, int *cur_idle,
121 assignedhd_t *preferred);
122 static unsigned long free_kps(netif_t *ip);
123 static off_t free_space(void);
124 static void dumper_chunker_result(disk_t *dp);
125 static void dumper_taper_result(disk_t *dp);
126 static void file_taper_result(disk_t *dp);
127 static void handle_dumper_result(void *);
128 static void handle_chunker_result(void *);
129 static void handle_dumpers_time(void *);
130 static void handle_taper_result(void *);
132 static void holdingdisk_state(char *time_str);
133 static taper_t *idle_taper(void);
134 static taper_t *taper_from_name(char *name);
135 static void interface_state(char *time_str);
136 static int queue_length(disklist_t q);
137 static void read_flush(void *cookie);
138 static void read_schedule(void *cookie);
139 static void short_dump_state(void);
140 static void startaflush(void);
141 static void start_degraded_mode(disklist_t *queuep);
142 static void start_some_dumps(disklist_t *rq);
143 static void continue_port_dumps(void);
144 static void update_failed_dump(disk_t *);
145 static int no_taper_flushing(void);
146 static int active_dumper(void);
149 TAPE_ACTION_NO_ACTION = 0,
150 TAPE_ACTION_SCAN = (1 << 0),
151 TAPE_ACTION_NEW_TAPE = (1 << 1),
152 TAPE_ACTION_NO_NEW_TAPE = (1 << 2),
153 TAPE_ACTION_START_A_FLUSH = (1 << 3),
154 TAPE_ACTION_START_A_FLUSH_FIT = (1 << 4),
155 TAPE_ACTION_MOVE = (1 << 5)
158 static TapeAction tape_action(taper_t *taper, char **why_no_new_tape);
160 static const char *idle_strings[] = {
163 #define IDLE_NO_DUMPERS 1
165 #define IDLE_START_WAIT 2
167 #define IDLE_NO_HOLD 3
169 #define IDLE_CLIENT_CONSTRAINED 4
170 T_("client-constrained"),
171 #define IDLE_NO_BANDWIDTH 5
173 #define IDLE_NO_DISKSPACE 6
187 struct fs_usage fsusage;
190 unsigned long reserve = 100;
198 config_overrides_t *cfg_ovr = NULL;
199 char *cfg_opt = NULL;
200 holdalloc_t *ha, *ha_last;
201 find_result_t *holding_files;
202 disklist_t holding_disklist = { NULL, NULL };
203 int no_taper = FALSE;
204 int from_client = FALSE;
206 if (argc > 1 && argv && argv[1] && g_str_equal(argv[1], "--version")) {
207 printf("driver-%s\n", VERSION);
212 * Configure program for internationalization:
213 * 1) Only set the message locale for now.
214 * 2) Set textdomain for all amanda related programs to "amanda"
215 * We don't want to be forced to support dozens of message catalogs.
217 setlocale(LC_MESSAGES, "C");
218 textdomain("amanda");
222 setvbuf(stdout, (char *)NULL, (int)_IOLBF, 0);
223 setvbuf(stderr, (char *)NULL, (int)_IOLBF, 0);
227 dbopen(DBG_SUBDIR_SERVER);
229 atexit(wait_for_children);
231 /* Don't die when child closes pipe */
232 signal(SIGPIPE, SIG_IGN);
234 add_amanda_log_handler(amanda_log_stderr);
235 add_amanda_log_handler(amanda_log_trace_log);
239 cfg_ovr = extract_commandline_config_overrides(&argc, &argv);
243 set_config_overrides(cfg_ovr);
244 config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
246 conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
247 read_diskfile(conf_diskfile, &origq);
248 disable_skip_disk(&origq);
249 amfree(conf_diskfile);
251 if (config_errors(NULL) >= CFGERR_WARNINGS) {
252 config_print_errors();
253 if (config_errors(NULL) >= CFGERR_ERRORS) {
254 g_critical(_("errors processing config file"));
258 log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
259 g_printf(_("%s: pid %ld executable %s version %s\n"),
260 get_pname(), (long) getpid(), argv[0], VERSION);
263 if(strcmp(argv[2], "nodump") == 0) {
271 if (strcmp(argv[2], "--no-taper") == 0) {
279 if (strcmp(argv[2], "--from-client") == 0) {
281 from_client = from_client;
287 safe_cd(); /* do this *after* config_init */
289 check_running_as(RUNNING_AS_DUMPUSER);
291 dbrename(get_config_name(), DBG_SUBDIR_SERVER);
293 /* load DLEs from the holding disk, in case there's anything to flush there */
294 search_holding_disk(&holding_files, &holding_disklist);
295 /* note that the dumps are added to the global disklist, so we need not consult
296 * holding_files or holding_disklist after this */
298 amfree(driver_timestamp);
299 /* read timestamp from stdin */
300 while ((line = agets(stdin)) != NULL) {
305 if ( line == NULL ) {
306 error(_("Did not get DATE line from planner"));
309 driver_timestamp = alloc(15);
310 strncpy(driver_timestamp, &line[5], 14);
311 driver_timestamp[14] = '\0';
313 log_add(L_START,_("date %s"), driver_timestamp);
315 gethostname(hostname, SIZEOF(hostname));
316 log_add(L_STATS,_("hostname %s"), hostname);
318 /* check that we don't do many dump in a day and usetimestamps is off */
319 if(strlen(driver_timestamp) == 8) {
321 char *conf_logdir = getconf_str(CNF_LOGDIR);
322 char *logfile = vstralloc(conf_logdir, "/log.",
323 driver_timestamp, ".0", NULL);
324 char *oldlogfile = vstralloc(conf_logdir, "/oldlog/log.",
325 driver_timestamp, ".0", NULL);
326 if(access(logfile, F_OK) == 0 || access(oldlogfile, F_OK) == 0) {
327 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."));
332 hd_driver_timestamp = get_timestamp_from_time(0);
335 hd_driver_timestamp = stralloc(driver_timestamp);
338 taper_program = vstralloc(amlibexecdir, "/", "taper", NULL);
339 dumper_program = vstralloc(amlibexecdir, "/", "dumper", NULL);
340 chunker_program = vstralloc(amlibexecdir, "/", "chunker", NULL);
342 conf_taperalgo = getconf_taperalgo(CNF_TAPERALGO);
343 conf_taper_parallel_write = getconf_int(CNF_TAPER_PARALLEL_WRITE);
344 conf_tapetype = getconf_str(CNF_TAPETYPE);
345 conf_runtapes = getconf_int(CNF_RUNTAPES);
346 conf_max_dle_by_volume = getconf_int(CNF_MAX_DLE_BY_VOLUME);
347 if (conf_taper_parallel_write > conf_runtapes) {
348 conf_taper_parallel_write = conf_runtapes;
350 tape = lookup_tapetype(conf_tapetype);
351 tape_length = tapetype_get_length(tape);
352 g_printf("driver: tape size %lld\n", (long long)tape_length);
353 conf_flush_threshold_dumped = getconf_int(CNF_FLUSH_THRESHOLD_DUMPED);
354 conf_flush_threshold_scheduled = getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED);
355 conf_taperflush = getconf_int(CNF_TAPERFLUSH);
356 flush_threshold_dumped = (conf_flush_threshold_dumped * tape_length) / 100;
357 flush_threshold_scheduled = (conf_flush_threshold_scheduled * tape_length) / 100;
358 taperflush = (conf_taperflush *tape_length) / 100;
360 driver_debug(1, _("flush-threshold-dumped: %lld\n"), (long long)flush_threshold_dumped);
361 driver_debug(1, _("flush-threshold-scheduled: %lld\n"), (long long)flush_threshold_scheduled);
362 driver_debug(1, _("taperflush: %lld\n"), (long long)taperflush);
364 /* set up any configuration-dependent variables */
366 inparallel = getconf_int(CNF_INPARALLEL);
368 reserve = (unsigned long)getconf_int(CNF_RESERVE);
370 total_disksize = (off_t)0;
373 for (il = getconf_identlist(CNF_HOLDINGDISK), dsk = 0;
375 il = il->next, dsk++) {
376 hdp = lookup_holdingdisk(il->data);
377 ha = alloc(SIZEOF(holdalloc_t));
380 /* link the list in the same order as getconf_holdingdisks's results */
389 ha->allocated_dumpers = 0;
390 ha->allocated_space = (off_t)0;
391 ha->disksize = holdingdisk_get_disksize(hdp);
394 if(get_fs_usage(holdingdisk_get_diskdir(hdp), NULL, &fsusage) == -1
395 || access(holdingdisk_get_diskdir(hdp), W_OK) == -1) {
396 log_add(L_WARNING, _("WARNING: ignoring holding disk %s: %s\n"),
397 holdingdisk_get_diskdir(hdp), strerror(errno));
402 /* do the division first to avoid potential integer overflow */
403 if (fsusage.fsu_bavail_top_bit_set)
406 kb_avail = fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize;
408 if(ha->disksize > (off_t)0) {
409 if(ha->disksize > kb_avail) {
411 _("WARNING: %s: %lld KB requested, "
412 "but only %lld KB available."),
413 holdingdisk_get_diskdir(hdp),
414 (long long)ha->disksize,
415 (long long)kb_avail);
416 ha->disksize = kb_avail;
419 /* ha->disksize is negative; use all but that amount */
420 else if(kb_avail < -ha->disksize) {
422 _("WARNING: %s: not %lld KB free."),
423 holdingdisk_get_diskdir(hdp),
424 (long long)-ha->disksize);
425 ha->disksize = (off_t)0;
429 ha->disksize += kb_avail;
431 g_printf(_("driver: adding holding disk %d dir %s size %lld chunksize %lld\n"),
432 dsk, holdingdisk_get_diskdir(hdp),
433 (long long)ha->disksize,
434 (long long)(holdingdisk_get_chunksize(hdp)));
436 newdir = newvstralloc(newdir,
437 holdingdisk_get_diskdir(hdp), "/", hd_driver_timestamp,
439 if(!mkholdingdir(newdir)) {
440 ha->disksize = (off_t)0;
442 total_disksize += ha->disksize;
445 reserved_space = total_disksize * (off_t)(reserve / 100);
447 g_printf(_("reserving %lld out of %lld for degraded-mode dumps\n"),
448 (long long)reserved_space, (long long)free_space());
452 if(inparallel > MAX_DUMPERS) inparallel = MAX_DUMPERS;
454 /* taper takes a while to get going, so start it up right away */
457 startup_tape_process(taper_program, conf_taper_parallel_write, no_taper);
459 /* fire up the dumpers now while we are waiting */
460 if(!nodump) startup_dump_processes(dumper_program, inparallel, driver_timestamp);
463 * Read schedule from stdin. Usually, this is a pipe from planner,
464 * so the effect is that we wait here for the planner to
465 * finish, but meanwhile the taper is rewinding the tape, reading
466 * the label, checking it, writing a new label and all that jazz
467 * in parallel with the planner.
479 taper_nb_wait_reply = 0;
482 if (no_taper || conf_runtapes <= 0) {
483 taper_started = 1; /* we'll pretend the taper started and failed immediately */
486 tapetable[0].state = TAPER_STATE_INIT;
487 taper_nb_wait_reply++;
488 taper_nb_scan_volume++;
489 taper_ev_read = event_register(taper_fd, EV_READFD,
490 handle_taper_result, NULL);
491 taper_cmd(START_TAPER, NULL, tapetable[0].name, 0, driver_timestamp);
494 flush_ev_read = event_register((event_id_t)0, EV_READFD, read_flush, NULL);
496 log_add(L_STATS, _("startup time %s"), walltime_str(curclock()));
498 g_printf(_("driver: start time %s inparallel %d bandwidth %lu diskspace %lld "), walltime_str(curclock()), inparallel,
499 free_kps(NULL), (long long)free_space());
500 g_printf(_(" dir %s datestamp %s driver: drain-ends tapeq %s big-dumpers %s\n"),
501 "OBSOLETE", driver_timestamp, taperalgo2str(conf_taperalgo),
502 getconf_str(CNF_DUMPORDER));
505 schedule_done = nodump;
513 /* mv runq to directq */
514 while (!empty(runq)) {
515 diskp = dequeue_disk(&runq);
516 headqueue_disk(&directq, diskp);
519 run_server_global_scripts(EXECUTE_ON_POST_BACKUP, get_config_name());
521 /* log error for any remaining dumps */
522 while(!empty(directq)) {
523 diskp = dequeue_disk(&directq);
525 if (diskp->to_holdingdisk == HOLD_REQUIRED) {
526 char *qname = quote_string(diskp->name);
527 log_add(L_FAIL, "%s %s %s %d [%s]",
528 diskp->host->hostname, qname, sched(diskp)->datestamp,
530 _("can't dump required holdingdisk"));
533 else if (!degraded_mode) {
534 char *qname = quote_string(diskp->name);
535 log_add(L_FAIL, "%s %s %s %d [%s]",
536 diskp->host->hostname, qname, sched(diskp)->datestamp,
538 _("can't dump in non degraded mode"));
542 char *qname = quote_string(diskp->name);
543 log_add(L_FAIL, "%s %s %s %d [%s]",
544 diskp->host->hostname, qname, sched(diskp)->datestamp,
547 _("can't do degraded dump without holding disk") :
548 diskp->to_holdingdisk != HOLD_NEVER ?
549 _("out of holding space in degraded mode") :
550 _("can't dump 'holdingdisk never' dle in degraded mode"));
555 short_dump_state(); /* for amstatus */
557 g_printf(_("driver: QUITTING time %s telling children to quit\n"),
558 walltime_str(curclock()));
562 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
564 dumper_cmd(dumper, QUIT, NULL, NULL);
569 taper_cmd(QUIT, NULL, NULL, 0, NULL);
572 /* wait for all to die */
576 holding_cleanup(NULL, NULL);
580 check_unfree_serial();
581 g_printf(_("driver: FINISHED time %s\n"), walltime_str(curclock()));
583 log_add(L_FINISH,_("date %s time %s"), driver_timestamp, walltime_str(curclock()));
584 log_add(L_INFO, "pid-done %ld", (long)getpid());
585 amfree(driver_timestamp);
587 amfree(dumper_program);
588 amfree(taper_program);
595 /* sleep up to count seconds, and wait for terminating child process */
596 /* if sleep is negative, this function will not timeout */
597 /* exit once all child process are finished or the timout expired */
598 /* return 0 if no more children to wait */
599 /* return 1 if some children are still alive */
601 wait_children(int count)
613 pid = waitpid((pid_t)-1, &retstat, WNOHANG);
617 if (! WIFEXITED(retstat)) {
619 code = WTERMSIG(retstat);
620 } else if (WEXITSTATUS(retstat) != 0) {
622 code = WEXITSTATUS(retstat);
625 for (dumper = dmptable; dumper < dmptable + inparallel;
627 if (pid == dumper->pid) {
628 who = stralloc(dumper->name);
632 if (dumper->chunker && pid == dumper->chunker->pid) {
633 who = stralloc(dumper->chunker->name);
634 dumper->chunker->pid = -1;
638 if (who == NULL && pid == taper_pid) {
639 who = stralloc("taper");
642 if(what != NULL && who == NULL) {
643 who = stralloc("unknown");
646 log_add(L_WARNING, _("%s pid %u exited with %s %d\n"), who,
647 (unsigned)pid, what, code);
648 g_printf(_("driver: %s pid %u exited with %s %d\n"), who,
649 (unsigned)pid, what, code);
653 } while (pid > 0 || wait_errno == EINTR);
658 } while ((errno != ECHILD) && (count != 0));
659 return (errno != ECHILD);
663 kill_children(int signal)
668 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
669 if (!dumper->down && dumper->pid > 1) {
670 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
671 dumper->name, (unsigned)dumper->pid);
672 if (kill(dumper->pid, signal) == -1 && errno == ESRCH) {
674 dumper->chunker->pid = 0;
676 if (dumper->chunker && dumper->chunker->pid > 1) {
677 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
678 dumper->chunker->name,
679 (unsigned)dumper->chunker->pid);
680 if (kill(dumper->chunker->pid, signal) == -1 &&
682 dumper->chunker->pid = 0;
689 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
690 "taper", (unsigned)taper_pid);
691 if (kill(taper_pid, signal) == -1 && errno == ESRCH)
697 wait_for_children(void)
702 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
703 if (dumper->pid > 1 && dumper->fd >= 0) {
704 dumper_cmd(dumper, QUIT, NULL, NULL);
705 if (dumper->chunker && dumper->chunker->pid > 1 &&
706 dumper->chunker->fd >= 0)
707 chunker_cmd(dumper->chunker, QUIT, NULL, NULL);
712 if(taper_pid > 1 && taper_fd > 0) {
713 taper_cmd(QUIT, NULL, NULL, 0, NULL);
716 if(wait_children(60) == 0)
719 kill_children(SIGHUP);
720 if(wait_children(60) == 0)
723 kill_children(SIGKILL);
724 if(wait_children(-1) == 0)
729 static void startaflush_tape(taper_t *taper, gboolean *state_changed);
735 gboolean state_changed = FALSE;
737 for(taper = tapetable; taper <= tapetable+conf_taper_parallel_write;
739 if (!(taper->state & TAPER_STATE_DONE) &&
740 taper->state & TAPER_STATE_WAIT_FOR_TAPE) {
741 startaflush_tape(taper, &state_changed);
744 for(taper = tapetable; taper <= tapetable+conf_taper_parallel_write;
746 if (!(taper->state & TAPER_STATE_DONE) &&
747 taper->state & TAPER_STATE_TAPE_REQUESTED) {
748 startaflush_tape(taper, &state_changed);
751 for(taper = tapetable; taper <= tapetable+conf_taper_parallel_write;
753 if (!(taper->state & TAPER_STATE_DONE) &&
754 taper->state & TAPER_STATE_INIT) {
755 startaflush_tape(taper, &state_changed);
758 for(taper = tapetable; taper <= tapetable+conf_taper_parallel_write;
760 if (!(taper->state & TAPER_STATE_DONE) &&
761 taper->state & TAPER_STATE_IDLE) {
762 startaflush_tape(taper, &state_changed);
773 gboolean *state_changed)
778 off_t extra_tapes_size = 0;
781 TapeAction result_tape_action;
782 char *why_no_new_tape = NULL;
785 result_tape_action = tape_action(taper, &why_no_new_tape);
787 if (result_tape_action & TAPE_ACTION_SCAN) {
788 taper->state &= ~TAPER_STATE_TAPE_REQUESTED;
789 taper->state |= TAPER_STATE_WAIT_FOR_TAPE;
790 taper_nb_scan_volume++;
791 taper_cmd(START_SCAN, taper->disk, NULL, 0, NULL);
792 } else if (result_tape_action & TAPE_ACTION_NEW_TAPE) {
793 taper->state &= ~TAPER_STATE_WAIT_FOR_TAPE;
794 taper->state |= TAPER_STATE_WAIT_NEW_TAPE;
796 taper_cmd(NEW_TAPE, taper->disk, NULL, 0, NULL);
797 } else if (result_tape_action & TAPE_ACTION_NO_NEW_TAPE) {
798 taper->state &= ~TAPER_STATE_WAIT_FOR_TAPE;
799 taper_cmd(NO_NEW_TAPE, taper->disk, why_no_new_tape, 0, NULL);
800 taper->state |= TAPER_STATE_DONE;
801 start_degraded_mode(&runq);
802 *state_changed = TRUE;
803 } else if (result_tape_action & TAPE_ACTION_MOVE) {
804 taper_t *taper1 = idle_taper();
806 taper->state &= ~TAPER_STATE_TAPE_REQUESTED;
807 taper->state &= ~TAPER_STATE_WAIT_FOR_TAPE;
808 taper_cmd(TAKE_SCRIBE_FROM, taper->disk, taper1->name, 0 , NULL);
809 taper1->state = TAPER_STATE_DEFAULT;
810 taper->state |= TAPER_STATE_TAPE_STARTED;
811 taper->left = taper1->left;
813 if (last_started_taper == taper1) {
814 last_started_taper = taper;
816 *state_changed = TRUE;
820 if (!degraded_mode &&
821 taper->state & TAPER_STATE_IDLE &&
823 (result_tape_action & TAPE_ACTION_START_A_FLUSH ||
824 result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT)) {
826 int taperalgo = conf_taperalgo;
827 if (result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT) {
828 if (taperalgo == ALGO_FIRST)
829 taperalgo = ALGO_FIRSTFIT;
830 else if (taperalgo == ALGO_LARGEST)
831 taperalgo = ALGO_LARGESTFIT;
832 else if (taperalgo == ALGO_SMALLEST)
833 taperalgo = ALGO_SMALLESTFIT;
834 else if (taperalgo == ALGO_LAST)
835 taperalgo = ALGO_LASTFIT;
838 extra_tapes_size = tape_length * (off_t)(conf_runtapes - current_tape);
839 for (taper1 = tapetable; taper1 < tapetable + conf_taper_parallel_write;
841 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
842 extra_tapes_size += taper1->left;
846 extra_tapes_size -= (sched(dp)->act_size - taper1->written);
850 if (taper->state & TAPER_STATE_TAPE_STARTED) {
851 taper_left = taper->left;
853 taper_left = tape_length;
856 datestamp = sched(tapeq.head)->datestamp;
859 dp = dequeue_disk(&tapeq);
863 while (fit != NULL) {
864 if (sched(fit)->act_size <=
865 (fit->splitsize ? extra_tapes_size : taper_left) &&
866 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
874 if(dp) remove_disk(&tapeq, dp);
877 fit = dp = tapeq.head;
878 while (fit != NULL) {
879 if(sched(fit)->act_size > sched(dp)->act_size &&
880 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
885 if(dp) remove_disk(&tapeq, dp);
887 case ALGO_LARGESTFIT:
889 while (fit != NULL) {
890 if(sched(fit)->act_size <=
891 (fit->splitsize ? extra_tapes_size : taper_left) &&
892 (!dp || sched(fit)->act_size > sched(dp)->act_size) &&
893 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
898 if(dp) remove_disk(&tapeq, dp);
901 fit = dp = tapeq.head;
902 while (fit != NULL) {
903 if (sched(fit)->act_size < sched(dp)->act_size &&
904 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
909 if(dp) remove_disk(&tapeq, dp);
911 case ALGO_SMALLESTFIT:
912 fit = dp = tapeq.head;
913 while (fit != NULL) {
914 if (sched(fit)->act_size <=
915 (fit->splitsize ? extra_tapes_size : taper_left) &&
916 (!dp || sched(fit)->act_size < sched(dp)->act_size) &&
917 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
922 if(dp) remove_disk(&tapeq, dp);
926 remove_disk(&tapeq, dp);
930 while (fit != NULL) {
931 if (sched(fit)->act_size <=
932 (fit->splitsize ? extra_tapes_size : taper_left) &&
933 (!dp || sched(fit)->act_size < sched(dp)->act_size) &&
934 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
939 if(dp) remove_disk(&tapeq, dp);
943 if (!(result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT)) {
944 if(conf_taperalgo != ALGO_SMALLEST) {
946 _("driver: startaflush: Using SMALLEST because nothing fit\n"));
949 fit = dp = tapeq.head;
950 while (fit != NULL) {
951 if (sched(fit)->act_size < sched(dp)->act_size &&
952 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
957 if(dp) remove_disk(&tapeq, dp);
962 taper->dumper = NULL;
963 amfree(taper->input_error);
964 amfree(taper->tape_error);
965 taper->result = LAST_TOK;
966 taper->sendresult = 0;
967 amfree(taper->first_label);
969 taper->state &= ~TAPER_STATE_IDLE;
970 taper->state |= TAPER_STATE_FILE_TO_TAPE;
971 taper->dumper = NULL;
972 qname = quote_string(dp->name);
973 if (taper_nb_wait_reply == 0) {
974 taper_ev_read = event_register(taper_fd, EV_READFD,
975 handle_taper_result, NULL);
977 taper_nb_wait_reply++;
979 sched(dp)->taper = taper;
980 taper_cmd(FILE_WRITE, dp, sched(dp)->destname, sched(dp)->level,
981 sched(dp)->datestamp);
982 g_fprintf(stderr,_("driver: startaflush: %s %s %s %lld %lld\n"),
983 taperalgo2str(taperalgo), dp->host->hostname, qname,
984 (long long)sched(taper->disk)->act_size,
985 (long long)taper->left);
987 *state_changed = TRUE;
998 /* first, check if host is too busy */
1000 if(dp->host->inprogress >= dp->host->maxdumps) {
1004 /* next, check conflict with other dumps on same spindle */
1006 if(dp->spindle == -1) { /* but spindle -1 never conflicts by def. */
1010 for(dp2 = dp->host->disks; dp2 != NULL; dp2 = dp2->hostnext)
1011 if(dp2->inprogress && dp2->spindle == dp->spindle) {
1025 int dumper_to_holding,
1027 disk_t **delayed_diskp,
1028 disk_t **diskp_accept,
1029 assignedhd_t ***holdp_accept,
1030 off_t extra_tapes_size)
1032 assignedhd_t **holdp=NULL;
1034 if (diskp->host->start_t > now) {
1035 *cur_idle = max(*cur_idle, IDLE_START_WAIT);
1036 if (*delayed_diskp == NULL || sleep_time > diskp->host->start_t) {
1037 *delayed_diskp = diskp;
1038 sleep_time = diskp->host->start_t;
1040 } else if(diskp->start_t > now) {
1041 *cur_idle = max(*cur_idle, IDLE_START_WAIT);
1042 if (*delayed_diskp == NULL || sleep_time > diskp->start_t) {
1043 *delayed_diskp = diskp;
1044 sleep_time = diskp->start_t;
1046 } else if (diskp->host->netif->curusage > 0 &&
1047 sched(diskp)->est_kps > free_kps(diskp->host->netif)) {
1048 *cur_idle = max(*cur_idle, IDLE_NO_BANDWIDTH);
1049 } else if (!taper && sched(diskp)->no_space) {
1050 *cur_idle = max(*cur_idle, IDLE_NO_DISKSPACE);
1051 } else if (!taper && diskp->to_holdingdisk == HOLD_NEVER) {
1052 *cur_idle = max(*cur_idle, IDLE_NO_HOLD);
1053 } else if (extra_tapes_size && sched(diskp)->est_size > extra_tapes_size) {
1054 *cur_idle = max(*cur_idle, IDLE_NO_DISKSPACE);
1056 } else if (!taper && (holdp =
1057 find_diskspace(sched(diskp)->est_size, cur_idle, NULL)) == NULL) {
1058 *cur_idle = max(*cur_idle, IDLE_NO_DISKSPACE);
1059 if (empty(tapeq) && dumper_to_holding == 0 && rq != &directq && no_taper_flushing()) {
1060 remove_disk(rq, diskp);
1061 if (diskp->to_holdingdisk != HOLD_REQUIRED) {
1062 enqueue_disk(&directq, diskp);
1063 diskp->to_holdingdisk = HOLD_NEVER;
1065 if (empty(*rq) && active_dumper() == 0) { force_flush = 1;}
1067 } else if (client_constrained(diskp)) {
1068 free_assignedhd(holdp);
1069 *cur_idle = max(*cur_idle, IDLE_CLIENT_CONSTRAINED);
1072 /* disk fits, dump it */
1073 int accept = !*diskp_accept;
1076 case 's': accept = (sched(diskp)->est_size < sched(*diskp_accept)->est_size);
1078 case 'S': accept = (sched(diskp)->est_size > sched(*diskp_accept)->est_size);
1080 case 't': accept = (sched(diskp)->est_time < sched(*diskp_accept)->est_time);
1082 case 'T': accept = (sched(diskp)->est_time > sched(*diskp_accept)->est_time);
1084 case 'b': accept = (sched(diskp)->est_kps < sched(*diskp_accept)->est_kps);
1086 case 'B': accept = (sched(diskp)->est_kps > sched(*diskp_accept)->est_kps);
1088 default: log_add(L_WARNING, _("Unknown dumporder character \'%c\', using 's'.\n"),
1090 accept = (sched(diskp)->est_size < sched(*diskp_accept)->est_size);
1095 if( !*diskp_accept || !degraded_mode || diskp->priority >= (*diskp_accept)->priority) {
1096 if(*holdp_accept) free_assignedhd(*holdp_accept);
1097 *diskp_accept = diskp;
1098 *holdp_accept = holdp;
1101 free_assignedhd(holdp);
1105 free_assignedhd(holdp);
1114 const time_t now = time(NULL);
1116 disk_t *diskp, *delayed_diskp, *diskp_accept, *diskp_next;
1118 assignedhd_t **holdp=NULL, **holdp_accept;
1127 int dumper_to_holding = 0;
1128 gboolean state_changed = FALSE;
1130 /* don't start any actual dumps until the taper is started */
1131 if (!taper_started) return;
1133 idle_reason = IDLE_NO_DUMPERS;
1136 if(dumpers_ev_time != NULL) {
1137 event_release(dumpers_ev_time);
1138 dumpers_ev_time = NULL;
1141 for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
1142 if (dumper->busy && dumper->dp->to_holdingdisk != HOLD_NEVER) {
1143 dumper_to_holding++;
1146 for (dumper = dmptable; dumper < dmptable+inparallel; dumper++) {
1148 if( dumper->busy || dumper->down) {
1152 if (dumper->ev_read != NULL) {
1153 event_release(dumper->ev_read);
1154 dumper->ev_read = NULL;
1158 * A potential problem with starting from the bottom of the dump time
1159 * distribution is that a slave host will have both one of the shortest
1160 * and one of the longest disks, so starting its shortest disk first will
1161 * tie up the host and eliminate its longest disk from consideration the
1162 * first pass through. This could cause a big delay in starting that long
1163 * disk, which could drag out the whole night's dumps.
1165 * While starting from the top of the dump time distribution solves the
1166 * above problem, this turns out to be a bad idea, because the big dumps
1167 * will almost certainly pack the holding disk completely, leaving no
1168 * room for even one small dump to start. This ends up shutting out the
1169 * small-end dumpers completely (they stay idle).
1171 * The introduction of multiple simultaneous dumps to one host alleviates
1172 * the biggest&smallest dumps problem: both can be started at the
1176 diskp_accept = NULL;
1177 holdp_accept = NULL;
1178 delayed_diskp = NULL;
1180 cur_idle = NOT_IDLE;
1182 dumporder = getconf_str(CNF_DUMPORDER);
1183 if(strlen(dumporder) > (size_t)(dumper-dmptable)) {
1184 dumptype = dumporder[dumper-dmptable];
1187 if(dumper-dmptable < 3)
1195 if (!empty(directq)) {
1196 taper = idle_taper();
1198 TapeAction result_tape_action;
1199 char *why_no_new_tape = NULL;
1200 result_tape_action = tape_action(taper, &why_no_new_tape);
1201 if (result_tape_action & TAPE_ACTION_START_A_FLUSH ||
1202 result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT) {
1203 off_t extra_tapes_size = 0;
1206 if (result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT) {
1207 extra_tapes_size = tape_length *
1208 (off_t)(conf_runtapes - current_tape);
1209 for (taper1 = tapetable;
1210 taper1 < tapetable + conf_taper_parallel_write;
1212 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
1213 extra_tapes_size += taper1->left;
1217 extra_tapes_size -= (sched(dp)->est_size -
1223 for (diskp = directq.head; diskp != NULL;
1224 diskp = diskp_next) {
1225 diskp_next = diskp->next;
1226 allow_dump_dle(diskp, taper, dumptype, &directq, now,
1227 dumper_to_holding, &cur_idle,
1228 &delayed_diskp, &diskp_accept,
1229 &holdp_accept, extra_tapes_size);
1232 diskp = diskp_accept;
1233 holdp = holdp_accept;
1243 if (diskp == NULL) {
1244 for(diskp = rq->head; diskp != NULL; diskp = diskp_next) {
1245 diskp_next = diskp->next;
1246 assert(diskp->host != NULL && sched(diskp) != NULL);
1248 allow_dump_dle(diskp, NULL, dumptype, rq, now,
1249 dumper_to_holding, &cur_idle, &delayed_diskp,
1250 &diskp_accept, &holdp_accept, 0);
1252 diskp = diskp_accept;
1253 holdp = holdp_accept;
1256 idle_reason = max(idle_reason, cur_idle);
1257 if (diskp == NULL && idle_reason == IDLE_NO_DISKSPACE) {
1258 /* continue flush waiting for new tape */
1263 * If we have no disk at this point, and there are disks that
1264 * are delayed, then schedule a time event to call this dumper
1265 * with the disk with the shortest delay.
1267 if (diskp == NULL && delayed_diskp != NULL) {
1268 assert(sleep_time > now);
1270 dumpers_ev_time = event_register((event_id_t)sleep_time, EV_TIME,
1271 handle_dumpers_time, &runq);
1273 } else if (diskp != NULL && taper == NULL) {
1274 sched(diskp)->act_size = (off_t)0;
1275 allocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1276 sched(diskp)->activehd = assign_holdingdisk(holdp, diskp);
1278 sched(diskp)->destname = newstralloc(sched(diskp)->destname,
1279 sched(diskp)->holdp[0]->destname);
1280 diskp->host->inprogress++; /* host is now busy */
1281 diskp->inprogress = 1;
1282 sched(diskp)->dumper = dumper;
1283 sched(diskp)->timestamp = now;
1284 amfree(diskp->dataport_list);
1286 dumper->busy = 1; /* dumper is now busy */
1287 dumper->dp = diskp; /* link disk to dumper */
1288 remove_disk(rq, diskp); /* take it off the run queue */
1290 sched(diskp)->origsize = (off_t)-1;
1291 sched(diskp)->dumpsize = (off_t)-1;
1292 sched(diskp)->dumptime = (time_t)0;
1293 sched(diskp)->tapetime = (time_t)0;
1294 chunker = dumper->chunker = &chktable[dumper - dmptable];
1295 chunker->result = LAST_TOK;
1296 dumper->result = LAST_TOK;
1297 startup_chunk_process(chunker,chunker_program);
1298 chunker_cmd(chunker, START, NULL, driver_timestamp);
1299 chunker->dumper = dumper;
1300 chunker_cmd(chunker, PORT_WRITE, diskp, NULL);
1301 cmd = getresult(chunker->fd, 1, &result_argc, &result_argv);
1303 assignedhd_t **h=NULL;
1305 char *qname = quote_string(diskp->name);
1307 g_printf(_("driver: did not get PORT from %s for %s:%s\n"),
1308 chunker->name, diskp->host->hostname, qname);
1312 deallocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1313 h = sched(diskp)->holdp;
1314 activehd = sched(diskp)->activehd;
1315 h[activehd]->used = 0;
1316 h[activehd]->disk->allocated_dumpers--;
1317 adjust_diskspace(diskp, DONE);
1318 delete_diskspace(diskp);
1319 diskp->host->inprogress--;
1320 diskp->inprogress = 0;
1321 sched(diskp)->dumper = NULL;
1324 sched(diskp)->dump_attempted++;
1325 free_serial_dp(diskp);
1326 if(sched(diskp)->dump_attempted < 2)
1327 enqueue_disk(rq, diskp);
1330 dumper->ev_read = event_register((event_id_t)dumper->fd, EV_READFD,
1331 handle_dumper_result, dumper);
1332 chunker->ev_read = event_register((event_id_t)chunker->fd, EV_READFD,
1333 handle_chunker_result, chunker);
1334 dumper->output_port = atoi(result_argv[1]);
1335 amfree(diskp->dataport_list);
1336 diskp->dataport_list = stralloc(result_argv[2]);
1338 if (diskp->host->pre_script == 0) {
1339 run_server_host_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
1340 get_config_name(), diskp->host);
1341 diskp->host->pre_script = 1;
1343 run_server_dle_scripts(EXECUTE_ON_PRE_DLE_BACKUP,
1344 get_config_name(), diskp,
1345 sched(diskp)->level);
1346 dumper_cmd(dumper, PORT_DUMP, diskp, NULL);
1348 diskp->host->start_t = now + 5;
1349 if (empty(*rq) && active_dumper() == 0) { force_flush = 1;}
1352 g_strfreev(result_argv);
1354 } else if (diskp != NULL && taper != NULL) { /* dump to tape */
1355 sched(diskp)->act_size = (off_t)0;
1356 allocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1357 diskp->host->inprogress++; /* host is now busy */
1358 diskp->inprogress = 1;
1359 sched(diskp)->dumper = dumper;
1360 sched(diskp)->taper = taper;
1361 sched(diskp)->timestamp = now;
1362 dumper->chunker = NULL;
1363 amfree(diskp->dataport_list);
1365 dumper->busy = 1; /* dumper is now busy */
1366 dumper->dp = diskp; /* link disk to dumper */
1367 remove_disk(&directq, diskp); /* take it off the direct queue */
1369 sched(diskp)->origsize = (off_t)-1;
1370 sched(diskp)->dumpsize = (off_t)-1;
1371 sched(diskp)->dumptime = (time_t)0;
1372 sched(diskp)->tapetime = (time_t)0;
1373 dumper->result = LAST_TOK;
1374 taper->result = LAST_TOK;
1375 taper->input_error = NULL;
1376 taper->tape_error = NULL;
1377 taper->disk = diskp;
1378 taper->first_label = NULL;
1380 taper->dumper = dumper;
1381 taper->state |= TAPER_STATE_DUMP_TO_TAPE;
1382 taper->state &= ~TAPER_STATE_IDLE;
1384 if (taper_nb_wait_reply == 0) {
1385 taper_ev_read = event_register(taper_fd, EV_READFD,
1386 handle_taper_result, NULL);
1389 taper_nb_wait_reply++;
1390 taper_cmd(PORT_WRITE, diskp, NULL, sched(diskp)->level,
1391 sched(diskp)->datestamp);
1392 diskp->host->start_t = now + 5;
1394 state_changed = TRUE;
1397 if (state_changed) {
1403 * This gets called when a dumper is delayed for some reason. It may
1404 * be because a disk has a delayed start, or amanda is constrained
1405 * by network or disk limits.
1409 handle_dumpers_time(
1412 disklist_t *runq = cookie;
1413 event_release(dumpers_ev_time);
1414 dumpers_ev_time = NULL;
1415 start_some_dumps(runq);
1426 g_printf(_("dump of driver schedule %s:\n--------\n"), str);
1428 for(dp = qp->head; dp != NULL; dp = dp->next) {
1429 qname = quote_string(dp->name);
1430 g_printf(" %-20s %-25s lv %d t %5lu s %lld p %d\n",
1431 dp->host->hostname, qname, sched(dp)->level,
1432 sched(dp)->est_time,
1433 (long long)sched(dp)->est_size, sched(dp)->priority);
1436 g_printf("--------\n");
1440 start_degraded_mode(
1441 /*@keep@*/ disklist_t *queuep)
1445 off_t est_full_size;
1449 if (need_degraded == 0) {
1450 for(taper = tapetable;
1451 taper < tapetable+conf_taper_parallel_write;
1453 if (!(taper->state & TAPER_STATE_DONE))
1459 if (!schedule_done || degraded_mode) {
1463 if (need_degraded == 0) {
1464 for(taper = tapetable;
1465 taper < tapetable+conf_taper_parallel_write;
1467 if (!(taper->state & TAPER_STATE_DONE))
1473 newq.head = newq.tail = 0;
1475 dump_schedule(queuep, _("before start degraded mode"));
1477 est_full_size = (off_t)0;
1478 while(!empty(*queuep)) {
1479 dp = dequeue_disk(queuep);
1481 qname = quote_string(dp->name);
1482 if(sched(dp)->level != 0)
1483 /* go ahead and do the disk as-is */
1484 enqueue_disk(&newq, dp);
1486 if (reserved_space + est_full_size + sched(dp)->est_size
1487 <= total_disksize) {
1488 enqueue_disk(&newq, dp);
1489 est_full_size += sched(dp)->est_size;
1491 else if(sched(dp)->degr_level != -1) {
1492 sched(dp)->level = sched(dp)->degr_level;
1493 sched(dp)->dumpdate = sched(dp)->degr_dumpdate;
1494 sched(dp)->est_nsize = sched(dp)->degr_nsize;
1495 sched(dp)->est_csize = sched(dp)->degr_csize;
1496 sched(dp)->est_time = sched(dp)->degr_time;
1497 sched(dp)->est_kps = sched(dp)->degr_kps;
1498 enqueue_disk(&newq, dp);
1501 log_add(L_FAIL, "%s %s %s %d [%s]",
1502 dp->host->hostname, qname, sched(dp)->datestamp,
1503 sched(dp)->level, sched(dp)->degr_mesg);
1509 /*@i@*/ *queuep = newq;
1512 dump_schedule(queuep, _("after start degraded mode"));
1517 continue_port_dumps(void)
1521 int active_dumpers=0, busy_dumpers=0, i;
1524 /* First we try to grant diskspace to some dumps waiting for it. */
1525 for( dp = roomq.head; dp; dp = ndp ) {
1527 /* find last holdingdisk used by this dump */
1528 for( i = 0, h = sched(dp)->holdp; h[i+1]; i++ ) {
1529 (void)h; /* Quiet lint */
1531 /* find more space */
1532 h = find_diskspace( sched(dp)->est_size - sched(dp)->act_size,
1533 &active_dumpers, h[i] );
1535 for(dumper = dmptable; dumper < dmptable + inparallel &&
1536 dumper->dp != dp; dumper++) {
1537 (void)dp; /* Quiet lint */
1539 assert( dumper < dmptable + inparallel );
1540 sched(dp)->activehd = assign_holdingdisk( h, dp );
1541 chunker_cmd( dumper->chunker, CONTINUE, dp, NULL );
1543 remove_disk( &roomq, dp );
1547 /* So for some disks there is less holding diskspace available than
1548 * was asked for. Possible reasons are
1549 * a) diskspace has been allocated for other dumps which are
1550 * still running or already being written to tape
1551 * b) all other dumps have been suspended due to lack of diskspace
1552 * Case a) is not a problem. We just wait for the diskspace to
1553 * be freed by moving the current disk to a queue.
1554 * If case b) occurs, we have a deadlock situation. We select
1555 * a dump from the queue to be aborted and abort it. It will
1556 * be retried directly to tape.
1558 for(dp=NULL, dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
1559 if( dumper->busy ) {
1561 if( !find_disk(&roomq, dumper->dp) ) {
1562 if (dumper->chunker) {
1566 sched(dp)->est_size > sched(dumper->dp)->est_size ) {
1571 if((dp != NULL) && (active_dumpers == 0) && (busy_dumpers > 0) &&
1572 ((no_taper_flushing() && empty(tapeq)) || degraded_mode) &&
1573 pending_aborts == 0 ) { /* case b */
1574 sched(dp)->no_space = 1;
1575 /* At this time, dp points to the dump with the smallest est_size.
1576 * We abort that dump, hopefully not wasting too much time retrying it.
1578 remove_disk( &roomq, dp );
1579 chunker_cmd(sched(dp)->dumper->chunker, ABORT, NULL, _("Not enough holding disk space"));
1580 dumper_cmd( sched(dp)->dumper, ABORT, NULL, _("Not enough holding disk space"));
1587 handle_taper_result(
1588 void *cookie G_GNUC_UNUSED)
1597 taper_t *taper = NULL;
1602 assert(cookie == NULL);
1609 cmd = getresult(taper_fd, 1, &result_argc, &result_argv);
1614 if(result_argc != 2) {
1615 error(_("error: [taper FAILED result_argc != 2: %d"), result_argc);
1621 for (i=0; i < conf_taper_parallel_write; i++) {
1622 if (strcmp(tapetable[i].name, result_argv[1]) == 0) {
1623 taper= &tapetable[i];
1626 assert(taper != NULL);
1629 taper->state &= ~TAPER_STATE_INIT;
1630 taper->state |= TAPER_STATE_RESERVATION;
1631 taper->state |= TAPER_STATE_IDLE;
1632 amfree(taper->first_label);
1633 taper_nb_wait_reply--;
1634 taper_nb_scan_volume--;
1635 last_started_taper = taper;
1636 if (taper_nb_wait_reply == 0) {
1637 event_release(taper_ev_read);
1638 taper_ev_read = NULL;
1640 start_some_dumps(&runq);
1644 case FAILED: /* FAILED <handle> INPUT-* TAPE-* <input err mesg> <tape err mesg> */
1645 if(result_argc != 6) {
1646 error(_("error: [taper FAILED result_argc != 6: %d"), result_argc);
1650 dp = serial2disk(result_argv[1]);
1651 taper = sched(dp)->taper;
1652 assert(dp == taper->disk);
1654 free_serial(result_argv[1]);
1656 qname = quote_string(dp->name);
1657 g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1658 walltime_str(curclock()), dp->host->hostname, qname);
1661 if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
1662 taper->input_error = newstralloc(taper->input_error, result_argv[4]);
1663 taper->result = FAILED;
1666 } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
1667 taper->tape_error = newstralloc(taper->tape_error,
1668 _("Taper protocol error"));
1669 taper->result = FAILED;
1670 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1671 dp->host->hostname, qname, sched(dp)->datestamp,
1672 sched(dp)->level, taper->tape_error);
1676 if (strcmp(result_argv[3], "TAPE-ERROR") == 0 ||
1677 strcmp(result_argv[3], "TAPE-CONFIG") == 0) {
1678 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1679 taper->tape_error = newstralloc(taper->tape_error, result_argv[5]);
1680 taper->result = FAILED;
1683 } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
1684 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1685 taper->tape_error = newstralloc(taper->tape_error,
1686 _("Taper protocol error"));
1687 taper->result = FAILED;
1688 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1689 dp->host->hostname, qname, sched(dp)->datestamp,
1690 sched(dp)->level, taper->tape_error);
1696 taper->result = cmd;
1700 case PARTIAL: /* PARTIAL <handle> INPUT-* TAPE-* <stat mess> <input err mesg> <tape err mesg>*/
1701 case DONE: /* DONE <handle> INPUT-GOOD TAPE-GOOD <stat mess> <input err mesg> <tape err mesg> */
1702 if(result_argc != 7) {
1703 error(_("error: [taper PARTIAL result_argc != 7: %d"), result_argc);
1707 dp = serial2disk(result_argv[1]);
1708 taper = sched(dp)->taper;
1709 assert(dp == taper->disk);
1711 free_serial(result_argv[1]);
1713 qname = quote_string(dp->name);
1714 g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1715 walltime_str(curclock()), dp->host->hostname, qname);
1718 if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
1719 taper->input_error = newstralloc(taper->input_error, result_argv[5]);
1720 taper->result = FAILED;
1723 } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
1724 taper->tape_error = newstralloc(taper->tape_error,
1725 _("Taper protocol error"));
1726 taper->result = FAILED;
1727 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1728 dp->host->hostname, qname, sched(dp)->datestamp,
1729 sched(dp)->level, taper->tape_error);
1733 if (strcmp(result_argv[3], "TAPE-ERROR") == 0 ||
1734 strcmp(result_argv[3], "TAPE-CONFIG") == 0) {
1735 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1736 taper->tape_error = newstralloc(taper->tape_error, result_argv[6]);
1737 taper->result = FAILED;
1740 } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
1741 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1742 taper->tape_error = newstralloc(taper->tape_error,
1743 _("Taper protocol error"));
1744 taper->result = FAILED;
1745 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1746 dp->host->hostname, qname, sched(dp)->datestamp,
1747 sched(dp)->level, taper->tape_error);
1752 s = strstr(result_argv[4], " kb ");
1755 sched(dp)->dumpsize = OFF_T_ATOI(s);
1757 s = strstr(result_argv[4], " bytes ");
1760 sched(dp)->dumpsize = OFF_T_ATOI(s)/1024;
1764 taper->result = cmd;
1769 case PARTDONE: /* PARTDONE <handle> <label> <fileno> <kbytes> <stat> */
1770 dp = serial2disk(result_argv[1]);
1771 taper = sched(dp)->taper;
1772 assert(dp == taper->disk);
1773 if (result_argc != 6) {
1774 error(_("error [taper PARTDONE result_argc != 6: %d]"),
1778 if (!taper->first_label) {
1779 amfree(taper->first_label);
1780 taper->first_label = stralloc(result_argv[2]);
1781 taper->first_fileno = OFF_T_ATOI(result_argv[3]);
1783 taper->written += OFF_T_ATOI(result_argv[4]);
1784 if (taper->written > sched(taper->disk)->act_size)
1785 sched(taper->disk)->act_size = taper->written;
1788 s = strstr(result_argv[5], " kb ");
1791 partsize = OFF_T_ATOI(s);
1793 s = strstr(result_argv[5], " bytes ");
1796 partsize = OFF_T_ATOI(s)/1024;
1799 taper->left -= partsize;
1803 case REQUEST_NEW_TAPE: /* REQUEST-NEW-TAPE <handle> */
1804 if (result_argc != 2) {
1805 error(_("error [taper REQUEST_NEW_TAPE result_argc != 2: %d]"),
1810 dp = serial2disk(result_argv[1]);
1811 taper = sched(dp)->taper;
1812 if (taper->state & TAPER_STATE_DONE) {
1813 taper_cmd(NO_NEW_TAPE, taper->disk, "taper found no tape", 0, NULL);
1815 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1816 taper->state |= TAPER_STATE_TAPE_REQUESTED;
1818 start_some_dumps(&runq);
1823 case NEW_TAPE: /* NEW-TAPE <handle> <label> */
1824 if (result_argc != 3) {
1825 error(_("error [taper NEW_TAPE result_argc != 3: %d]"),
1831 taper_nb_scan_volume--;
1832 dp = serial2disk(result_argv[1]);
1833 taper = sched(dp)->taper;
1834 /* Update our tape counter and reset taper->left */
1837 taper->left = tape_length;
1838 taper->state &= ~TAPER_STATE_WAIT_NEW_TAPE;
1839 taper->state |= TAPER_STATE_TAPE_STARTED;
1840 last_started_taper = NULL;
1842 /* start a new worker */
1843 for (i = 0; i < conf_taper_parallel_write ; i++) {
1844 taper1 = &tapetable[i];
1845 if (need_degraded == 0 &&
1846 taper1->state == TAPER_STATE_DEFAULT) {
1847 taper1->state = TAPER_STATE_INIT;
1848 if (taper_nb_wait_reply == 0) {
1849 taper_ev_read = event_register(taper_fd, EV_READFD,
1850 handle_taper_result, NULL);
1852 taper_nb_wait_reply++;
1853 taper_nb_scan_volume++;
1854 taper_cmd(START_TAPER, NULL, taper1->name, 0,
1861 case NO_NEW_TAPE: /* NO-NEW-TAPE <handle> */
1862 if (result_argc != 2) {
1863 error(_("error [taper NO_NEW_TAPE result_argc != 2: %d]"),
1868 taper_nb_scan_volume--;
1869 dp = serial2disk(result_argv[1]);
1870 taper = sched(dp)->taper;
1871 taper->state |= TAPER_STATE_DONE;
1872 last_started_taper = NULL;
1873 start_degraded_mode(&runq);
1876 case DUMPER_STATUS: /* DUMPER-STATUS <handle> */
1877 if (result_argc != 2) {
1878 error(_("error [taper DUMPER_STATUS result_argc != 2: %d]"),
1882 dp = serial2disk(result_argv[1]);
1883 taper = sched(dp)->taper;
1884 if (taper->dumper->result == LAST_TOK) {
1885 taper->sendresult = 1;
1887 if( taper->dumper->result == DONE) {
1888 taper_cmd(DONE, dp, NULL, 0, NULL);
1890 taper_cmd(FAILED, dp, NULL, 0, NULL);
1895 case TAPE_ERROR: /* TAPE-ERROR <name> <err mess> */
1897 if (strcmp(result_argv[1], "SETUP") == 0) {
1898 taper_nb_wait_reply = 0;
1899 taper_nb_scan_volume = 0;
1902 taper = taper_from_name(result_argv[1]);
1903 taper->state = TAPER_STATE_DONE;
1905 q = quote_string(result_argv[2]);
1906 log_add(L_WARNING, _("Taper error: %s"), q);
1909 taper->tape_error = newstralloc(taper->tape_error,
1913 taper_nb_wait_reply--;
1914 taper_nb_scan_volume--;
1916 if (taper_nb_wait_reply == 0) {
1918 event_release(taper_ev_read);
1919 taper_ev_read = NULL;
1921 start_degraded_mode(&runq);
1922 start_some_dumps(&runq);
1925 case PORT: /* PORT <name> <handle> <port> <dataport_list> */
1926 dp = serial2disk(result_argv[2]);
1927 taper = sched(dp)->taper;
1928 dumper = sched(dp)->dumper;
1929 dumper->output_port = atoi(result_argv[3]);
1930 amfree(dp->dataport_list);
1931 dp->dataport_list = stralloc(result_argv[4]);
1933 amfree(taper->input_error);
1934 amfree(taper->tape_error);
1935 amfree(taper->first_label);
1937 taper->state |= TAPER_STATE_DUMP_TO_TAPE;
1939 if (dp->host->pre_script == 0) {
1940 run_server_host_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
1941 get_config_name(), dp->host);
1942 dp->host->pre_script = 1;
1944 run_server_dle_scripts(EXECUTE_ON_PRE_DLE_BACKUP,
1945 get_config_name(), dp,
1947 /* tell the dumper to dump to a port */
1948 dumper_cmd(dumper, PORT_DUMP, dp, NULL);
1949 dp->host->start_t = time(NULL) + 5;
1950 amfree(dp->dataport_list);
1952 taper->state |= TAPER_STATE_DUMP_TO_TAPE;
1954 dumper->ev_read = event_register(dumper->fd, EV_READFD,
1955 handle_dumper_result, dumper);
1959 log_add(L_WARNING, _("Taper protocol error"));
1961 * Since we received a taper error, we can't send anything more
1962 * to the taper. Go into degraded mode to try to get everthing
1963 * onto disk. Later, these dumps can be flushed to a new tape.
1964 * The tape queue is zapped so that it appears empty in future
1965 * checks. If there are dumps waiting for diskspace to be freed,
1971 _("going into degraded mode because of taper component error."));
1974 for (taper = tapetable;
1975 taper < tapetable + conf_taper_parallel_write;
1977 if (taper && taper->disk) {
1978 taper->tape_error = newstralloc(taper->tape_error,"BOGUS");
1979 taper->result = cmd;
1980 if (taper->dumper) {
1981 if (taper->dumper->result != LAST_TOK) {
1982 // Dumper already returned it's result
1983 dumper_taper_result(taper->disk);
1986 file_taper_result(taper->disk);
1992 if(taper_ev_read != NULL) {
1993 event_release(taper_ev_read);
1994 taper_ev_read = NULL;
1995 taper_nb_wait_reply = 0;
1998 start_degraded_mode(&runq);
1999 tapeq.head = tapeq.tail = NULL;
2005 error(_("driver received unexpected token (%s) from taper"),
2010 g_strfreev(result_argv);
2012 if (taper && taper->disk && taper->result != LAST_TOK) {
2013 if (taper->nb_dle >= conf_max_dle_by_volume) {
2014 taper_cmd(CLOSE_VOLUME, dp, NULL, 0, NULL);
2017 if (taper->dumper->result != LAST_TOK) {
2018 // Dumper already returned it's result
2019 dumper_taper_result(taper->disk);
2022 file_taper_result(taper->disk);
2026 } while(areads_dataready(taper_fd));
2027 start_some_dumps(&runq);
2037 char *qname = quote_string(dp->name);
2039 taper = sched(dp)->taper;
2040 if (taper->result == DONE) {
2041 update_info_taper(dp, taper->first_label, taper->first_fileno,
2045 sched(dp)->taper_attempted += 1;
2047 if (taper->input_error) {
2048 g_printf("driver: taper failed %s %s: %s\n",
2049 dp->host->hostname, qname, taper->input_error);
2050 if (strcmp(sched(dp)->datestamp, driver_timestamp) == 0) {
2051 if(sched(dp)->taper_attempted >= 2) {
2052 log_add(L_FAIL, _("%s %s %s %d [too many taper retries after holding disk error: %s]"),
2053 dp->host->hostname, qname, sched(dp)->datestamp,
2054 sched(dp)->level, taper->input_error);
2055 g_printf("driver: taper failed %s %s, too many taper retry after holding disk error\n",
2056 dp->host->hostname, qname);
2057 amfree(sched(dp)->destname);
2058 amfree(sched(dp)->dumpdate);
2059 amfree(sched(dp)->degr_dumpdate);
2060 amfree(sched(dp)->degr_mesg);
2061 amfree(sched(dp)->datestamp);
2064 log_add(L_INFO, _("%s %s %s %d [Will retry dump because of holding disk error: %s]"),
2065 dp->host->hostname, qname, sched(dp)->datestamp,
2066 sched(dp)->level, taper->input_error);
2067 g_printf("driver: taper will retry %s %s because of holding disk error\n",
2068 dp->host->hostname, qname);
2069 if (dp->to_holdingdisk != HOLD_REQUIRED) {
2070 dp->to_holdingdisk = HOLD_NEVER;
2071 sched(dp)->dump_attempted -= 1;
2072 headqueue_disk(&directq, dp);
2074 amfree(sched(dp)->destname);
2075 amfree(sched(dp)->dumpdate);
2076 amfree(sched(dp)->degr_dumpdate);
2077 amfree(sched(dp)->degr_mesg);
2078 amfree(sched(dp)->datestamp);
2083 amfree(sched(dp)->destname);
2084 amfree(sched(dp)->dumpdate);
2085 amfree(sched(dp)->degr_dumpdate);
2086 amfree(sched(dp)->degr_mesg);
2087 amfree(sched(dp)->datestamp);
2090 } else if (taper->tape_error) {
2091 g_printf("driver: taper failed %s %s with tape error: %s\n",
2092 dp->host->hostname, qname, taper->tape_error);
2093 if(sched(dp)->taper_attempted >= 2) {
2094 log_add(L_FAIL, _("%s %s %s %d [too many taper retries]"),
2095 dp->host->hostname, qname, sched(dp)->datestamp,
2097 g_printf("driver: taper failed %s %s, too many taper retry\n",
2098 dp->host->hostname, qname);
2099 amfree(sched(dp)->destname);
2100 amfree(sched(dp)->dumpdate);
2101 amfree(sched(dp)->degr_dumpdate);
2102 amfree(sched(dp)->degr_mesg);
2103 amfree(sched(dp)->datestamp);
2106 g_printf("driver: taper will retry %s %s\n",
2107 dp->host->hostname, qname);
2108 /* Re-insert into taper queue. */
2109 headqueue_disk(&tapeq, dp);
2111 } else if (taper->result != DONE) {
2112 g_printf("driver: taper failed %s %s without error\n",
2113 dp->host->hostname, qname);
2115 delete_diskspace(dp);
2116 amfree(sched(dp)->destname);
2117 amfree(sched(dp)->dumpdate);
2118 amfree(sched(dp)->degr_dumpdate);
2119 amfree(sched(dp)->degr_mesg);
2120 amfree(sched(dp)->datestamp);
2126 taper->state &= ~TAPER_STATE_FILE_TO_TAPE;
2127 taper->state |= TAPER_STATE_IDLE;
2128 amfree(taper->input_error);
2129 amfree(taper->tape_error);
2131 taper_nb_wait_reply--;
2132 if (taper_nb_wait_reply == 0) {
2133 event_release(taper_ev_read);
2134 taper_ev_read = NULL;
2137 /* continue with those dumps waiting for diskspace */
2138 continue_port_dumps();
2139 start_some_dumps(&runq);
2144 dumper_taper_result(
2151 dumper = sched(dp)->dumper;
2152 taper = sched(dp)->taper;
2155 if(dumper->result == DONE && taper->result == DONE) {
2156 update_info_dumper(dp, sched(dp)->origsize,
2157 sched(dp)->dumpsize, sched(dp)->dumptime);
2158 update_info_taper(dp, taper->first_label, taper->first_fileno,
2160 qname = quote_string(dp->name); /*quote to take care of spaces*/
2162 log_add(L_STATS, _("estimate %s %s %s %d [sec %ld nkb %lld ckb %lld kps %lu]"),
2163 dp->host->hostname, qname, sched(dp)->datestamp,
2165 sched(dp)->est_time, (long long)sched(dp)->est_nsize,
2166 (long long)sched(dp)->est_csize,
2167 sched(dp)->est_kps);
2170 update_failed_dump(dp);
2173 sched(dp)->dump_attempted += 1;
2174 sched(dp)->taper_attempted += 1;
2176 if((dumper->result != DONE || taper->result != DONE) &&
2177 sched(dp)->dump_attempted <= 1 &&
2178 sched(dp)->taper_attempted <= 1) {
2179 enqueue_disk(&directq, dp);
2182 if(dumper->ev_read != NULL) {
2183 event_release(dumper->ev_read);
2184 dumper->ev_read = NULL;
2186 taper_nb_wait_reply--;
2187 if (taper_nb_wait_reply == 0 && taper_ev_read != NULL) {
2188 event_release(taper_ev_read);
2189 taper_ev_read = NULL;
2191 taper->state &= ~TAPER_STATE_DUMP_TO_TAPE;
2192 taper->state |= TAPER_STATE_IDLE;
2193 amfree(taper->input_error);
2194 amfree(taper->tape_error);
2196 dp->host->inprogress -= 1;
2198 deallocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
2199 taper->dumper = NULL;
2201 sched(dp)->dumper = NULL;
2202 sched(dp)->taper = NULL;
2203 start_some_dumps(&runq);
2212 /* Use an already started taper first */
2213 for (taper = tapetable; taper < tapetable + conf_taper_parallel_write;
2215 if ((taper->state & TAPER_STATE_IDLE) &&
2216 (taper->state & TAPER_STATE_TAPE_STARTED) &&
2217 !(taper->state & TAPER_STATE_DONE) &&
2218 !(taper->state & TAPER_STATE_FILE_TO_TAPE) &&
2219 !(taper->state & TAPER_STATE_FILE_TO_TAPE))
2222 for (taper = tapetable; taper < tapetable + conf_taper_parallel_write;
2224 if ((taper->state & TAPER_STATE_IDLE) &&
2225 (taper->state & TAPER_STATE_RESERVATION) &&
2226 !(taper->state & TAPER_STATE_DONE) &&
2227 !(taper->state & TAPER_STATE_FILE_TO_TAPE) &&
2228 !(taper->state & TAPER_STATE_FILE_TO_TAPE))
2240 for (taper = tapetable; taper < tapetable+conf_taper_parallel_write;
2242 if (strcmp(taper->name, name) == 0) return taper;
2248 dumper_chunker_result(
2253 assignedhd_t **h=NULL;
2260 dumper = sched(dp)->dumper;
2261 chunker = dumper->chunker;
2265 h = sched(dp)->holdp;
2266 activehd = sched(dp)->activehd;
2268 if(dumper->result == DONE && chunker->result == DONE) {
2269 update_info_dumper(dp, sched(dp)->origsize,
2270 sched(dp)->dumpsize, sched(dp)->dumptime);
2271 qname = quote_string(dp->name);/*quote to take care of spaces*/
2273 log_add(L_STATS, _("estimate %s %s %s %d [sec %ld nkb %lld ckb %lld kps %lu]"),
2274 dp->host->hostname, qname, sched(dp)->datestamp,
2276 sched(dp)->est_time, (long long)sched(dp)->est_nsize,
2277 (long long)sched(dp)->est_csize,
2278 sched(dp)->est_kps);
2281 update_failed_dump(dp);
2284 deallocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
2286 is_partial = dumper->result != DONE || chunker->result != DONE;
2287 rename_tmp_holding(sched(dp)->destname, !is_partial);
2288 holding_set_origsize(sched(dp)->destname, sched(dp)->origsize);
2291 for( i = 0, h = sched(dp)->holdp; i < activehd; i++ ) {
2292 dummy += h[i]->used;
2295 size = holding_file_size(sched(dp)->destname, 0);
2296 h[activehd]->used = size - dummy;
2297 h[activehd]->disk->allocated_dumpers--;
2298 adjust_diskspace(dp, DONE);
2300 sched(dp)->dump_attempted += 1;
2302 if((dumper->result != DONE || chunker->result != DONE) &&
2303 sched(dp)->dump_attempted <= 1) {
2304 delete_diskspace(dp);
2305 if (sched(dp)->no_space) {
2306 enqueue_disk(&directq, dp);
2308 enqueue_disk(&runq, dp);
2311 else if(size > (off_t)DISK_BLOCK_KB) {
2312 enqueue_disk(&tapeq, dp);
2315 delete_diskspace(dp);
2319 dp->host->inprogress -= 1;
2322 waitpid(chunker->pid, NULL, 0 );
2323 aclose(chunker->fd);
2328 if (chunker->result == ABORT_FINISHED)
2330 continue_port_dumps();
2332 * Wakeup any dumpers that are sleeping because of network
2333 * or disk constraints.
2335 start_some_dumps(&runq);
2341 handle_dumper_result(
2344 /* uses global pending_aborts */
2345 dumper_t *dumper = cookie;
2347 disk_t *dp, *sdp, *dp1;
2353 assert(dumper != NULL);
2356 assert(sched(dp) != NULL);
2361 cmd = getresult(dumper->fd, 1, &result_argc, &result_argv);
2364 /* result_argv[1] always contains the serial number */
2365 sdp = serial2disk(result_argv[1]);
2367 error(_("Invalid serial number %s"), result_argv[1]);
2368 g_assert_not_reached();
2372 qname = quote_string(dp->name);
2375 case DONE: /* DONE <handle> <origsize> <dumpsize> <dumptime> <errstr> */
2376 if(result_argc != 6) {
2377 error(_("error [dumper DONE result_argc != 6: %d]"), result_argc);
2381 sched(dp)->origsize = OFF_T_ATOI(result_argv[2]);
2382 sched(dp)->dumptime = TIME_T_ATOI(result_argv[4]);
2384 g_printf(_("driver: finished-cmd time %s %s dumped %s:%s\n"),
2385 walltime_str(curclock()), dumper->name,
2386 dp->host->hostname, qname);
2389 dumper->result = cmd;
2393 case TRYAGAIN: /* TRY-AGAIN <handle> <errstr> */
2395 * Requeue this disk, and fall through to the FAILED
2398 if(sched(dp)->dump_attempted) {
2399 char *qname = quote_string(dp->name);
2400 char *qerr = quote_string(result_argv[2]);
2401 log_add(L_FAIL, _("%s %s %s %d [too many dumper retry: %s]"),
2402 dp->host->hostname, qname, sched(dp)->datestamp,
2403 sched(dp)->level, qerr);
2404 g_printf(_("driver: dump failed %s %s %s, too many dumper retry: %s\n"),
2405 result_argv[1], dp->host->hostname, qname, qerr);
2410 case FAILED: /* FAILED <handle> <errstr> */
2411 /*free_serial(result_argv[1]);*/
2412 dumper->result = cmd;
2415 case ABORT_FINISHED: /* ABORT-FINISHED <handle> */
2417 * We sent an ABORT from the NO-ROOM case because this dump
2418 * wasn't going to fit onto the holding disk. We now need to
2419 * clean up the remains of this image, and try to finish
2420 * other dumps that are waiting on disk space.
2422 assert(pending_aborts);
2423 /*free_serial(result_argv[1]);*/
2424 dumper->result = cmd;
2428 /* either EOF or garbage from dumper. Turn it off */
2429 log_add(L_WARNING, _("%s pid %ld is messed up, ignoring it.\n"),
2430 dumper->name, (long)dumper->pid);
2431 if (dumper->ev_read) {
2432 event_release(dumper->ev_read);
2433 dumper->ev_read = NULL;
2437 dumper->down = 1; /* mark it down so it isn't used again */
2439 /* if it was dumping something, zap it and try again */
2440 if(sched(dp)->dump_attempted) {
2441 log_add(L_FAIL, _("%s %s %s %d [%s died]"),
2442 dp->host->hostname, qname, sched(dp)->datestamp,
2443 sched(dp)->level, dumper->name);
2445 log_add(L_WARNING, _("%s died while dumping %s:%s lev %d."),
2446 dumper->name, dp->host->hostname, qname,
2449 dumper->result = cmd;
2456 g_strfreev(result_argv);
2462 run_server_dle_scripts(EXECUTE_ON_POST_DLE_BACKUP,
2463 get_config_name(), dp, sched(dp)->level);
2464 /* check dump not yet started */
2465 for (dp1=runq.head; dp1 != NULL; dp1 = dp1->next) {
2466 if (dp1->host == dp->host)
2469 /* check direct to tape dump */
2470 for (dp1=directq.head; dp1 != NULL; dp1 = dp1->next) {
2471 if (dp1->host == dp->host)
2474 /* check dumping dle */
2475 for (dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
2476 if (dumper->busy && dumper->dp != dp &&
2477 dumper->dp->host == dp->host)
2480 if (last_dump && dp->host->post_script == 0) {
2481 if (dp->host->post_script == 0) {
2482 run_server_host_scripts(EXECUTE_ON_POST_HOST_BACKUP,
2483 get_config_name(), dp->host);
2484 dp->host->post_script = 1;
2489 taper = sched(dp)->taper;
2490 /* send the dumper result to the chunker */
2491 if (dumper->chunker) {
2492 if (dumper->chunker->down == 0 && dumper->chunker->fd != -1 &&
2493 dumper->chunker->result == LAST_TOK) {
2495 chunker_cmd(dumper->chunker, DONE, dp, NULL);
2498 chunker_cmd(dumper->chunker, FAILED, dp, NULL);
2501 if( dumper->result != LAST_TOK &&
2502 dumper->chunker->result != LAST_TOK)
2503 dumper_chunker_result(dp);
2504 } else { /* send the dumper result to the taper */
2506 taper_cmd(DONE, dp, NULL, 0, NULL);
2508 taper_cmd(FAILED, dp, NULL, 0, NULL);
2510 taper->sendresult = 0;
2511 if (taper->dumper && taper->result != LAST_TOK) {
2512 dumper_taper_result(dp);
2515 } while(areads_dataready(dumper->fd));
2520 handle_chunker_result(
2523 chunker_t *chunker = cookie;
2524 assignedhd_t **h=NULL;
2534 assert(chunker != NULL);
2535 dumper = chunker->dumper;
2536 assert(dumper != NULL);
2539 assert(sched(dp) != NULL);
2540 assert(sched(dp)->destname != NULL);
2541 assert(dp != NULL && sched(dp) != NULL && sched(dp)->destname);
2543 if(sched(dp)->holdp) {
2544 h = sched(dp)->holdp;
2545 activehd = sched(dp)->activehd;
2551 cmd = getresult(chunker->fd, 1, &result_argc, &result_argv);
2554 /* result_argv[1] always contains the serial number */
2555 sdp = serial2disk(result_argv[1]);
2557 error(_("Invalid serial number %s"), result_argv[1]);
2558 g_assert_not_reached();
2564 case PARTIAL: /* PARTIAL <handle> <dumpsize> <errstr> */
2565 case DONE: /* DONE <handle> <dumpsize> <errstr> */
2566 if(result_argc != 4) {
2567 error(_("error [chunker %s result_argc != 4: %d]"), cmdstr[cmd],
2571 /*free_serial(result_argv[1]);*/
2573 sched(dp)->dumpsize = (off_t)atof(result_argv[2]);
2575 qname = quote_string(dp->name);
2576 g_printf(_("driver: finished-cmd time %s %s chunked %s:%s\n"),
2577 walltime_str(curclock()), chunker->name,
2578 dp->host->hostname, qname);
2582 event_release(chunker->ev_read);
2584 chunker->result = cmd;
2588 case TRYAGAIN: /* TRY-AGAIN <handle> <errstr> */
2589 event_release(chunker->ev_read);
2591 chunker->result = cmd;
2594 case FAILED: /* FAILED <handle> <errstr> */
2595 /*free_serial(result_argv[1]);*/
2597 event_release(chunker->ev_read);
2599 chunker->result = cmd;
2603 case NO_ROOM: /* NO-ROOM <handle> <missing_size> */
2604 if (!h || activehd < 0) { /* should never happen */
2605 error(_("!h || activehd < 0"));
2608 h[activehd]->used -= OFF_T_ATOI(result_argv[2]);
2609 h[activehd]->reserved -= OFF_T_ATOI(result_argv[2]);
2610 h[activehd]->disk->allocated_space -= OFF_T_ATOI(result_argv[2]);
2611 h[activehd]->disk->disksize -= OFF_T_ATOI(result_argv[2]);
2614 case RQ_MORE_DISK: /* RQ-MORE-DISK <handle> */
2615 if (!h || activehd < 0) { /* should never happen */
2616 error(_("!h || activehd < 0"));
2619 h[activehd]->disk->allocated_dumpers--;
2620 h[activehd]->used = h[activehd]->reserved;
2621 if( h[++activehd] ) { /* There's still some allocated space left.
2622 * Tell the dumper about it. */
2623 sched(dp)->activehd++;
2624 chunker_cmd( chunker, CONTINUE, dp, NULL );
2625 } else { /* !h[++activehd] - must allocate more space */
2626 sched(dp)->act_size = sched(dp)->est_size; /* not quite true */
2627 sched(dp)->est_size = (sched(dp)->act_size/(off_t)20) * (off_t)21; /* +5% */
2628 sched(dp)->est_size = am_round(sched(dp)->est_size, (off_t)DISK_BLOCK_KB);
2629 if (sched(dp)->est_size < sched(dp)->act_size + 2*DISK_BLOCK_KB)
2630 sched(dp)->est_size += 2 * DISK_BLOCK_KB;
2631 h = find_diskspace( sched(dp)->est_size - sched(dp)->act_size,
2635 /* No diskspace available. The reason for this will be
2636 * determined in continue_port_dumps(). */
2637 enqueue_disk( &roomq, dp );
2638 continue_port_dumps();
2639 /* continue flush waiting for new tape */
2642 /* OK, allocate space for disk and have chunker continue */
2643 sched(dp)->activehd = assign_holdingdisk( h, dp );
2644 chunker_cmd( chunker, CONTINUE, dp, NULL );
2650 case ABORT_FINISHED: /* ABORT-FINISHED <handle> */
2652 * We sent an ABORT from the NO-ROOM case because this dump
2653 * wasn't going to fit onto the holding disk. We now need to
2654 * clean up the remains of this image, and try to finish
2655 * other dumps that are waiting on disk space.
2657 /*assert(pending_aborts);*/
2659 /*free_serial(result_argv[1]);*/
2661 event_release(chunker->ev_read);
2663 chunker->result = cmd;
2668 /* either EOF or garbage from chunker. Turn it off */
2669 log_add(L_WARNING, _("%s pid %ld is messed up, ignoring it.\n"),
2670 chunker->name, (long)chunker->pid);
2672 /* if it was dumping something, zap it and try again */
2673 g_assert(h && activehd >= 0);
2674 qname = quote_string(dp->name);
2675 if(sched(dp)->dump_attempted) {
2676 log_add(L_FAIL, _("%s %s %s %d [%s died]"),
2677 dp->host->hostname, qname, sched(dp)->datestamp,
2678 sched(dp)->level, chunker->name);
2680 log_add(L_WARNING, _("%s died while dumping %s:%s lev %d."),
2681 chunker->name, dp->host->hostname, qname,
2687 event_release(chunker->ev_read);
2689 chunker->result = cmd;
2696 g_strfreev(result_argv);
2698 if(chunker->result != LAST_TOK && chunker->dumper->result != LAST_TOK)
2699 dumper_chunker_result(dp);
2701 } while(areads_dataready(chunker->fd));
2712 char *hostname, *diskname, *datestamp;
2716 char *inpline = NULL;
2721 char *qdestname = NULL;
2722 char *conf_infofile;
2724 (void)cookie; /* Quiet unused parameter warning */
2726 event_release(flush_ev_read);
2727 flush_ev_read = NULL;
2729 /* read schedule from stdin */
2730 conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE));
2731 if (open_infofile(conf_infofile)) {
2732 error(_("could not open info db \"%s\""), conf_infofile);
2735 amfree(conf_infofile);
2737 for(line = 0; (inpline = agets(stdin)) != NULL; free(inpline)) {
2741 if (inpline[0] == '\0')
2747 skip_whitespace(s, ch); /* find the command */
2749 error(_("flush line %d: syntax error (no command)"), line);
2753 skip_non_whitespace(s, ch);
2756 if(strcmp(command,"ENDFLUSH") == 0) {
2760 if(strcmp(command,"FLUSH") != 0) {
2761 error(_("flush line %d: syntax error (%s != FLUSH)"), line, command);
2765 skip_whitespace(s, ch); /* find the hostname */
2767 error(_("flush line %d: syntax error (no hostname)"), line);
2771 skip_non_whitespace(s, ch);
2774 skip_whitespace(s, ch); /* find the diskname */
2776 error(_("flush line %d: syntax error (no diskname)"), line);
2780 skip_quoted_string(s, ch);
2781 s[-1] = '\0'; /* terminate the disk name */
2782 diskname = unquote_string(qname);
2784 skip_whitespace(s, ch); /* find the datestamp */
2786 error(_("flush line %d: syntax error (no datestamp)"), line);
2790 skip_non_whitespace(s, ch);
2793 skip_whitespace(s, ch); /* find the level number */
2794 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2795 error(_("flush line %d: syntax error (bad level)"), line);
2798 skip_integer(s, ch);
2800 skip_whitespace(s, ch); /* find the filename */
2802 error(_("flush line %d: syntax error (no filename)"), line);
2806 skip_quoted_string(s, ch);
2808 destname = unquote_string(qdestname);
2810 holding_file_get_dumpfile(destname, &file);
2811 if( file.type != F_DUMPFILE) {
2812 if( file.type != F_CONT_DUMPFILE )
2813 log_add(L_INFO, _("%s: ignoring cruft file."), destname);
2816 dumpfile_free_data(&file);
2820 if(strcmp(hostname, file.name) != 0 ||
2821 strcmp(diskname, file.disk) != 0 ||
2822 strcmp(datestamp, file.datestamp) != 0) {
2823 log_add(L_INFO, _("disk %s:%s not consistent with file %s"),
2824 hostname, diskname, destname);
2827 dumpfile_free_data(&file);
2832 dp = lookup_disk(file.name, file.disk);
2835 log_add(L_INFO, _("%s: disk %s:%s not in database, skipping it."),
2836 destname, file.name, file.disk);
2838 dumpfile_free_data(&file);
2842 if (file.dumplevel < 0 || file.dumplevel > 399) {
2843 log_add(L_INFO, _("%s: ignoring file with bogus dump level %d."),
2844 destname, file.dumplevel);
2846 dumpfile_free_data(&file);
2850 if (holding_file_size(destname,1) <= 0) {
2851 log_add(L_INFO, "%s: removing file with no data.", destname);
2852 holding_file_unlink(destname);
2854 dumpfile_free_data(&file);
2858 dp1 = (disk_t *)alloc(SIZEOF(disk_t));
2860 dp1->next = dp1->prev = NULL;
2862 /* add it to the flushhost list */
2864 flushhost = alloc(SIZEOF(am_host_t));
2865 flushhost->next = NULL;
2866 flushhost->hostname = stralloc("FLUSHHOST");
2867 flushhost->up = NULL;
2868 flushhost->features = NULL;
2870 dp1->hostnext = flushhost->disks;
2871 flushhost->disks = dp1;
2873 sp = (sched_t *) alloc(SIZEOF(sched_t));
2874 sp->destname = destname;
2875 sp->level = file.dumplevel;
2876 sp->dumpdate = NULL;
2877 sp->degr_dumpdate = NULL;
2878 sp->degr_mesg = NULL;
2879 sp->datestamp = stralloc(file.datestamp);
2880 sp->est_nsize = (off_t)0;
2881 sp->est_csize = (off_t)0;
2884 sp->origsize = file.orig_size;
2886 sp->degr_level = -1;
2887 sp->dump_attempted = 0;
2888 sp->taper_attempted = 0;
2889 sp->act_size = holding_file_size(destname, 0);
2890 sp->holdp = build_diskspace(destname);
2891 if(sp->holdp == NULL) continue;
2894 sp->timestamp = (time_t)0;
2896 dp1->up = (char *)sp;
2898 enqueue_disk(&tapeq, dp1);
2899 dumpfile_free_data(&file);
2906 schedule_ev_read = event_register((event_id_t)0, EV_READFD,
2907 read_schedule, NULL);
2919 int level, line, priority;
2920 char *dumpdate, *degr_dumpdate, *degr_mesg;
2922 time_t time, degr_time;
2923 time_t *time_p = &time;
2924 time_t *degr_time_p = °r_time;
2925 off_t nsize, csize, degr_nsize, degr_csize;
2926 unsigned long kps, degr_kps;
2927 char *hostname, *features, *diskname, *datestamp, *inpline = NULL;
2931 off_t flush_size = (off_t)0;
2936 long long degr_nsize_;
2937 long long degr_csize_;
2938 GPtrArray *errarray;
2940 (void)cookie; /* Quiet unused parameter warning */
2942 event_release(schedule_ev_read);
2943 schedule_ev_read = NULL;
2945 /* read schedule from stdin */
2947 for(line = 0; (inpline = agets(stdin)) != NULL; free(inpline)) {
2948 if (inpline[0] == '\0')
2955 skip_whitespace(s, ch); /* find the command */
2957 error(_("schedule line %d: syntax error (no command)"), line);
2961 skip_non_whitespace(s, ch);
2964 if(strcmp(command,"DUMP") != 0) {
2965 error(_("schedule line %d: syntax error (%s != DUMP)"), line, command);
2969 skip_whitespace(s, ch); /* find the host name */
2971 error(_("schedule line %d: syntax error (no host name)"), line);
2975 skip_non_whitespace(s, ch);
2978 skip_whitespace(s, ch); /* find the feature list */
2980 error(_("schedule line %d: syntax error (no feature list)"), line);
2984 skip_non_whitespace(s, ch);
2987 skip_whitespace(s, ch); /* find the disk name */
2989 error(_("schedule line %d: syntax error (no disk name)"), line);
2993 skip_quoted_string(s, ch);
2994 s[-1] = '\0'; /* terminate the disk name */
2995 diskname = unquote_string(qname);
2997 skip_whitespace(s, ch); /* find the datestamp */
2999 error(_("schedule line %d: syntax error (no datestamp)"), line);
3003 skip_non_whitespace(s, ch);
3006 skip_whitespace(s, ch); /* find the priority number */
3007 if(ch == '\0' || sscanf(s - 1, "%d", &priority) != 1) {
3008 error(_("schedule line %d: syntax error (bad priority)"), line);
3011 skip_integer(s, ch);
3013 skip_whitespace(s, ch); /* find the level number */
3014 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
3015 error(_("schedule line %d: syntax error (bad level)"), line);
3018 skip_integer(s, ch);
3020 skip_whitespace(s, ch); /* find the dump date */
3022 error(_("schedule line %d: syntax error (bad dump date)"), line);
3026 skip_non_whitespace(s, ch);
3029 skip_whitespace(s, ch); /* find the native size */
3031 if(ch == '\0' || sscanf(s - 1, "%lld", &nsize_) != 1) {
3032 error(_("schedule line %d: syntax error (bad nsize)"), line);
3035 nsize = (off_t)nsize_;
3036 skip_integer(s, ch);
3038 skip_whitespace(s, ch); /* find the compressed size */
3040 if(ch == '\0' || sscanf(s - 1, "%lld", &csize_) != 1) {
3041 error(_("schedule line %d: syntax error (bad csize)"), line);
3044 csize = (off_t)csize_;
3045 skip_integer(s, ch);
3047 skip_whitespace(s, ch); /* find the time number */
3048 if(ch == '\0' || sscanf(s - 1, "%lld", &time_) != 1) {
3049 error(_("schedule line %d: syntax error (bad estimated time)"), line);
3052 *time_p = (time_t)time_;
3053 skip_integer(s, ch);
3055 skip_whitespace(s, ch); /* find the kps number */
3056 if(ch == '\0' || sscanf(s - 1, "%lu", &kps) != 1) {
3057 error(_("schedule line %d: syntax error (bad kps)"), line);
3060 skip_integer(s, ch);
3062 degr_dumpdate = NULL; /* flag if degr fields found */
3063 skip_whitespace(s, ch); /* find the degr level number */
3067 skip_quoted_string(s, ch);
3068 s[-1] = '\0'; /* terminate degr mesg */
3069 degr_mesg = unquote_string(qname);
3071 degr_nsize = (off_t)0;
3072 degr_csize = (off_t)0;
3073 degr_time = (time_t)0;
3075 } else if (ch != '\0') {
3076 if(sscanf(s - 1, "%d", °r_level) != 1) {
3077 error(_("schedule line %d: syntax error (bad degr level)"), line);
3080 skip_integer(s, ch);
3082 skip_whitespace(s, ch); /* find the degr dump date */
3084 error(_("schedule line %d: syntax error (bad degr dump date)"), line);
3087 degr_dumpdate = s - 1;
3088 skip_non_whitespace(s, ch);
3091 skip_whitespace(s, ch); /* find the degr native size */
3092 degr_nsize_ = (off_t)0;
3093 if(ch == '\0' || sscanf(s - 1, "%lld", °r_nsize_) != 1) {
3094 error(_("schedule line %d: syntax error (bad degr nsize)"), line);
3097 degr_nsize = (off_t)degr_nsize_;
3098 skip_integer(s, ch);
3100 skip_whitespace(s, ch); /* find the degr compressed size */
3101 degr_csize_ = (off_t)0;
3102 if(ch == '\0' || sscanf(s - 1, "%lld", °r_csize_) != 1) {
3103 error(_("schedule line %d: syntax error (bad degr csize)"), line);
3106 degr_csize = (off_t)degr_csize_;
3107 skip_integer(s, ch);
3109 skip_whitespace(s, ch); /* find the degr time number */
3110 if(ch == '\0' || sscanf(s - 1, "%lld", &time_) != 1) {
3111 error(_("schedule line %d: syntax error (bad degr estimated time)"), line);
3114 *degr_time_p = (time_t)time_;
3115 skip_integer(s, ch);
3117 skip_whitespace(s, ch); /* find the degr kps number */
3118 if(ch == '\0' || sscanf(s - 1, "%lu", °r_kps) != 1) {
3119 error(_("schedule line %d: syntax error (bad degr kps)"), line);
3122 skip_integer(s, ch);
3124 error(_("schedule line %d: no degraded estimate or message"), line);
3127 dp = lookup_disk(hostname, diskname);
3130 _("schedule line %d: %s:'%s' not in disklist, ignored"),
3131 line, hostname, qname);
3136 sp = (sched_t *) alloc(SIZEOF(sched_t));
3139 sp->dumpdate = stralloc(dumpdate);
3140 sp->est_nsize = DISK_BLOCK_KB + nsize; /* include header */
3141 sp->est_csize = DISK_BLOCK_KB + csize; /* include header */
3142 /* round estimate to next multiple of DISK_BLOCK_KB */
3143 sp->est_csize = am_round(sp->est_csize, DISK_BLOCK_KB);
3144 sp->est_size = sp->est_csize;
3145 sp->est_time = time;
3147 sp->priority = priority;
3148 sp->datestamp = stralloc(datestamp);
3151 sp->degr_level = degr_level;
3152 sp->degr_dumpdate = stralloc(degr_dumpdate);
3153 sp->degr_nsize = DISK_BLOCK_KB + degr_nsize;
3154 sp->degr_csize = DISK_BLOCK_KB + degr_csize;
3155 /* round estimate to next multiple of DISK_BLOCK_KB */
3156 sp->degr_csize = am_round(sp->degr_csize, DISK_BLOCK_KB);
3157 sp->degr_time = degr_time;
3158 sp->degr_kps = degr_kps;
3159 sp->degr_mesg = NULL;
3161 sp->degr_level = -1;
3162 sp->degr_dumpdate = NULL;
3163 sp->degr_mesg = degr_mesg;
3167 sp->dump_attempted = 0;
3168 sp->taper_attempted = 0;
3174 sp->timestamp = (time_t)0;
3175 sp->destname = NULL;
3178 dp->up = (char *) sp;
3179 if(dp->host->features == NULL) {
3180 dp->host->features = am_string_to_feature(features);
3181 if (!dp->host->features) {
3183 _("Invalid feature string from client '%s'"),
3185 dp->host->features = am_set_default_feature_set();
3188 remove_disk(&waitq, dp);
3190 errarray = validate_optionstr(dp);
3191 if (errarray->len > 0) {
3193 for (i=0; i < errarray->len; i++) {
3194 log_add(L_FAIL, _("%s %s %s 0 [%s]"),
3195 dp->host->hostname, qname,
3197 (char *)g_ptr_array_index(errarray, i));
3202 if (dp->data_path == DATA_PATH_DIRECTTCP &&
3203 dp->to_holdingdisk == HOLD_AUTO) {
3204 dp->to_holdingdisk = HOLD_NEVER;
3207 if (dp->to_holdingdisk == HOLD_NEVER) {
3208 enqueue_disk(&directq, dp);
3210 enqueue_disk(&runq, dp);
3212 flush_size += sp->act_size;
3216 g_printf(_("driver: flush size %lld\n"), (long long)flush_size);
3219 log_add(L_WARNING, _("WARNING: got empty schedule from planner"));
3221 start_degraded_mode(&runq);
3222 run_server_global_scripts(EXECUTE_ON_PRE_BACKUP, get_config_name());
3223 if (empty(runq)) force_flush = 1;
3224 start_some_dumps(&runq);
3228 static unsigned long
3236 unsigned long maxusage=0;
3237 unsigned long curusage=0;
3238 for(p = disklist_netifs(); p != NULL; p = p->next) {
3239 maxusage += interface_get_maxusage(p->config);
3240 curusage += p->curusage;
3242 if (maxusage >= curusage)
3243 res = maxusage - curusage;
3248 if ((unsigned long)interface_get_maxusage(ip->config) >= ip->curusage)
3249 res = interface_get_maxusage(ip->config) - ip->curusage;
3264 g_printf(_("driver: interface-state time %s"), time_str);
3266 for(ip = disklist_netifs(); ip != NULL; ip = ip->next) {
3267 g_printf(_(" if %s: free %lu"), interface_name(ip->config), free_kps(ip));
3277 ip->curusage += kps;
3281 deallocate_bandwidth(
3285 assert(kps <= ip->curusage);
3286 ip->curusage -= kps;
3297 total_free = (off_t)0;
3298 for(ha = holdalloc; ha != NULL; ha = ha->next) {
3299 diff = ha->disksize - ha->allocated_space;
3307 * We return an array of pointers to assignedhd_t. The array contains at
3308 * most one entry per holding disk. The list of pointers is terminated by
3309 * a NULL pointer. Each entry contains a pointer to a holdingdisk and
3310 * how much diskspace to use on that disk. Later on, assign_holdingdisk
3311 * will allocate the given amount of space.
3312 * If there is not enough room on the holdingdisks, NULL is returned.
3315 static assignedhd_t **
3319 assignedhd_t * pref)
3321 assignedhd_t **result = NULL;
3322 holdalloc_t *ha, *minp;
3326 off_t halloc, dalloc, hfree, dfree;
3328 (void)cur_idle; /* Quiet unused parameter warning */
3330 if (size < 2*DISK_BLOCK_KB)
3331 size = 2*DISK_BLOCK_KB;
3332 size = am_round(size, (off_t)DISK_BLOCK_KB);
3334 hold_debug(1, _("find_diskspace: want %lld K\n"),
3337 used = alloc(SIZEOF(*used) * num_holdalloc);/*disks used during this run*/
3338 memset( used, 0, (size_t)num_holdalloc );
3339 result = alloc(SIZEOF(assignedhd_t *) * (num_holdalloc + 1));
3342 while( i < num_holdalloc && size > (off_t)0 ) {
3343 /* find the holdingdisk with the fewest active dumpers and among
3344 * those the one with the biggest free space
3346 minp = NULL; minj = -1;
3347 for(j = 0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3348 if( pref && pref->disk == ha && !used[j] &&
3349 ha->allocated_space <= ha->disksize - (off_t)DISK_BLOCK_KB) {
3354 else if( ha->allocated_space <= ha->disksize - (off_t)(2*DISK_BLOCK_KB) &&
3357 ha->allocated_dumpers < minp->allocated_dumpers ||
3358 (ha->allocated_dumpers == minp->allocated_dumpers &&
3359 ha->disksize-ha->allocated_space > minp->disksize-minp->allocated_space)) ) {
3366 if( !minp ) { break; } /* all holding disks are full */
3369 /* hfree = free space on the disk */
3370 hfree = minp->disksize - minp->allocated_space;
3372 /* dfree = free space for data, remove 1 header for each chunksize */
3373 dfree = hfree - (((hfree-(off_t)1)/holdingdisk_get_chunksize(minp->hdisk))+(off_t)1) * (off_t)DISK_BLOCK_KB;
3375 /* dalloc = space I can allocate for data */
3376 dalloc = ( dfree < size ) ? dfree : size;
3378 /* halloc = space to allocate, including 1 header for each chunksize */
3379 halloc = dalloc + (((dalloc-(off_t)1)/holdingdisk_get_chunksize(minp->hdisk))+(off_t)1) * (off_t)DISK_BLOCK_KB;
3381 hold_debug(1, _("find_diskspace: find diskspace: size %lld hf %lld df %lld da %lld ha %lld\n"),
3388 result[i] = alloc(SIZEOF(assignedhd_t));
3389 result[i]->disk = minp;
3390 result[i]->reserved = halloc;
3391 result[i]->used = (off_t)0;
3392 result[i]->destname = NULL;
3398 if(size != (off_t)0) { /* not enough space available */
3399 g_printf(_("find diskspace: not enough diskspace. Left with %lld K\n"), (long long)size);
3401 free_assignedhd(result);
3405 if (debug_holding > 1) {
3406 for( i = 0; result && result[i]; i++ ) {
3407 hold_debug(1, _("find_diskspace: find diskspace: selected %s free %lld reserved %lld dumpers %d\n"),
3408 holdingdisk_get_diskdir(result[i]->disk->hdisk),
3409 (long long)(result[i]->disk->disksize -
3410 result[i]->disk->allocated_space),
3411 (long long)result[i]->reserved,
3412 result[i]->disk->allocated_dumpers);
3421 assignedhd_t ** holdp,
3426 char *sfn = sanitise_filename(diskp->name);
3428 assignedhd_t **new_holdp;
3431 g_snprintf( lvl, SIZEOF(lvl), "%d", sched(diskp)->level );
3433 size = am_round(sched(diskp)->est_size - sched(diskp)->act_size,
3434 (off_t)DISK_BLOCK_KB);
3436 for( c = 0; holdp[c]; c++ )
3437 (void)c; /* count number of disks */
3439 /* allocate memory for sched(diskp)->holdp */
3440 for(j = 0; sched(diskp)->holdp && sched(diskp)->holdp[j]; j++)
3441 (void)j; /* Quiet lint */
3442 new_holdp = (assignedhd_t **)alloc(SIZEOF(assignedhd_t*)*(j+c+1));
3443 if (sched(diskp)->holdp) {
3444 memcpy(new_holdp, sched(diskp)->holdp, j * SIZEOF(*new_holdp));
3445 amfree(sched(diskp)->holdp);
3447 sched(diskp)->holdp = new_holdp;
3451 if( j > 0 ) { /* This is a request for additional diskspace. See if we can
3452 * merge assignedhd_t's */
3454 if( sched(diskp)->holdp[j-1]->disk == holdp[0]->disk ) { /* Yes! */
3455 sched(diskp)->holdp[j-1]->reserved += holdp[0]->reserved;
3456 holdp[0]->disk->allocated_space += holdp[0]->reserved;
3457 size = (holdp[0]->reserved>size) ? (off_t)0 : size-holdp[0]->reserved;
3458 qname = quote_string(diskp->name);
3459 hold_debug(1, _("assign_holdingdisk: merging holding disk %s to disk %s:%s, add %lld for reserved %lld, left %lld\n"),
3460 holdingdisk_get_diskdir(
3461 sched(diskp)->holdp[j-1]->disk->hdisk),
3462 diskp->host->hostname, qname,
3463 (long long)holdp[0]->reserved,
3464 (long long)sched(diskp)->holdp[j-1]->reserved,
3473 /* copy assignedhd_s to sched(diskp), adjust allocated_space */
3474 for( ; holdp[i]; i++ ) {
3475 holdp[i]->destname = newvstralloc( holdp[i]->destname,
3476 holdingdisk_get_diskdir(holdp[i]->disk->hdisk), "/",
3477 hd_driver_timestamp, "/",
3478 diskp->host->hostname, ".",
3481 sched(diskp)->holdp[j++] = holdp[i];
3482 holdp[i]->disk->allocated_space += holdp[i]->reserved;
3483 size = (holdp[i]->reserved > size) ? (off_t)0 :
3484 (size - holdp[i]->reserved);
3485 qname = quote_string(diskp->name);
3487 _("assign_holdingdisk: %d assigning holding disk %s to disk %s:%s, reserved %lld, left %lld\n"),
3488 i, holdingdisk_get_diskdir(holdp[i]->disk->hdisk),
3489 diskp->host->hostname, qname,
3490 (long long)holdp[i]->reserved,
3493 holdp[i] = NULL; /* so it doesn't get free()d... */
3495 sched(diskp)->holdp[j] = NULL;
3506 assignedhd_t **holdp;
3507 off_t total = (off_t)0;
3510 char *qname, *hqname, *qdest;
3512 (void)cmd; /* Quiet unused parameter warning */
3514 qname = quote_string(diskp->name);
3515 qdest = quote_string(sched(diskp)->destname);
3516 hold_debug(1, _("adjust_diskspace: %s:%s %s\n"),
3517 diskp->host->hostname, qname, qdest);
3519 holdp = sched(diskp)->holdp;
3521 assert(holdp != NULL);
3523 for( i = 0; holdp[i]; i++ ) { /* for each allocated disk */
3524 diff = holdp[i]->used - holdp[i]->reserved;
3525 total += holdp[i]->used;
3526 holdp[i]->disk->allocated_space += diff;
3527 hqname = quote_string(holdingdisk_name(holdp[i]->disk->hdisk));
3528 hold_debug(1, _("adjust_diskspace: hdisk %s done, reserved %lld used %lld diff %lld alloc %lld dumpers %d\n"),
3529 holdingdisk_name(holdp[i]->disk->hdisk),
3530 (long long)holdp[i]->reserved,
3531 (long long)holdp[i]->used,
3533 (long long)holdp[i]->disk->allocated_space,
3534 holdp[i]->disk->allocated_dumpers );
3535 holdp[i]->reserved += diff;
3539 sched(diskp)->act_size = total;
3541 hold_debug(1, _("adjust_diskspace: after: disk %s:%s used %lld\n"),
3542 diskp->host->hostname, qname,
3543 (long long)sched(diskp)->act_size);
3552 assignedhd_t **holdp;
3555 holdp = sched(diskp)->holdp;
3557 assert(holdp != NULL);
3559 for( i = 0; holdp[i]; i++ ) { /* for each disk */
3560 /* find all files of this dump on that disk, and subtract their
3561 * reserved sizes from the disk's allocated space
3563 holdp[i]->disk->allocated_space -= holdp[i]->used;
3566 holding_file_unlink(holdp[0]->destname); /* no need for the entire list,
3567 * because holding_file_unlink
3568 * will walk through all files
3569 * using cont_filename */
3570 free_assignedhd(sched(diskp)->holdp);
3571 sched(diskp)->holdp = NULL;
3572 sched(diskp)->act_size = (off_t)0;
3575 static assignedhd_t **
3582 char buffer[DISK_BLOCK_BYTES];
3584 assignedhd_t **result;
3587 char dirname[1000], *ch;
3589 char *filename = destname;
3591 memset(buffer, 0, sizeof(buffer));
3592 used = alloc(SIZEOF(off_t) * num_holdalloc);
3593 for(i=0;i<num_holdalloc;i++)
3595 result = alloc(SIZEOF(assignedhd_t *) * (num_holdalloc + 1));
3597 while(filename != NULL && filename[0] != '\0') {
3598 strncpy(dirname, filename, 999);
3600 ch = strrchr(dirname,'/');
3603 ch = strrchr(dirname,'/');
3610 g_fprintf(stderr,_("build_diskspace: bogus filename '%s'\n"), filename);
3616 for(j = 0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3617 if(strcmp(dirname, holdingdisk_get_diskdir(ha->hdisk))==0) {
3621 if (!ha || j >= num_holdalloc) {
3622 fprintf(stderr,_("build_diskspace: holding disk file '%s' is not in a holding disk directory.\n"), filename);
3627 if(stat(filename, &finfo) == -1) {
3628 g_fprintf(stderr, _("build_diskspace: can't stat %s: %s\n"),
3629 filename, strerror(errno));
3634 used[j] += ((off_t)finfo.st_size+(off_t)1023)/(off_t)1024;
3635 if((fd = open(filename,O_RDONLY)) == -1) {
3636 g_fprintf(stderr,_("build_diskspace: open of %s failed: %s\n"),
3637 filename, strerror(errno));
3642 if ((buflen = full_read(fd, buffer, SIZEOF(buffer))) > 0) {;
3643 parse_file_header(buffer, &file, buflen);
3646 filename = file.cont_filename;
3649 for(j = 0, i=0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3650 if(used[j] != (off_t)0) {
3651 result[i] = alloc(SIZEOF(assignedhd_t));
3652 result[i]->disk = ha;
3653 result[i]->reserved = used[j];
3654 result[i]->used = used[j];
3655 result[i]->destname = stralloc(destname);
3673 g_printf(_("driver: hdisk-state time %s"), time_str);
3675 for(ha = holdalloc, dsk = 0; ha != NULL; ha = ha->next, dsk++) {
3676 diff = ha->disksize - ha->allocated_space;
3677 g_printf(_(" hdisk %d: free %lld dumpers %d"), dsk,
3678 (long long)diff, ha->allocated_dumpers);
3687 time_t save_timestamp = sched(dp)->timestamp;
3688 /* setting timestamp to 0 removes the current level from the
3689 * database, so that we ensure that it will not be bumped to the
3690 * next level on the next run. If we didn't do this, dumpdates or
3691 * gnutar-lists might have been updated already, and a bumped
3692 * incremental might be created. */
3693 sched(dp)->timestamp = 0;
3694 update_info_dumper(dp, (off_t)-1, (off_t)-1, (time_t)-1);
3695 sched(dp)->timestamp = save_timestamp;
3698 /* ------------------- */
3707 for(len = 0, p = q.head; p != NULL; len++, p = p->next)
3708 (void)len; /* Quiet lint */
3713 short_dump_state(void)
3718 wall_time = walltime_str(curclock());
3720 g_printf(_("driver: state time %s "), wall_time);
3721 g_printf(_("free kps: %lu space: %lld taper: "),
3723 (long long)free_space());
3724 if(degraded_mode) g_printf(_("DOWN"));
3728 for(taper = tapetable; taper < tapetable+conf_taper_parallel_write;
3730 if (taper->state & TAPER_STATE_DUMP_TO_TAPE ||
3731 taper->state & TAPER_STATE_FILE_TO_TAPE)
3735 g_printf(_("writing"));
3737 g_printf(_("idle"));
3740 for(i = 0; i < inparallel; i++) if(!dmptable[i].busy) nidle++;
3741 g_printf(_(" idle-dumpers: %d"), nidle);
3742 g_printf(_(" qlen tapeq: %d"), queue_length(tapeq));
3743 g_printf(_(" runq: %d"), queue_length(runq));
3744 g_printf(_(" roomq: %d"), queue_length(roomq));
3745 g_printf(_(" wakeup: %d"), (int)sleep_time);
3746 g_printf(_(" driver-idle: %s\n"), _(idle_strings[idle_reason]));
3747 interface_state(wall_time);
3748 holdingdisk_state(wall_time);
3755 char **why_no_new_tape)
3757 TapeAction result = TAPE_ACTION_NO_ACTION;
3766 off_t dump_to_disk_size;
3767 int dump_to_disk_terminated;
3768 int nb_taper_active = nb_sent_new_tape;
3769 int nb_taper_flushing = 0;
3770 int dle_free = 0; /* number of dle that fit on started tape */
3771 int new_dle = 0; /* number of dle that doesn't fit on started tape */
3772 off_t new_data = 0; /* size of dle that doesn't fit on started tape */
3773 off_t data_next_tape = 0;
3774 off_t data_free = 0;
3775 off_t data_lost = 0;
3776 off_t data_lost_next_tape = 0;
3777 gboolean taperflush_criteria;
3778 gboolean flush_criteria;
3780 driver_debug(2, "tape_action: ENTER %p\n", taper);
3782 for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
3783 if (dumper->busy && !sched(dumper->dp)->taper)
3784 dumpers_size += sched(dumper->dp)->est_size;
3786 driver_debug(2, _("dumpers_size: %lld\n"), (long long)dumpers_size);
3789 for(dp = runq.head; dp != NULL; dp = dp->next) {
3790 runq_size += sched(dp)->est_size;
3792 driver_debug(2, _("runq_size: %lld\n"), (long long)runq_size);
3795 for(dp = directq.head; dp != NULL; dp = dp->next) {
3796 directq_size += sched(dp)->est_size;
3798 driver_debug(2, _("directq_size: %lld\n"), (long long)directq_size);
3800 tapeq_size = directq_size;
3801 for(dp = tapeq.head; dp != NULL; dp = dp->next) {
3802 tapeq_size += sched(dp)->act_size;
3805 for (taper1 = tapetable; taper1 < tapetable+conf_taper_parallel_write;
3807 if (taper1->state & TAPER_STATE_FILE_TO_TAPE ||
3808 taper1->state & TAPER_STATE_DUMP_TO_TAPE) {
3809 nb_taper_flushing++;
3813 /* Add what is currently written to tape and in the go. */
3815 for (taper1 = tapetable; taper1 < tapetable+conf_taper_parallel_write;
3817 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
3818 if (taper1->nb_dle < conf_max_dle_by_volume) {
3819 tapeq_size -= taper1->left;
3821 dle_free += (conf_max_dle_by_volume - taper1->nb_dle);
3826 if (taper1->dumper) {
3827 t_size = sched(taper1->disk)->est_size;
3829 t_size = sched(taper1->disk)->act_size;
3831 data_to_go = t_size - taper1->written;
3832 if (data_to_go > taper1->left) {
3833 data_next_tape += data_to_go - taper1->left;
3834 data_lost += taper1->written + taper1->left;
3835 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
3836 dle_free -= (conf_max_dle_by_volume - taper1->nb_dle) + 1;
3842 if (!(taper1->state & TAPER_STATE_TAPE_STARTED)) {
3846 data_free += taper1->left - data_to_go;
3848 tapeq_size += data_to_go;
3852 new_dle = queue_length(tapeq) - dle_free;
3853 driver_debug(2, _("dle_free: %d\n"), dle_free);
3854 driver_debug(2, _("new_dle: %d\n"), new_dle);
3856 if (taperflush == 0 &&
3857 flush_threshold_dumped == 0 &&
3858 flush_threshold_scheduled == 0) {
3859 /* shortcut, will trigger taperflush_criteria and/or flush_criteria */
3862 /* sum the size of the first new-dle in tapeq */
3863 /* they should be the reverse taperalgo */
3864 for (dp = tapeq.head;
3865 dp != NULL && new_dle > 0;
3866 dp = dp->next, new_dle--) {
3867 new_data += sched(dp)->act_size;
3870 if (tapeq_size < new_data) {
3871 tapeq_size = new_data;
3874 driver_debug(2, _("new_data: %lld\n"), (long long)new_data);
3875 data_lost_next_tape = tape_length + data_free - data_next_tape - runq_size - directq_size - tapeq_size;
3876 driver_debug(2, _("data_lost: %lld\n"), (long long)data_lost);
3877 driver_debug(2, _("data_free: %lld\n"), (long long)data_free);
3878 driver_debug(2, _("data_next_tape: %lld\n"), (long long)data_next_tape);
3879 driver_debug(2, _("data_lost_next_tape: %lld\n"), (long long)data_lost_next_tape);
3881 driver_debug(2, _("tapeq_size: %lld\n"), (long long)tapeq_size);
3883 sched_size = runq_size + directq_size + tapeq_size + dumpers_size;
3884 driver_debug(2, _("sched_size: %lld\n"), (long long)sched_size);
3886 dump_to_disk_size = dumpers_size + runq_size + directq_size;
3887 driver_debug(2, _("dump_to_disk_size: %lld\n"), (long long)dump_to_disk_size);
3889 dump_to_disk_terminated = schedule_done && dump_to_disk_size == 0;
3891 for (taper1 = tapetable; taper1 < tapetable + conf_taper_parallel_write;
3893 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
3898 taperflush_criteria = (taperflush < tapeq_size &&
3899 (force_flush == 1 || dump_to_disk_terminated));
3900 flush_criteria = (flush_threshold_dumped < tapeq_size &&
3901 flush_threshold_scheduled < sched_size) ||
3902 taperflush_criteria;
3904 driver_debug(2, "taperflush %lld\n", (long long)taperflush);
3905 driver_debug(2, "flush_threshold_dumped %lld\n", (long long)flush_threshold_dumped);
3906 driver_debug(2, "flush_threshold_scheduled %lld\n", (long long)flush_threshold_scheduled);
3907 driver_debug(2, "force_flush %d\n", force_flush);
3908 driver_debug(2, "dump_to_disk_terminated %d\n", dump_to_disk_terminated);
3909 driver_debug(2, "queue_length(runq) %d\n", queue_length(runq));
3910 driver_debug(2, "queue_length(directq) %d\n", queue_length(directq));
3911 driver_debug(2, "queue_length(tapeq) %d\n", queue_length(tapeq));
3912 driver_debug(2, "taperflush_criteria %d\n", taperflush_criteria);
3913 driver_debug(2, "flush_criteria %d\n", flush_criteria);
3915 // Changing conditionals can produce a driver hang, take care.
3917 // when to start writting to a new tape
3918 if (taper->state & TAPER_STATE_TAPE_REQUESTED) {
3919 driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED\n");
3920 if (current_tape >= conf_runtapes && taper_nb_scan_volume == 0 &&
3921 nb_taper_active == 0) {
3922 *why_no_new_tape = g_strdup_printf(_("%d tapes filled; runtapes=%d "
3923 "does not allow additional tapes"), current_tape, conf_runtapes);
3924 driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED return TAPE_ACTION_NO_NEW_TAPE\n");
3925 result |= TAPE_ACTION_NO_NEW_TAPE;
3926 } else if (current_tape < conf_runtapes &&
3927 taper_nb_scan_volume == 0 &&
3929 (data_lost > data_lost_next_tape) ||
3930 nb_taper_active == 0) &&
3931 (last_started_taper == NULL ||
3932 last_started_taper == taper)) {
3933 driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED return TAPE_ACTION_SCAN\n");
3934 result |= TAPE_ACTION_SCAN;
3936 driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED return TAPE_ACTION_MOVE\n");
3937 result |= TAPE_ACTION_MOVE;
3939 } else if ((taper->state & TAPER_STATE_WAIT_FOR_TAPE) &&
3940 ((taper->state & TAPER_STATE_DUMP_TO_TAPE) || // for dump to tape
3941 !empty(directq) || // if a dle is waiting for a dump to tape
3942 !empty(roomq) || // holding disk constraint
3943 idle_reason == IDLE_NO_DISKSPACE || // holding disk constraint
3944 flush_criteria || // flush criteria
3945 data_lost > data_lost_next_tape
3947 driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NEW_TAPE\n");
3948 result |= TAPE_ACTION_NEW_TAPE;
3949 // when to stop using new tape
3950 } else if ((taper->state & TAPER_STATE_WAIT_FOR_TAPE) &&
3951 (taperflush >= tapeq_size && // taperflush criteria
3952 (force_flush == 1 || // if force_flush
3953 dump_to_disk_terminated)) // or all dump to disk
3955 driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE B\n");
3956 if (nb_taper_active <= 0) {
3957 if (current_tape >= conf_runtapes) {
3958 *why_no_new_tape = g_strdup_printf(_("%d tapes filled; runtapes=%d "
3959 "does not allow additional tapes"), current_tape, conf_runtapes);
3960 driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NO_NEW_TAPE\n");
3961 result |= TAPE_ACTION_NO_NEW_TAPE;
3962 } else if (dumpers_size <= 0) {
3963 *why_no_new_tape = _("taperflush criteria not met");
3964 driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NO_NEW_TAPE\n");
3965 result |= TAPE_ACTION_NO_NEW_TAPE;
3970 // when to start a flush
3971 if (taper->state & TAPER_STATE_IDLE) {
3972 driver_debug(2, "tape_action: TAPER_STATE_IDLE\n");
3973 if (!degraded_mode && (!empty(tapeq) || !empty(directq)) &&
3974 (taper->state & TAPER_STATE_TAPE_STARTED || // tape already started
3975 !empty(roomq) || // holding disk constraint
3976 idle_reason == IDLE_NO_DISKSPACE || // holding disk constraint
3977 flush_criteria)) { // flush
3979 if (nb_taper_flushing == 0) {
3980 driver_debug(2, "tape_action: TAPER_STATE_IDLE return TAPE_ACTION_START_A_FLUSH\n");
3981 result |= TAPE_ACTION_START_A_FLUSH;
3983 driver_debug(2, "tape_action: TAPER_STATE_IDLE return TAPE_ACTION_START_A_FLUSH_FIT\n");
3984 result |= TAPE_ACTION_START_A_FLUSH_FIT;
3987 driver_debug(2, "tape_action: TAPER_STATE_IDLE return TAPE_ACTION_NO_ACTION\n");
3994 no_taper_flushing(void)
3998 for (taper = tapetable; taper < tapetable + conf_taper_parallel_write;
4000 if (taper->state & TAPER_STATE_FILE_TO_TAPE)
4011 for(i = 0; i < inparallel; i++) if(!dmptable[i].busy) nidle++;
4012 return inparallel - nidle;
4023 g_printf("================\n");
4024 g_printf(_("driver state at time %s: %s\n"), walltime_str(curclock()), str);
4025 g_printf(_("free kps: %lu, space: %lld\n"),
4027 (long long)free_space());
4028 if(degraded_mode) g_printf(_("taper: DOWN\n"));
4029 else if(taper->status == TAPER_IDLE) g_printf(_("taper: idle\n"));
4030 else g_printf(_("taper: writing %s:%s.%d est size %lld\n"),
4031 taper->disk->host->hostname, taper->disk->name,
4032 sched(taper->disk)->level,
4033 (long long)sched(taper->disk)->est_size);
4034 for(i = 0; i < inparallel; i++) {
4035 dp = dmptable[i].dp;
4036 if(!dmptable[i].busy)
4037 g_printf(_("%s: idle\n"), dmptable[i].name);
4039 qname = quote_string(dp->name);
4040 g_printf(_("%s: dumping %s:%s.%d est kps %d size %lld time %lu\n"),
4041 dmptable[i].name, dp->host->hostname, qname, sched(dp)->level,
4042 sched(dp)->est_kps, (long long)sched(dp)->est_size, sched(dp)->est_time);
4045 dump_queue("TAPE", tapeq, 5, stdout);
4046 dump_queue("ROOM", roomq, 5, stdout);
4047 dump_queue("RUN ", runq, 5, stdout);
4048 g_printf("================\n");