2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: driver.c 6512 2007-05-24 17:00:24Z ian $
29 * controlling process for the Amanda backup system
33 * XXX possibly modify tape queue to be cognizant of how much room is left on
34 * tape. Probably not effective though, should do this in planner.
48 #include "server_util.h"
49 #include "timestamp.h"
51 #define driver_debug(i, ...) do { \
52 if ((i) <= debug_driver) { \
53 dbprintf(__VA_ARGS__); \
57 #define hold_debug(i, ...) do { \
58 if ((i) <= debug_holding) { \
59 dbprintf(__VA_ARGS__); \
63 static disklist_t waitq; // dle waiting estimate result
64 static disklist_t runq; // dle waiting to be dumped to holding disk
65 static disklist_t directq; // dle waiting to be dumped directly to tape
66 static disklist_t tapeq; // dle on holding disk waiting to be written
68 static disklist_t roomq; // dle waiting for more space on holding disk
69 static int pending_aborts;
70 static int degraded_mode;
71 static off_t reserved_space;
72 static off_t total_disksize;
73 static char *dumper_program;
74 static char *chunker_program;
75 static int inparallel;
76 static int nodump = 0;
77 static off_t tape_length = (off_t)0;
78 static int current_tape = 0;
79 static int conf_max_dle_by_volume;
80 static int conf_taperalgo;
81 static int conf_taper_parallel_write;
82 static int conf_runtapes;
83 static time_t sleep_time;
84 static int idle_reason;
85 static char *driver_timestamp;
86 static char *hd_driver_timestamp;
87 static am_host_t *flushhost = NULL;
88 static int need_degraded=0;
89 static holdalloc_t *holdalloc;
90 static int num_holdalloc;
91 static event_handle_t *dumpers_ev_time = NULL;
92 static event_handle_t *flush_ev_read = NULL;
93 static event_handle_t *schedule_ev_read = NULL;
94 static int conf_flush_threshold_dumped;
95 static int conf_flush_threshold_scheduled;
96 static int conf_taperflush;
97 static off_t flush_threshold_dumped;
98 static off_t flush_threshold_scheduled;
99 static off_t taperflush;
100 static int schedule_done; // 1 if we don't wait for a
101 // schedule from the planner
102 static int force_flush; // All dump are terminated, we
103 // must now respect taper_flush
104 static int taper_nb_scan_volume = 0;
105 static int nb_sent_new_tape = 0;
106 static int taper_started = 0;
107 static taper_t *last_started_taper;
109 static int wait_children(int count);
110 static void wait_for_children(void);
111 static void allocate_bandwidth(netif_t *ip, unsigned long kps);
112 static int assign_holdingdisk(assignedhd_t **holdp, disk_t *diskp);
113 static void adjust_diskspace(disk_t *diskp, cmd_t cmd);
114 static void delete_diskspace(disk_t *diskp);
115 static assignedhd_t **build_diskspace(char *destname);
116 static int client_constrained(disk_t *dp);
117 static void deallocate_bandwidth(netif_t *ip, unsigned long kps);
118 static void dump_schedule(disklist_t *qp, char *str);
119 static assignedhd_t **find_diskspace(off_t size, int *cur_idle,
120 assignedhd_t *preferred);
121 static unsigned long free_kps(netif_t *ip);
122 static off_t free_space(void);
123 static void dumper_chunker_result(disk_t *dp);
124 static void dumper_taper_result(disk_t *dp);
125 static void file_taper_result(disk_t *dp);
126 static void handle_dumper_result(void *);
127 static void handle_chunker_result(void *);
128 static void handle_dumpers_time(void *);
129 static void handle_taper_result(void *);
131 static void holdingdisk_state(char *time_str);
132 static taper_t *idle_taper(void);
133 static taper_t *taper_from_name(char *name);
134 static void interface_state(char *time_str);
135 static int queue_length(disklist_t q);
136 static void read_flush(void *cookie);
137 static void read_schedule(void *cookie);
138 static void short_dump_state(void);
139 static void startaflush(void);
140 static void start_degraded_mode(disklist_t *queuep);
141 static void start_some_dumps(disklist_t *rq);
142 static void continue_port_dumps(void);
143 static void update_failed_dump(disk_t *);
144 static int no_taper_flushing(void);
147 TAPE_ACTION_NO_ACTION = 0,
148 TAPE_ACTION_SCAN = (1 << 0),
149 TAPE_ACTION_NEW_TAPE = (1 << 1),
150 TAPE_ACTION_NO_NEW_TAPE = (1 << 2),
151 TAPE_ACTION_START_A_FLUSH = (1 << 3),
152 TAPE_ACTION_START_A_FLUSH_FIT = (1 << 4),
153 TAPE_ACTION_MOVE = (1 << 5)
156 static TapeAction tape_action(taper_t *taper, char **why_no_new_tape);
158 static const char *idle_strings[] = {
161 #define IDLE_NO_DUMPERS 1
163 #define IDLE_START_WAIT 2
165 #define IDLE_NO_HOLD 3
167 #define IDLE_CLIENT_CONSTRAINED 4
168 T_("client-constrained"),
169 #define IDLE_NO_BANDWIDTH 5
171 #define IDLE_NO_DISKSPACE 6
185 struct fs_usage fsusage;
188 unsigned long reserve = 100;
190 char **result_argv = NULL;
197 config_overrides_t *cfg_ovr = NULL;
198 char *cfg_opt = NULL;
199 holdalloc_t *ha, *ha_last;
200 find_result_t *holding_files;
201 disklist_t holding_disklist = { NULL, NULL };
202 int no_taper = FALSE;
203 int from_client = FALSE;
205 if (argc > 1 && argv && argv[1] && g_str_equal(argv[1], "--version")) {
206 printf("driver-%s\n", VERSION);
211 * Configure program for internationalization:
212 * 1) Only set the message locale for now.
213 * 2) Set textdomain for all amanda related programs to "amanda"
214 * We don't want to be forced to support dozens of message catalogs.
216 setlocale(LC_MESSAGES, "C");
217 textdomain("amanda");
221 setvbuf(stdout, (char *)NULL, (int)_IOLBF, 0);
222 setvbuf(stderr, (char *)NULL, (int)_IOLBF, 0);
226 dbopen(DBG_SUBDIR_SERVER);
228 atexit(wait_for_children);
230 /* Don't die when child closes pipe */
231 signal(SIGPIPE, SIG_IGN);
233 add_amanda_log_handler(amanda_log_stderr);
234 add_amanda_log_handler(amanda_log_trace_log);
238 cfg_ovr = extract_commandline_config_overrides(&argc, &argv);
242 set_config_overrides(cfg_ovr);
243 config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
245 conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
246 read_diskfile(conf_diskfile, &origq);
247 disable_skip_disk(&origq);
248 amfree(conf_diskfile);
250 if (config_errors(NULL) >= CFGERR_WARNINGS) {
251 config_print_errors();
252 if (config_errors(NULL) >= CFGERR_ERRORS) {
253 g_critical(_("errors processing config file"));
257 log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
258 g_printf(_("%s: pid %ld executable %s version %s\n"),
259 get_pname(), (long) getpid(), argv[0], VERSION);
262 if(strcmp(argv[2], "nodump") == 0) {
270 if (strcmp(argv[2], "--no-taper") == 0) {
278 if (strcmp(argv[2], "--from-client") == 0) {
280 from_client = from_client;
286 safe_cd(); /* do this *after* config_init */
288 check_running_as(RUNNING_AS_DUMPUSER);
290 dbrename(get_config_name(), DBG_SUBDIR_SERVER);
292 /* load DLEs from the holding disk, in case there's anything to flush there */
293 search_holding_disk(&holding_files, &holding_disklist);
294 /* note that the dumps are added to the global disklist, so we need not consult
295 * holding_files or holding_disklist after this */
297 amfree(driver_timestamp);
298 /* read timestamp from stdin */
299 while ((line = agets(stdin)) != NULL) {
304 if ( line == NULL ) {
305 error(_("Did not get DATE line from planner"));
308 driver_timestamp = alloc(15);
309 strncpy(driver_timestamp, &line[5], 14);
310 driver_timestamp[14] = '\0';
312 log_add(L_START,_("date %s"), driver_timestamp);
314 gethostname(hostname, SIZEOF(hostname));
315 log_add(L_STATS,_("hostname %s"), hostname);
317 /* check that we don't do many dump in a day and usetimestamps is off */
318 if(strlen(driver_timestamp) == 8) {
320 char *conf_logdir = getconf_str(CNF_LOGDIR);
321 char *logfile = vstralloc(conf_logdir, "/log.",
322 driver_timestamp, ".0", NULL);
323 char *oldlogfile = vstralloc(conf_logdir, "/oldlog/log.",
324 driver_timestamp, ".0", NULL);
325 if(access(logfile, F_OK) == 0 || access(oldlogfile, F_OK) == 0) {
326 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."));
331 hd_driver_timestamp = get_timestamp_from_time(0);
334 hd_driver_timestamp = stralloc(driver_timestamp);
337 taper_program = vstralloc(amlibexecdir, "/", "taper", NULL);
338 dumper_program = vstralloc(amlibexecdir, "/", "dumper", NULL);
339 chunker_program = vstralloc(amlibexecdir, "/", "chunker", NULL);
341 conf_taperalgo = getconf_taperalgo(CNF_TAPERALGO);
342 conf_taper_parallel_write = getconf_int(CNF_TAPER_PARALLEL_WRITE);
343 conf_tapetype = getconf_str(CNF_TAPETYPE);
344 conf_runtapes = getconf_int(CNF_RUNTAPES);
345 conf_max_dle_by_volume = getconf_int(CNF_MAX_DLE_BY_VOLUME);
346 if (conf_taper_parallel_write > conf_runtapes) {
347 conf_taper_parallel_write = conf_runtapes;
349 tape = lookup_tapetype(conf_tapetype);
350 tape_length = tapetype_get_length(tape);
351 g_printf("driver: tape size %lld\n", (long long)tape_length);
352 conf_flush_threshold_dumped = getconf_int(CNF_FLUSH_THRESHOLD_DUMPED);
353 conf_flush_threshold_scheduled = getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED);
354 conf_taperflush = getconf_int(CNF_TAPERFLUSH);
355 flush_threshold_dumped = (conf_flush_threshold_dumped * tape_length) / 100;
356 flush_threshold_scheduled = (conf_flush_threshold_scheduled * tape_length) / 100;
357 taperflush = (conf_taperflush *tape_length) / 100;
359 driver_debug(1, _("flush-threshold-dumped: %lld\n"), (long long)flush_threshold_dumped);
360 driver_debug(1, _("flush-threshold-scheduled: %lld\n"), (long long)flush_threshold_scheduled);
361 driver_debug(1, _("taperflush: %lld\n"), (long long)taperflush);
363 /* set up any configuration-dependent variables */
365 inparallel = getconf_int(CNF_INPARALLEL);
367 reserve = (unsigned long)getconf_int(CNF_RESERVE);
369 total_disksize = (off_t)0;
372 for (il = getconf_identlist(CNF_HOLDINGDISK), dsk = 0;
374 il = il->next, dsk++) {
375 hdp = lookup_holdingdisk(il->data);
376 ha = alloc(SIZEOF(holdalloc_t));
379 /* link the list in the same order as getconf_holdingdisks's results */
388 ha->allocated_dumpers = 0;
389 ha->allocated_space = (off_t)0;
390 ha->disksize = holdingdisk_get_disksize(hdp);
393 if(get_fs_usage(holdingdisk_get_diskdir(hdp), NULL, &fsusage) == -1
394 || access(holdingdisk_get_diskdir(hdp), W_OK) == -1) {
395 log_add(L_WARNING, _("WARNING: ignoring holding disk %s: %s\n"),
396 holdingdisk_get_diskdir(hdp), strerror(errno));
401 /* do the division first to avoid potential integer overflow */
402 if (fsusage.fsu_bavail_top_bit_set)
405 kb_avail = fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize;
407 if(ha->disksize > (off_t)0) {
408 if(ha->disksize > kb_avail) {
410 _("WARNING: %s: %lld KB requested, "
411 "but only %lld KB available."),
412 holdingdisk_get_diskdir(hdp),
413 (long long)ha->disksize,
414 (long long)kb_avail);
415 ha->disksize = kb_avail;
418 /* ha->disksize is negative; use all but that amount */
419 else if(kb_avail < -ha->disksize) {
421 _("WARNING: %s: not %lld KB free."),
422 holdingdisk_get_diskdir(hdp),
423 (long long)-ha->disksize);
424 ha->disksize = (off_t)0;
428 ha->disksize += kb_avail;
430 g_printf(_("driver: adding holding disk %d dir %s size %lld chunksize %lld\n"),
431 dsk, holdingdisk_get_diskdir(hdp),
432 (long long)ha->disksize,
433 (long long)(holdingdisk_get_chunksize(hdp)));
435 newdir = newvstralloc(newdir,
436 holdingdisk_get_diskdir(hdp), "/", hd_driver_timestamp,
438 if(!mkholdingdir(newdir)) {
439 ha->disksize = (off_t)0;
441 total_disksize += ha->disksize;
444 reserved_space = total_disksize * (off_t)(reserve / 100);
446 g_printf(_("reserving %lld out of %lld for degraded-mode dumps\n"),
447 (long long)reserved_space, (long long)free_space());
451 if(inparallel > MAX_DUMPERS) inparallel = MAX_DUMPERS;
453 /* taper takes a while to get going, so start it up right away */
456 startup_tape_process(taper_program, conf_taper_parallel_write, no_taper);
458 /* fire up the dumpers now while we are waiting */
459 if(!nodump) startup_dump_processes(dumper_program, inparallel, driver_timestamp);
462 * Read schedule from stdin. Usually, this is a pipe from planner,
463 * so the effect is that we wait here for the planner to
464 * finish, but meanwhile the taper is rewinding the tape, reading
465 * the label, checking it, writing a new label and all that jazz
466 * in parallel with the planner.
478 taper_nb_wait_reply = 0;
481 if (no_taper || conf_runtapes <= 0) {
482 taper_started = 1; /* we'll pretend the taper started and failed immediately */
485 tapetable[0].state = TAPER_STATE_INIT;
486 taper_nb_wait_reply++;
487 taper_nb_scan_volume++;
488 taper_ev_read = event_register(taper_fd, EV_READFD,
489 handle_taper_result, NULL);
490 taper_cmd(START_TAPER, NULL, tapetable[0].name, 0, driver_timestamp);
493 flush_ev_read = event_register((event_id_t)0, EV_READFD, read_flush, NULL);
495 log_add(L_STATS, _("startup time %s"), walltime_str(curclock()));
497 g_printf(_("driver: start time %s inparallel %d bandwidth %lu diskspace %lld "), walltime_str(curclock()), inparallel,
498 free_kps(NULL), (long long)free_space());
499 g_printf(_(" dir %s datestamp %s driver: drain-ends tapeq %s big-dumpers %s\n"),
500 "OBSOLETE", driver_timestamp, taperalgo2str(conf_taperalgo),
501 getconf_str(CNF_DUMPORDER));
504 schedule_done = nodump;
512 /* mv runq to directq */
513 while (!empty(runq)) {
514 diskp = dequeue_disk(&runq);
515 headqueue_disk(&directq, diskp);
518 run_server_global_scripts(EXECUTE_ON_POST_BACKUP, get_config_name());
520 /* log error for any remaining dumps */
521 while(!empty(directq)) {
522 diskp = dequeue_disk(&directq);
524 if (diskp->to_holdingdisk == HOLD_REQUIRED) {
525 char *qname = quote_string(diskp->name);
526 log_add(L_FAIL, "%s %s %s %d [%s]",
527 diskp->host->hostname, qname, sched(diskp)->datestamp,
529 _("can't dump required holdingdisk"));
532 else if (!degraded_mode) {
533 char *qname = quote_string(diskp->name);
534 log_add(L_FAIL, "%s %s %s %d [%s]",
535 diskp->host->hostname, qname, sched(diskp)->datestamp,
537 _("can't dump in non degraded mode"));
541 char *qname = quote_string(diskp->name);
542 log_add(L_FAIL, "%s %s %s %d [%s]",
543 diskp->host->hostname, qname, sched(diskp)->datestamp,
546 _("can't do degraded dump without holding disk") :
547 diskp->to_holdingdisk != HOLD_NEVER ?
548 _("out of holding space in degraded mode") :
549 _("can't dump 'holdingdisk never' dle in degraded mode"));
554 short_dump_state(); /* for amstatus */
556 g_printf(_("driver: QUITTING time %s telling children to quit\n"),
557 walltime_str(curclock()));
561 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
563 dumper_cmd(dumper, QUIT, NULL, NULL);
568 taper_cmd(QUIT, NULL, NULL, 0, NULL);
571 /* wait for all to die */
575 holding_cleanup(NULL, NULL);
579 check_unfree_serial();
580 g_printf(_("driver: FINISHED time %s\n"), walltime_str(curclock()));
582 log_add(L_FINISH,_("date %s time %s"), driver_timestamp, walltime_str(curclock()));
583 log_add(L_INFO, "pid-done %ld", (long)getpid());
584 amfree(driver_timestamp);
586 amfree(dumper_program);
587 amfree(taper_program);
589 g_strfreev(result_argv);
596 /* sleep up to count seconds, and wait for terminating child process */
597 /* if sleep is negative, this function will not timeout */
598 /* exit once all child process are finished or the timout expired */
599 /* return 0 if no more children to wait */
600 /* return 1 if some children are still alive */
602 wait_children(int count)
614 pid = waitpid((pid_t)-1, &retstat, WNOHANG);
618 if (! WIFEXITED(retstat)) {
620 code = WTERMSIG(retstat);
621 } else if (WEXITSTATUS(retstat) != 0) {
623 code = WEXITSTATUS(retstat);
626 for (dumper = dmptable; dumper < dmptable + inparallel;
628 if (pid == dumper->pid) {
629 who = stralloc(dumper->name);
633 if (dumper->chunker && pid == dumper->chunker->pid) {
634 who = stralloc(dumper->chunker->name);
635 dumper->chunker->pid = -1;
639 if (who == NULL && pid == taper_pid) {
640 who = stralloc("taper");
643 if(what != NULL && who == NULL) {
644 who = stralloc("unknown");
647 log_add(L_WARNING, _("%s pid %u exited with %s %d\n"), who,
648 (unsigned)pid, what, code);
649 g_printf(_("driver: %s pid %u exited with %s %d\n"), who,
650 (unsigned)pid, what, code);
654 } while (pid > 0 || wait_errno == EINTR);
659 } while ((errno != ECHILD) && (count != 0));
660 return (errno != ECHILD);
664 kill_children(int signal)
669 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
670 if (!dumper->down && dumper->pid > 1) {
671 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
672 dumper->name, (unsigned)dumper->pid);
673 if (kill(dumper->pid, signal) == -1 && errno == ESRCH) {
675 dumper->chunker->pid = 0;
677 if (dumper->chunker && dumper->chunker->pid > 1) {
678 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
679 dumper->chunker->name,
680 (unsigned)dumper->chunker->pid);
681 if (kill(dumper->chunker->pid, signal) == -1 &&
683 dumper->chunker->pid = 0;
690 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
691 "taper", (unsigned)taper_pid);
692 if (kill(taper_pid, signal) == -1 && errno == ESRCH)
698 wait_for_children(void)
703 for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
704 if (dumper->pid > 1 && dumper->fd >= 0) {
705 dumper_cmd(dumper, QUIT, NULL, NULL);
706 if (dumper->chunker && dumper->chunker->pid > 1 &&
707 dumper->chunker->fd >= 0)
708 chunker_cmd(dumper->chunker, QUIT, NULL, NULL);
713 if(taper_pid > 1 && taper_fd > 0) {
714 taper_cmd(QUIT, NULL, NULL, 0, NULL);
717 if(wait_children(60) == 0)
720 kill_children(SIGHUP);
721 if(wait_children(60) == 0)
724 kill_children(SIGKILL);
725 if(wait_children(-1) == 0)
730 static void startaflush_tape(taper_t *taper, gboolean *state_changed);
736 gboolean state_changed = FALSE;
738 for(taper = tapetable; taper <= tapetable+conf_taper_parallel_write;
740 if (!(taper->state & TAPER_STATE_DONE) &&
741 taper->state & TAPER_STATE_WAIT_FOR_TAPE) {
742 startaflush_tape(taper, &state_changed);
745 for(taper = tapetable; taper <= tapetable+conf_taper_parallel_write;
747 if (!(taper->state & TAPER_STATE_DONE) &&
748 taper->state & TAPER_STATE_TAPE_REQUESTED) {
749 startaflush_tape(taper, &state_changed);
752 for(taper = tapetable; taper <= tapetable+conf_taper_parallel_write;
754 if (!(taper->state & TAPER_STATE_DONE) &&
755 taper->state & TAPER_STATE_INIT) {
756 startaflush_tape(taper, &state_changed);
759 for(taper = tapetable; taper <= tapetable+conf_taper_parallel_write;
761 if (!(taper->state & TAPER_STATE_DONE) &&
762 taper->state & TAPER_STATE_IDLE) {
763 startaflush_tape(taper, &state_changed);
774 gboolean *state_changed)
779 off_t extra_tapes_size = 0;
782 TapeAction result_tape_action;
783 char *why_no_new_tape = NULL;
786 result_tape_action = tape_action(taper, &why_no_new_tape);
788 if (result_tape_action & TAPE_ACTION_SCAN) {
789 taper->state &= ~TAPER_STATE_TAPE_REQUESTED;
790 taper->state |= TAPER_STATE_WAIT_FOR_TAPE;
791 taper_nb_scan_volume++;
792 taper_cmd(START_SCAN, taper->disk, NULL, 0, NULL);
793 } else if (result_tape_action & TAPE_ACTION_NEW_TAPE) {
794 taper->state &= ~TAPER_STATE_WAIT_FOR_TAPE;
795 taper->state |= TAPER_STATE_WAIT_NEW_TAPE;
797 taper_cmd(NEW_TAPE, taper->disk, NULL, 0, NULL);
798 } else if (result_tape_action & TAPE_ACTION_NO_NEW_TAPE) {
799 taper->state &= ~TAPER_STATE_WAIT_FOR_TAPE;
800 taper_cmd(NO_NEW_TAPE, taper->disk, why_no_new_tape, 0, NULL);
801 taper->state |= TAPER_STATE_DONE;
802 start_degraded_mode(&runq);
803 *state_changed = TRUE;
804 } else if (result_tape_action & TAPE_ACTION_MOVE) {
805 taper_t *taper1 = idle_taper();
807 taper->state &= ~TAPER_STATE_TAPE_REQUESTED;
808 taper->state &= ~TAPER_STATE_WAIT_FOR_TAPE;
809 taper_cmd(TAKE_SCRIBE_FROM, taper->disk, taper1->name, 0 , NULL);
810 taper1->state = TAPER_STATE_DEFAULT;
811 taper->state |= TAPER_STATE_TAPE_STARTED;
812 taper->left = taper1->left;
814 if (last_started_taper == taper1) {
815 last_started_taper = taper;
817 *state_changed = TRUE;
821 if (!degraded_mode &&
822 taper->state & TAPER_STATE_IDLE &&
824 (result_tape_action & TAPE_ACTION_START_A_FLUSH ||
825 result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT)) {
827 int taperalgo = conf_taperalgo;
828 if (result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT) {
829 if (taperalgo == ALGO_FIRST)
830 taperalgo = ALGO_FIRSTFIT;
831 else if (taperalgo == ALGO_LARGEST)
832 taperalgo = ALGO_LARGESTFIT;
833 else if (taperalgo == ALGO_SMALLEST)
834 taperalgo = ALGO_SMALLESTFIT;
835 else if (taperalgo == ALGO_LAST)
836 taperalgo = ALGO_LASTFIT;
839 extra_tapes_size = tape_length * (off_t)(conf_runtapes - current_tape);
840 for (taper1 = tapetable; taper1 < tapetable + conf_taper_parallel_write;
842 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
843 extra_tapes_size += taper1->left;
847 extra_tapes_size -= (sched(dp)->act_size - taper1->written);
851 if (taper->state & TAPER_STATE_TAPE_STARTED) {
852 taper_left = taper->left;
854 taper_left = tape_length;
857 datestamp = sched(tapeq.head)->datestamp;
860 dp = dequeue_disk(&tapeq);
864 while (fit != NULL) {
865 if (sched(fit)->act_size <=
866 (fit->splitsize ? extra_tapes_size : taper_left) &&
867 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
875 if(dp) remove_disk(&tapeq, dp);
878 fit = dp = tapeq.head;
879 while (fit != NULL) {
880 if(sched(fit)->act_size > sched(dp)->act_size &&
881 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
886 if(dp) remove_disk(&tapeq, dp);
888 case ALGO_LARGESTFIT:
890 while (fit != NULL) {
891 if(sched(fit)->act_size <=
892 (fit->splitsize ? extra_tapes_size : taper_left) &&
893 (!dp || sched(fit)->act_size > sched(dp)->act_size) &&
894 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
899 if(dp) remove_disk(&tapeq, dp);
902 fit = dp = tapeq.head;
903 while (fit != NULL) {
904 if (sched(fit)->act_size < sched(dp)->act_size &&
905 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
910 if(dp) remove_disk(&tapeq, dp);
912 case ALGO_SMALLESTFIT:
913 fit = dp = tapeq.head;
914 while (fit != NULL) {
915 if (sched(fit)->act_size <=
916 (fit->splitsize ? extra_tapes_size : taper_left) &&
917 (!dp || sched(fit)->act_size < sched(dp)->act_size) &&
918 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
923 if(dp) remove_disk(&tapeq, dp);
927 remove_disk(&tapeq, dp);
931 while (fit != NULL) {
932 if (sched(fit)->act_size <=
933 (fit->splitsize ? extra_tapes_size : taper_left) &&
934 (!dp || sched(fit)->act_size < sched(dp)->act_size) &&
935 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
940 if(dp) remove_disk(&tapeq, dp);
944 if (!(result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT)) {
945 if(conf_taperalgo != ALGO_SMALLEST) {
947 _("driver: startaflush: Using SMALLEST because nothing fit\n"));
950 fit = dp = tapeq.head;
951 while (fit != NULL) {
952 if (sched(fit)->act_size < sched(dp)->act_size &&
953 strcmp(sched(fit)->datestamp, datestamp) <= 0) {
958 if(dp) remove_disk(&tapeq, dp);
963 taper->dumper = NULL;
964 amfree(taper->input_error);
965 amfree(taper->tape_error);
966 taper->result = LAST_TOK;
967 taper->sendresult = 0;
968 amfree(taper->first_label);
970 taper->state &= ~TAPER_STATE_IDLE;
971 taper->state |= TAPER_STATE_FILE_TO_TAPE;
972 taper->dumper = NULL;
973 qname = quote_string(dp->name);
974 if (taper_nb_wait_reply == 0) {
975 taper_ev_read = event_register(taper_fd, EV_READFD,
976 handle_taper_result, NULL);
978 taper_nb_wait_reply++;
980 sched(dp)->taper = taper;
981 taper_cmd(FILE_WRITE, dp, sched(dp)->destname, sched(dp)->level,
982 sched(dp)->datestamp);
983 g_fprintf(stderr,_("driver: startaflush: %s %s %s %lld %lld\n"),
984 taperalgo2str(taperalgo), dp->host->hostname, qname,
985 (long long)sched(taper->disk)->act_size,
986 (long long)taper->left);
988 *state_changed = TRUE;
999 /* first, check if host is too busy */
1001 if(dp->host->inprogress >= dp->host->maxdumps) {
1005 /* next, check conflict with other dumps on same spindle */
1007 if(dp->spindle == -1) { /* but spindle -1 never conflicts by def. */
1011 for(dp2 = dp->host->disks; dp2 != NULL; dp2 = dp2->hostnext)
1012 if(dp2->inprogress && dp2->spindle == dp->spindle) {
1026 int dumper_to_holding,
1028 disk_t **delayed_diskp,
1029 disk_t **diskp_accept,
1030 assignedhd_t ***holdp_accept,
1031 off_t extra_tapes_size)
1033 assignedhd_t **holdp=NULL;
1035 if (diskp->host->start_t > now) {
1036 *cur_idle = max(*cur_idle, IDLE_START_WAIT);
1037 if (*delayed_diskp == NULL || sleep_time > diskp->host->start_t) {
1038 *delayed_diskp = diskp;
1039 sleep_time = diskp->host->start_t;
1041 } else if(diskp->start_t > now) {
1042 *cur_idle = max(*cur_idle, IDLE_START_WAIT);
1043 if (*delayed_diskp == NULL || sleep_time > diskp->start_t) {
1044 *delayed_diskp = diskp;
1045 sleep_time = diskp->start_t;
1047 } else if (diskp->host->netif->curusage > 0 &&
1048 sched(diskp)->est_kps > free_kps(diskp->host->netif)) {
1049 *cur_idle = max(*cur_idle, IDLE_NO_BANDWIDTH);
1050 } else if (!taper && sched(diskp)->no_space) {
1051 *cur_idle = max(*cur_idle, IDLE_NO_DISKSPACE);
1052 } else if (!taper && diskp->to_holdingdisk == HOLD_NEVER) {
1053 *cur_idle = max(*cur_idle, IDLE_NO_HOLD);
1054 } else if (extra_tapes_size && sched(diskp)->est_size > extra_tapes_size) {
1055 *cur_idle = max(*cur_idle, IDLE_NO_DISKSPACE);
1057 } else if (!taper && (holdp =
1058 find_diskspace(sched(diskp)->est_size, cur_idle, NULL)) == NULL) {
1059 *cur_idle = max(*cur_idle, IDLE_NO_DISKSPACE);
1060 if (empty(tapeq) && dumper_to_holding == 0 && rq != &directq && no_taper_flushing()) {
1061 remove_disk(rq, diskp);
1062 if (diskp->to_holdingdisk != HOLD_REQUIRED) {
1063 enqueue_disk(&directq, diskp);
1064 diskp->to_holdingdisk = HOLD_NEVER;
1066 if (empty(*rq)) force_flush = 1;
1068 } else if (client_constrained(diskp)) {
1069 free_assignedhd(holdp);
1070 *cur_idle = max(*cur_idle, IDLE_CLIENT_CONSTRAINED);
1073 /* disk fits, dump it */
1074 int accept = !*diskp_accept;
1077 case 's': accept = (sched(diskp)->est_size < sched(*diskp_accept)->est_size);
1079 case 'S': accept = (sched(diskp)->est_size > sched(*diskp_accept)->est_size);
1081 case 't': accept = (sched(diskp)->est_time < sched(*diskp_accept)->est_time);
1083 case 'T': accept = (sched(diskp)->est_time > sched(*diskp_accept)->est_time);
1085 case 'b': accept = (sched(diskp)->est_kps < sched(*diskp_accept)->est_kps);
1087 case 'B': accept = (sched(diskp)->est_kps > sched(*diskp_accept)->est_kps);
1089 default: log_add(L_WARNING, _("Unknown dumporder character \'%c\', using 's'.\n"),
1091 accept = (sched(diskp)->est_size < sched(*diskp_accept)->est_size);
1096 if( !*diskp_accept || !degraded_mode || diskp->priority >= (*diskp_accept)->priority) {
1097 if(*holdp_accept) free_assignedhd(*holdp_accept);
1098 *diskp_accept = diskp;
1099 *holdp_accept = holdp;
1102 free_assignedhd(holdp);
1106 free_assignedhd(holdp);
1115 const time_t now = time(NULL);
1117 disk_t *diskp, *delayed_diskp, *diskp_accept, *diskp_next;
1119 assignedhd_t **holdp=NULL, **holdp_accept;
1128 int dumper_to_holding = 0;
1129 gboolean state_changed = FALSE;
1131 /* don't start any actual dumps until the taper is started */
1132 if (!taper_started) return;
1134 idle_reason = IDLE_NO_DUMPERS;
1137 if(dumpers_ev_time != NULL) {
1138 event_release(dumpers_ev_time);
1139 dumpers_ev_time = NULL;
1142 for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
1143 if (dumper->busy && dumper->dp->to_holdingdisk != HOLD_NEVER) {
1144 dumper_to_holding++;
1147 for (dumper = dmptable; dumper < dmptable+inparallel; dumper++) {
1149 if( dumper->busy || dumper->down) {
1153 if (dumper->ev_read != NULL) {
1154 event_release(dumper->ev_read);
1155 dumper->ev_read = NULL;
1159 * A potential problem with starting from the bottom of the dump time
1160 * distribution is that a slave host will have both one of the shortest
1161 * and one of the longest disks, so starting its shortest disk first will
1162 * tie up the host and eliminate its longest disk from consideration the
1163 * first pass through. This could cause a big delay in starting that long
1164 * disk, which could drag out the whole night's dumps.
1166 * While starting from the top of the dump time distribution solves the
1167 * above problem, this turns out to be a bad idea, because the big dumps
1168 * will almost certainly pack the holding disk completely, leaving no
1169 * room for even one small dump to start. This ends up shutting out the
1170 * small-end dumpers completely (they stay idle).
1172 * The introduction of multiple simultaneous dumps to one host alleviates
1173 * the biggest&smallest dumps problem: both can be started at the
1177 diskp_accept = NULL;
1178 holdp_accept = NULL;
1179 delayed_diskp = NULL;
1181 cur_idle = NOT_IDLE;
1183 dumporder = getconf_str(CNF_DUMPORDER);
1184 if(strlen(dumporder) > (size_t)(dumper-dmptable)) {
1185 dumptype = dumporder[dumper-dmptable];
1188 if(dumper-dmptable < 3)
1196 if (!empty(directq)) {
1197 taper = idle_taper();
1199 TapeAction result_tape_action;
1200 char *why_no_new_tape = NULL;
1201 result_tape_action = tape_action(taper, &why_no_new_tape);
1202 if (result_tape_action & TAPE_ACTION_START_A_FLUSH ||
1203 result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT) {
1204 off_t extra_tapes_size = 0;
1207 if (result_tape_action & TAPE_ACTION_START_A_FLUSH_FIT) {
1208 extra_tapes_size = tape_length *
1209 (off_t)(conf_runtapes - current_tape);
1210 for (taper1 = tapetable;
1211 taper1 < tapetable + conf_taper_parallel_write;
1213 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
1214 extra_tapes_size += taper1->left;
1218 extra_tapes_size -= (sched(dp)->est_size -
1224 for (diskp = directq.head; diskp != NULL;
1225 diskp = diskp_next) {
1226 diskp_next = diskp->next;
1227 allow_dump_dle(diskp, taper, dumptype, &directq, now,
1228 dumper_to_holding, &cur_idle,
1229 &delayed_diskp, &diskp_accept,
1230 &holdp_accept, extra_tapes_size);
1233 diskp = diskp_accept;
1234 holdp = holdp_accept;
1244 if (diskp == NULL) {
1245 for(diskp = rq->head; diskp != NULL; diskp = diskp_next) {
1246 diskp_next = diskp->next;
1247 assert(diskp->host != NULL && sched(diskp) != NULL);
1249 allow_dump_dle(diskp, NULL, dumptype, rq, now,
1250 dumper_to_holding, &cur_idle, &delayed_diskp,
1251 &diskp_accept, &holdp_accept, 0);
1253 diskp = diskp_accept;
1254 holdp = holdp_accept;
1257 idle_reason = max(idle_reason, cur_idle);
1258 if (diskp == NULL && idle_reason == IDLE_NO_DISKSPACE) {
1259 /* continue flush waiting for new tape */
1264 * If we have no disk at this point, and there are disks that
1265 * are delayed, then schedule a time event to call this dumper
1266 * with the disk with the shortest delay.
1268 if (diskp == NULL && delayed_diskp != NULL) {
1269 assert(sleep_time > now);
1271 dumpers_ev_time = event_register((event_id_t)sleep_time, EV_TIME,
1272 handle_dumpers_time, &runq);
1274 } else if (diskp != NULL && taper == NULL) {
1275 sched(diskp)->act_size = (off_t)0;
1276 allocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1277 sched(diskp)->activehd = assign_holdingdisk(holdp, diskp);
1279 sched(diskp)->destname = newstralloc(sched(diskp)->destname,
1280 sched(diskp)->holdp[0]->destname);
1281 diskp->host->inprogress++; /* host is now busy */
1282 diskp->inprogress = 1;
1283 sched(diskp)->dumper = dumper;
1284 sched(diskp)->timestamp = now;
1285 amfree(diskp->dataport_list);
1287 dumper->busy = 1; /* dumper is now busy */
1288 dumper->dp = diskp; /* link disk to dumper */
1289 remove_disk(rq, diskp); /* take it off the run queue */
1291 sched(diskp)->origsize = (off_t)-1;
1292 sched(diskp)->dumpsize = (off_t)-1;
1293 sched(diskp)->dumptime = (time_t)0;
1294 sched(diskp)->tapetime = (time_t)0;
1295 chunker = dumper->chunker = &chktable[dumper - dmptable];
1296 chunker->result = LAST_TOK;
1297 dumper->result = LAST_TOK;
1298 startup_chunk_process(chunker,chunker_program);
1299 chunker_cmd(chunker, START, NULL, driver_timestamp);
1300 chunker->dumper = dumper;
1301 chunker_cmd(chunker, PORT_WRITE, diskp, NULL);
1302 cmd = getresult(chunker->fd, 1, &result_argc, &result_argv);
1304 assignedhd_t **h=NULL;
1306 char *qname = quote_string(diskp->name);
1308 g_printf(_("driver: did not get PORT from %s for %s:%s\n"),
1309 chunker->name, diskp->host->hostname, qname);
1313 deallocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1314 h = sched(diskp)->holdp;
1315 activehd = sched(diskp)->activehd;
1316 h[activehd]->used = 0;
1317 h[activehd]->disk->allocated_dumpers--;
1318 adjust_diskspace(diskp, DONE);
1319 delete_diskspace(diskp);
1320 diskp->host->inprogress--;
1321 diskp->inprogress = 0;
1322 sched(diskp)->dumper = NULL;
1325 sched(diskp)->dump_attempted++;
1326 free_serial_dp(diskp);
1327 if(sched(diskp)->dump_attempted < 2)
1328 enqueue_disk(rq, diskp);
1331 dumper->ev_read = event_register((event_id_t)dumper->fd, EV_READFD,
1332 handle_dumper_result, dumper);
1333 chunker->ev_read = event_register((event_id_t)chunker->fd, EV_READFD,
1334 handle_chunker_result, chunker);
1335 dumper->output_port = atoi(result_argv[1]);
1336 amfree(diskp->dataport_list);
1337 diskp->dataport_list = stralloc(result_argv[2]);
1339 if (diskp->host->pre_script == 0) {
1340 run_server_host_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
1341 get_config_name(), diskp->host);
1342 diskp->host->pre_script = 1;
1344 run_server_dle_scripts(EXECUTE_ON_PRE_DLE_BACKUP,
1345 get_config_name(), diskp,
1346 sched(diskp)->level);
1347 dumper_cmd(dumper, PORT_DUMP, diskp, NULL);
1349 diskp->host->start_t = now + 15;
1350 if (empty(*rq)) force_flush = 1;
1353 g_strfreev(result_argv);
1355 } else if (diskp != NULL && taper != NULL) { /* dump to tape */
1356 sched(diskp)->act_size = (off_t)0;
1357 allocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1358 diskp->host->inprogress++; /* host is now busy */
1359 diskp->inprogress = 1;
1360 sched(diskp)->dumper = dumper;
1361 sched(diskp)->taper = taper;
1362 sched(diskp)->timestamp = now;
1363 dumper->chunker = NULL;
1364 amfree(diskp->dataport_list);
1366 dumper->busy = 1; /* dumper is now busy */
1367 dumper->dp = diskp; /* link disk to dumper */
1368 remove_disk(&directq, diskp); /* take it off the direct queue */
1370 sched(diskp)->origsize = (off_t)-1;
1371 sched(diskp)->dumpsize = (off_t)-1;
1372 sched(diskp)->dumptime = (time_t)0;
1373 sched(diskp)->tapetime = (time_t)0;
1374 dumper->result = LAST_TOK;
1375 taper->result = LAST_TOK;
1376 taper->input_error = NULL;
1377 taper->tape_error = NULL;
1378 taper->disk = diskp;
1379 taper->first_label = NULL;
1381 taper->dumper = dumper;
1382 taper->state |= TAPER_STATE_DUMP_TO_TAPE;
1383 taper->state &= ~TAPER_STATE_IDLE;
1385 if (taper_nb_wait_reply == 0) {
1386 taper_ev_read = event_register(taper_fd, EV_READFD,
1387 handle_taper_result, NULL);
1390 taper_nb_wait_reply++;
1391 taper_cmd(PORT_WRITE, diskp, NULL, sched(diskp)->level,
1392 sched(diskp)->datestamp);
1393 diskp->host->start_t = now + 15;
1395 state_changed = TRUE;
1398 if (state_changed) {
1404 * This gets called when a dumper is delayed for some reason. It may
1405 * be because a disk has a delayed start, or amanda is constrained
1406 * by network or disk limits.
1410 handle_dumpers_time(
1413 disklist_t *runq = cookie;
1414 event_release(dumpers_ev_time);
1415 dumpers_ev_time = NULL;
1416 start_some_dumps(runq);
1427 g_printf(_("dump of driver schedule %s:\n--------\n"), str);
1429 for(dp = qp->head; dp != NULL; dp = dp->next) {
1430 qname = quote_string(dp->name);
1431 g_printf(" %-20s %-25s lv %d t %5lu s %lld p %d\n",
1432 dp->host->hostname, qname, sched(dp)->level,
1433 sched(dp)->est_time,
1434 (long long)sched(dp)->est_size, sched(dp)->priority);
1437 g_printf("--------\n");
1441 start_degraded_mode(
1442 /*@keep@*/ disklist_t *queuep)
1446 off_t est_full_size;
1449 newq.head = newq.tail = 0;
1451 dump_schedule(queuep, _("before start degraded mode"));
1453 est_full_size = (off_t)0;
1454 while(!empty(*queuep)) {
1455 dp = dequeue_disk(queuep);
1457 qname = quote_string(dp->name);
1458 if(sched(dp)->level != 0)
1459 /* go ahead and do the disk as-is */
1460 enqueue_disk(&newq, dp);
1462 if (reserved_space + est_full_size + sched(dp)->est_size
1463 <= total_disksize) {
1464 enqueue_disk(&newq, dp);
1465 est_full_size += sched(dp)->est_size;
1467 else if(sched(dp)->degr_level != -1) {
1468 sched(dp)->level = sched(dp)->degr_level;
1469 sched(dp)->dumpdate = sched(dp)->degr_dumpdate;
1470 sched(dp)->est_nsize = sched(dp)->degr_nsize;
1471 sched(dp)->est_csize = sched(dp)->degr_csize;
1472 sched(dp)->est_time = sched(dp)->degr_time;
1473 sched(dp)->est_kps = sched(dp)->degr_kps;
1474 enqueue_disk(&newq, dp);
1477 log_add(L_FAIL, "%s %s %s %d [%s]",
1478 dp->host->hostname, qname, sched(dp)->datestamp,
1479 sched(dp)->level, sched(dp)->degr_mesg);
1485 /*@i@*/ *queuep = newq;
1488 dump_schedule(queuep, _("after start degraded mode"));
1493 continue_port_dumps(void)
1497 int active_dumpers=0, busy_dumpers=0, i;
1500 /* First we try to grant diskspace to some dumps waiting for it. */
1501 for( dp = roomq.head; dp; dp = ndp ) {
1503 /* find last holdingdisk used by this dump */
1504 for( i = 0, h = sched(dp)->holdp; h[i+1]; i++ ) {
1505 (void)h; /* Quiet lint */
1507 /* find more space */
1508 h = find_diskspace( sched(dp)->est_size - sched(dp)->act_size,
1509 &active_dumpers, h[i] );
1511 for(dumper = dmptable; dumper < dmptable + inparallel &&
1512 dumper->dp != dp; dumper++) {
1513 (void)dp; /* Quiet lint */
1515 assert( dumper < dmptable + inparallel );
1516 sched(dp)->activehd = assign_holdingdisk( h, dp );
1517 chunker_cmd( dumper->chunker, CONTINUE, dp, NULL );
1519 remove_disk( &roomq, dp );
1523 /* So for some disks there is less holding diskspace available than
1524 * was asked for. Possible reasons are
1525 * a) diskspace has been allocated for other dumps which are
1526 * still running or already being written to tape
1527 * b) all other dumps have been suspended due to lack of diskspace
1528 * Case a) is not a problem. We just wait for the diskspace to
1529 * be freed by moving the current disk to a queue.
1530 * If case b) occurs, we have a deadlock situation. We select
1531 * a dump from the queue to be aborted and abort it. It will
1532 * be retried directly to tape.
1534 for(dp=NULL, dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
1535 if( dumper->busy ) {
1537 if( !find_disk(&roomq, dumper->dp) ) {
1538 if (dumper->chunker) {
1542 sched(dp)->est_size > sched(dumper->dp)->est_size ) {
1547 if((dp != NULL) && (active_dumpers == 0) && (busy_dumpers > 0) &&
1548 ((no_taper_flushing() && empty(tapeq)) || degraded_mode) &&
1549 pending_aborts == 0 ) { /* case b */
1550 sched(dp)->no_space = 1;
1551 /* At this time, dp points to the dump with the smallest est_size.
1552 * We abort that dump, hopefully not wasting too much time retrying it.
1554 remove_disk( &roomq, dp );
1555 chunker_cmd(sched(dp)->dumper->chunker, ABORT, NULL, _("Not enough holding disk space"));
1556 dumper_cmd( sched(dp)->dumper, ABORT, NULL, _("Not enough holding disk space"));
1563 handle_taper_result(
1564 void *cookie G_GNUC_UNUSED)
1573 taper_t *taper = NULL;
1578 assert(cookie == NULL);
1585 cmd = getresult(taper_fd, 1, &result_argc, &result_argv);
1590 if(result_argc != 2) {
1591 error(_("error: [taper FAILED result_argc != 2: %d"), result_argc);
1597 for (i=0; i < conf_taper_parallel_write; i++) {
1598 if (strcmp(tapetable[i].name, result_argv[1]) == 0) {
1599 taper= &tapetable[i];
1602 assert(taper != NULL);
1605 taper->state &= ~TAPER_STATE_INIT;
1606 taper->state |= TAPER_STATE_RESERVATION;
1607 taper->state |= TAPER_STATE_IDLE;
1608 amfree(taper->first_label);
1609 taper_nb_wait_reply--;
1610 taper_nb_scan_volume--;
1611 last_started_taper = taper;
1612 if (taper_nb_wait_reply == 0) {
1613 event_release(taper_ev_read);
1614 taper_ev_read = NULL;
1616 start_some_dumps(&runq);
1620 case FAILED: /* FAILED <handle> INPUT-* TAPE-* <input err mesg> <tape err mesg> */
1621 if(result_argc != 6) {
1622 error(_("error: [taper FAILED result_argc != 6: %d"), result_argc);
1626 dp = serial2disk(result_argv[1]);
1627 taper = sched(dp)->taper;
1628 assert(dp == taper->disk);
1630 free_serial(result_argv[1]);
1632 qname = quote_string(dp->name);
1633 g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1634 walltime_str(curclock()), dp->host->hostname, qname);
1637 if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
1638 taper->input_error = newstralloc(taper->input_error, result_argv[4]);
1639 taper->result = FAILED;
1642 } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
1643 taper->tape_error = newstralloc(taper->tape_error,
1644 _("Taper protocol error"));
1645 taper->result = FAILED;
1646 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1647 dp->host->hostname, qname, sched(dp)->datestamp,
1648 sched(dp)->level, taper->tape_error);
1652 if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
1653 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1654 taper->tape_error = newstralloc(taper->tape_error, result_argv[5]);
1655 taper->result = FAILED;
1658 } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
1659 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1660 taper->tape_error = newstralloc(taper->tape_error,
1661 _("Taper protocol error"));
1662 taper->result = FAILED;
1663 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1664 dp->host->hostname, qname, sched(dp)->datestamp,
1665 sched(dp)->level, taper->tape_error);
1671 taper->result = cmd;
1675 case PARTIAL: /* PARTIAL <handle> INPUT-* TAPE-* <stat mess> <input err mesg> <tape err mesg>*/
1676 case DONE: /* DONE <handle> INPUT-GOOD TAPE-GOOD <stat mess> <input err mesg> <tape err mesg> */
1677 if(result_argc != 7) {
1678 error(_("error: [taper PARTIAL result_argc != 7: %d"), result_argc);
1682 dp = serial2disk(result_argv[1]);
1683 taper = sched(dp)->taper;
1684 assert(dp == taper->disk);
1686 free_serial(result_argv[1]);
1688 qname = quote_string(dp->name);
1689 g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1690 walltime_str(curclock()), dp->host->hostname, qname);
1693 if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
1694 taper->input_error = newstralloc(taper->input_error, result_argv[5]);
1695 taper->result = FAILED;
1698 } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
1699 taper->tape_error = newstralloc(taper->tape_error,
1700 _("Taper protocol error"));
1701 taper->result = FAILED;
1702 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1703 dp->host->hostname, qname, sched(dp)->datestamp,
1704 sched(dp)->level, taper->tape_error);
1708 if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
1709 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1710 taper->tape_error = newstralloc(taper->tape_error, result_argv[6]);
1711 taper->result = FAILED;
1714 } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
1715 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1716 taper->tape_error = newstralloc(taper->tape_error,
1717 _("Taper protocol error"));
1718 taper->result = FAILED;
1719 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1720 dp->host->hostname, qname, sched(dp)->datestamp,
1721 sched(dp)->level, taper->tape_error);
1726 s = strstr(result_argv[4], " kb ");
1729 sched(dp)->dumpsize = atol(s);
1731 s = strstr(result_argv[4], " bytes ");
1734 sched(dp)->dumpsize = atol(s)/1024;
1738 taper->result = cmd;
1743 case PARTDONE: /* PARTDONE <handle> <label> <fileno> <kbytes> <stat> */
1744 dp = serial2disk(result_argv[1]);
1745 taper = sched(dp)->taper;
1746 assert(dp == taper->disk);
1747 if (result_argc != 6) {
1748 error(_("error [taper PARTDONE result_argc != 6: %d]"),
1752 if (!taper->first_label) {
1753 amfree(taper->first_label);
1754 taper->first_label = stralloc(result_argv[2]);
1755 taper->first_fileno = OFF_T_ATOI(result_argv[3]);
1757 taper->written += OFF_T_ATOI(result_argv[4]);
1758 if (taper->written > sched(taper->disk)->act_size)
1759 sched(taper->disk)->act_size = taper->written;
1762 s = strstr(result_argv[5], " kb ");
1767 s = strstr(result_argv[5], " bytes ");
1770 partsize = atol(s)/1024;
1773 taper->left -= partsize;
1777 case REQUEST_NEW_TAPE: /* REQUEST-NEW-TAPE <handle> */
1778 if (result_argc != 2) {
1779 error(_("error [taper REQUEST_NEW_TAPE result_argc != 2: %d]"),
1784 dp = serial2disk(result_argv[1]);
1785 taper = sched(dp)->taper;
1786 if (taper->state & TAPER_STATE_DONE) {
1787 taper_cmd(NO_NEW_TAPE, taper->disk, "taper found no tape", 0, NULL);
1789 taper->state &= ~TAPER_STATE_TAPE_STARTED;
1790 taper->state |= TAPER_STATE_TAPE_REQUESTED;
1792 start_some_dumps(&runq);
1797 case NEW_TAPE: /* NEW-TAPE <handle> <label> */
1798 if (result_argc != 3) {
1799 error(_("error [taper NEW_TAPE result_argc != 3: %d]"),
1805 taper_nb_scan_volume--;
1806 dp = serial2disk(result_argv[1]);
1807 taper = sched(dp)->taper;
1808 /* Update our tape counter and reset taper->left */
1811 taper->left = tape_length;
1812 taper->state &= ~TAPER_STATE_WAIT_NEW_TAPE;
1813 taper->state |= TAPER_STATE_TAPE_STARTED;
1814 last_started_taper = NULL;
1816 /* start a new worker */
1817 for (i = 0; i < conf_taper_parallel_write ; i++) {
1818 taper1 = &tapetable[i];
1819 if (need_degraded == 0 &&
1820 taper1->state == TAPER_STATE_DEFAULT) {
1821 taper1->state = TAPER_STATE_INIT;
1822 if (taper_nb_wait_reply == 0) {
1823 taper_ev_read = event_register(taper_fd, EV_READFD,
1824 handle_taper_result, NULL);
1826 taper_nb_wait_reply++;
1827 taper_nb_scan_volume++;
1828 taper_cmd(START_TAPER, NULL, taper1->name, 0,
1835 case NO_NEW_TAPE: /* NO-NEW-TAPE <handle> */
1836 if (result_argc != 2) {
1837 error(_("error [taper NO_NEW_TAPE result_argc != 2: %d]"),
1842 taper_nb_scan_volume--;
1843 dp = serial2disk(result_argv[1]);
1844 taper = sched(dp)->taper;
1845 taper->state |= TAPER_STATE_DONE;
1846 last_started_taper = NULL;
1847 start_degraded_mode(&runq);
1850 case DUMPER_STATUS: /* DUMPER-STATUS <handle> */
1851 if (result_argc != 2) {
1852 error(_("error [taper DUMPER_STATUS result_argc != 2: %d]"),
1856 dp = serial2disk(result_argv[1]);
1857 taper = sched(dp)->taper;
1858 if (taper->dumper->result == LAST_TOK) {
1859 taper->sendresult = 1;
1861 if( taper->dumper->result == DONE) {
1862 taper_cmd(DONE, dp, NULL, 0, NULL);
1864 taper_cmd(FAILED, dp, NULL, 0, NULL);
1869 case TAPE_ERROR: /* TAPE-ERROR <name> <err mess> */
1871 if (strcmp(result_argv[1], "SETUP") == 0) {
1872 taper_nb_wait_reply = 0;
1873 taper_nb_scan_volume = 0;
1875 taper = taper_from_name(result_argv[1]);
1876 taper->state = TAPER_STATE_DONE;
1878 q = quote_string(result_argv[2]);
1879 log_add(L_WARNING, _("Taper error: %s"), q);
1882 taper->tape_error = newstralloc(taper->tape_error,
1886 taper_nb_wait_reply--;
1887 taper_nb_scan_volume--;
1889 if (taper_nb_wait_reply == 0) {
1890 event_release(taper_ev_read);
1891 taper_ev_read = NULL;
1894 if (schedule_done && !degraded_mode) {
1895 start_degraded_mode(&runq);
1897 start_some_dumps(&runq);
1900 case PORT: /* PORT <name> <handle> <port> <dataport_list> */
1901 dp = serial2disk(result_argv[2]);
1902 taper = sched(dp)->taper;
1903 dumper = sched(dp)->dumper;
1904 dumper->output_port = atoi(result_argv[3]);
1905 amfree(dp->dataport_list);
1906 dp->dataport_list = stralloc(result_argv[4]);
1908 amfree(taper->input_error);
1909 amfree(taper->tape_error);
1910 amfree(taper->first_label);
1912 taper->state |= TAPER_STATE_DUMP_TO_TAPE;
1914 if (dp->host->pre_script == 0) {
1915 run_server_host_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
1916 get_config_name(), dp->host);
1917 dp->host->pre_script = 1;
1919 run_server_dle_scripts(EXECUTE_ON_PRE_DLE_BACKUP,
1920 get_config_name(), dp,
1922 /* tell the dumper to dump to a port */
1923 dumper_cmd(dumper, PORT_DUMP, dp, NULL);
1924 dp->host->start_t = time(NULL) + 15;
1925 amfree(dp->dataport_list);
1927 taper->state |= TAPER_STATE_DUMP_TO_TAPE;
1929 dumper->ev_read = event_register(dumper->fd, EV_READFD,
1930 handle_dumper_result, dumper);
1934 log_add(L_WARNING, _("Taper protocol error"));
1936 * Since we received a taper error, we can't send anything more
1937 * to the taper. Go into degraded mode to try to get everthing
1938 * onto disk. Later, these dumps can be flushed to a new tape.
1939 * The tape queue is zapped so that it appears empty in future
1940 * checks. If there are dumps waiting for diskspace to be freed,
1946 _("going into degraded mode because of taper component error."));
1949 for (taper = tapetable;
1950 taper < tapetable + conf_taper_parallel_write;
1952 if (taper && taper->disk) {
1953 taper->tape_error = newstralloc(taper->tape_error,"BOGUS");
1954 taper->result = cmd;
1955 if (taper->dumper) {
1956 if (taper->dumper->result != LAST_TOK) {
1957 // Dumper already returned it's result
1958 dumper_taper_result(taper->disk);
1961 file_taper_result(taper->disk);
1968 if(taper_ev_read != NULL) {
1969 event_release(taper_ev_read);
1970 taper_ev_read = NULL;
1971 taper_nb_wait_reply = 0;
1973 start_degraded_mode(&runq);
1974 tapeq.head = tapeq.tail = NULL;
1980 error(_("driver received unexpected token (%s) from taper"),
1985 g_strfreev(result_argv);
1987 if (taper && taper->disk && taper->result != LAST_TOK) {
1988 if (taper->nb_dle >= conf_max_dle_by_volume) {
1989 taper_cmd(CLOSE_VOLUME, dp, NULL, 0, NULL);
1992 if (taper->dumper->result != LAST_TOK) {
1993 // Dumper already returned it's result
1994 dumper_taper_result(taper->disk);
1997 file_taper_result(taper->disk);
2001 } while(areads_dataready(taper_fd));
2002 start_some_dumps(&runq);
2012 char *qname = quote_string(dp->name);
2014 taper = sched(dp)->taper;
2015 if (taper->result == DONE) {
2016 update_info_taper(dp, taper->first_label, taper->first_fileno,
2020 sched(dp)->taper_attempted += 1;
2022 if (taper->input_error) {
2023 g_printf("driver: taper failed %s %s: %s\n",
2024 dp->host->hostname, qname, taper->input_error);
2025 if (strcmp(sched(dp)->datestamp, driver_timestamp) == 0) {
2026 if(sched(dp)->taper_attempted >= 2) {
2027 log_add(L_FAIL, _("%s %s %s %d [too many taper retries after holding disk error: %s]"),
2028 dp->host->hostname, qname, sched(dp)->datestamp,
2029 sched(dp)->level, taper->input_error);
2030 g_printf("driver: taper failed %s %s, too many taper retry after holding disk error\n",
2031 dp->host->hostname, qname);
2032 amfree(sched(dp)->destname);
2033 amfree(sched(dp)->dumpdate);
2034 amfree(sched(dp)->degr_dumpdate);
2035 amfree(sched(dp)->degr_mesg);
2036 amfree(sched(dp)->datestamp);
2039 log_add(L_INFO, _("%s %s %s %d [Will retry dump because of holding disk error: %s]"),
2040 dp->host->hostname, qname, sched(dp)->datestamp,
2041 sched(dp)->level, taper->input_error);
2042 g_printf("driver: taper will retry %s %s because of holding disk error\n",
2043 dp->host->hostname, qname);
2044 if (dp->to_holdingdisk != HOLD_REQUIRED) {
2045 dp->to_holdingdisk = HOLD_NEVER;
2046 sched(dp)->dump_attempted -= 1;
2047 headqueue_disk(&directq, dp);
2049 amfree(sched(dp)->destname);
2050 amfree(sched(dp)->dumpdate);
2051 amfree(sched(dp)->degr_dumpdate);
2052 amfree(sched(dp)->degr_mesg);
2053 amfree(sched(dp)->datestamp);
2058 amfree(sched(dp)->destname);
2059 amfree(sched(dp)->dumpdate);
2060 amfree(sched(dp)->degr_dumpdate);
2061 amfree(sched(dp)->degr_mesg);
2062 amfree(sched(dp)->datestamp);
2065 } else if (taper->tape_error) {
2066 g_printf("driver: taper failed %s %s with tape error: %s\n",
2067 dp->host->hostname, qname, taper->tape_error);
2068 if(sched(dp)->taper_attempted >= 2) {
2069 log_add(L_FAIL, _("%s %s %s %d [too many taper retries]"),
2070 dp->host->hostname, qname, sched(dp)->datestamp,
2072 g_printf("driver: taper failed %s %s, too many taper retry\n",
2073 dp->host->hostname, qname);
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);
2081 g_printf("driver: taper will retry %s %s\n",
2082 dp->host->hostname, qname);
2083 /* Re-insert into taper queue. */
2084 headqueue_disk(&tapeq, dp);
2086 } else if (taper->result != DONE) {
2087 g_printf("driver: taper failed %s %s without error\n",
2088 dp->host->hostname, qname);
2090 delete_diskspace(dp);
2091 amfree(sched(dp)->destname);
2092 amfree(sched(dp)->dumpdate);
2093 amfree(sched(dp)->degr_dumpdate);
2094 amfree(sched(dp)->degr_mesg);
2095 amfree(sched(dp)->datestamp);
2101 taper->state &= ~TAPER_STATE_FILE_TO_TAPE;
2102 taper->state |= TAPER_STATE_IDLE;
2103 amfree(taper->input_error);
2104 amfree(taper->tape_error);
2106 taper_nb_wait_reply--;
2107 if (taper_nb_wait_reply == 0) {
2108 event_release(taper_ev_read);
2109 taper_ev_read = NULL;
2112 /* continue with those dumps waiting for diskspace */
2113 continue_port_dumps();
2114 start_some_dumps(&runq);
2119 dumper_taper_result(
2126 dumper = sched(dp)->dumper;
2127 taper = sched(dp)->taper;
2130 if(dumper->result == DONE && taper->result == DONE) {
2131 update_info_dumper(dp, sched(dp)->origsize,
2132 sched(dp)->dumpsize, sched(dp)->dumptime);
2133 update_info_taper(dp, taper->first_label, taper->first_fileno,
2135 qname = quote_string(dp->name); /*quote to take care of spaces*/
2137 log_add(L_STATS, _("estimate %s %s %s %d [sec %ld nkb %lld ckb %lld kps %lu]"),
2138 dp->host->hostname, qname, sched(dp)->datestamp,
2140 sched(dp)->est_time, (long long)sched(dp)->est_nsize,
2141 (long long)sched(dp)->est_csize,
2142 sched(dp)->est_kps);
2145 update_failed_dump(dp);
2148 sched(dp)->dump_attempted += 1;
2149 sched(dp)->taper_attempted += 1;
2151 if((dumper->result != DONE || taper->result != DONE) &&
2152 sched(dp)->dump_attempted <= 1 &&
2153 sched(dp)->taper_attempted <= 1) {
2154 enqueue_disk(&directq, dp);
2157 if(dumper->ev_read != NULL) {
2158 event_release(dumper->ev_read);
2159 dumper->ev_read = NULL;
2161 taper_nb_wait_reply--;
2162 if (taper_nb_wait_reply == 0 && taper_ev_read != NULL) {
2163 event_release(taper_ev_read);
2164 taper_ev_read = NULL;
2166 taper->state &= ~TAPER_STATE_DUMP_TO_TAPE;
2167 taper->state |= TAPER_STATE_IDLE;
2168 amfree(taper->input_error);
2169 amfree(taper->tape_error);
2171 dp->host->inprogress -= 1;
2173 deallocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
2174 taper->dumper = NULL;
2176 sched(dp)->dumper = NULL;
2177 sched(dp)->taper = NULL;
2178 start_some_dumps(&runq);
2187 /* Use an already started taper first */
2188 for (taper = tapetable; taper < tapetable + conf_taper_parallel_write;
2190 if ((taper->state & TAPER_STATE_IDLE) &&
2191 (taper->state & TAPER_STATE_TAPE_STARTED) &&
2192 !(taper->state & TAPER_STATE_DONE) &&
2193 !(taper->state & TAPER_STATE_FILE_TO_TAPE) &&
2194 !(taper->state & TAPER_STATE_FILE_TO_TAPE))
2197 for (taper = tapetable; taper < tapetable + conf_taper_parallel_write;
2199 if ((taper->state & TAPER_STATE_IDLE) &&
2200 (taper->state & TAPER_STATE_RESERVATION) &&
2201 !(taper->state & TAPER_STATE_DONE) &&
2202 !(taper->state & TAPER_STATE_FILE_TO_TAPE) &&
2203 !(taper->state & TAPER_STATE_FILE_TO_TAPE))
2215 for (taper = tapetable; taper < tapetable+conf_taper_parallel_write;
2217 if (strcmp(taper->name, name) == 0) return taper;
2223 dumper_chunker_result(
2228 assignedhd_t **h=NULL;
2235 dumper = sched(dp)->dumper;
2236 chunker = dumper->chunker;
2240 h = sched(dp)->holdp;
2241 activehd = sched(dp)->activehd;
2243 if(dumper->result == DONE && chunker->result == DONE) {
2244 update_info_dumper(dp, sched(dp)->origsize,
2245 sched(dp)->dumpsize, sched(dp)->dumptime);
2246 qname = quote_string(dp->name);/*quote to take care of spaces*/
2248 log_add(L_STATS, _("estimate %s %s %s %d [sec %ld nkb %lld ckb %lld kps %lu]"),
2249 dp->host->hostname, qname, sched(dp)->datestamp,
2251 sched(dp)->est_time, (long long)sched(dp)->est_nsize,
2252 (long long)sched(dp)->est_csize,
2253 sched(dp)->est_kps);
2256 update_failed_dump(dp);
2259 deallocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
2261 is_partial = dumper->result != DONE || chunker->result != DONE;
2262 rename_tmp_holding(sched(dp)->destname, !is_partial);
2263 holding_set_origsize(sched(dp)->destname, sched(dp)->origsize);
2266 for( i = 0, h = sched(dp)->holdp; i < activehd; i++ ) {
2267 dummy += h[i]->used;
2270 size = holding_file_size(sched(dp)->destname, 0);
2271 h[activehd]->used = size - dummy;
2272 h[activehd]->disk->allocated_dumpers--;
2273 adjust_diskspace(dp, DONE);
2275 sched(dp)->dump_attempted += 1;
2277 if((dumper->result != DONE || chunker->result != DONE) &&
2278 sched(dp)->dump_attempted <= 1) {
2279 delete_diskspace(dp);
2280 if (sched(dp)->no_space) {
2281 enqueue_disk(&directq, dp);
2283 enqueue_disk(&runq, dp);
2286 else if(size > (off_t)DISK_BLOCK_KB) {
2287 enqueue_disk(&tapeq, dp);
2290 delete_diskspace(dp);
2294 dp->host->inprogress -= 1;
2297 waitpid(chunker->pid, NULL, 0 );
2298 aclose(chunker->fd);
2303 if (chunker->result == ABORT_FINISHED)
2305 continue_port_dumps();
2307 * Wakeup any dumpers that are sleeping because of network
2308 * or disk constraints.
2310 start_some_dumps(&runq);
2316 handle_dumper_result(
2319 /* uses global pending_aborts */
2320 dumper_t *dumper = cookie;
2322 disk_t *dp, *sdp, *dp1;
2328 assert(dumper != NULL);
2331 assert(sched(dp) != NULL);
2336 cmd = getresult(dumper->fd, 1, &result_argc, &result_argv);
2339 /* result_argv[1] always contains the serial number */
2340 sdp = serial2disk(result_argv[1]);
2342 error(_("Invalid serial number %s"), result_argv[1]);
2343 g_assert_not_reached();
2347 qname = quote_string(dp->name);
2350 case DONE: /* DONE <handle> <origsize> <dumpsize> <dumptime> <errstr> */
2351 if(result_argc != 6) {
2352 error(_("error [dumper DONE result_argc != 6: %d]"), result_argc);
2356 sched(dp)->origsize = OFF_T_ATOI(result_argv[2]);
2357 sched(dp)->dumptime = TIME_T_ATOI(result_argv[4]);
2359 g_printf(_("driver: finished-cmd time %s %s dumped %s:%s\n"),
2360 walltime_str(curclock()), dumper->name,
2361 dp->host->hostname, qname);
2364 dumper->result = cmd;
2368 case TRYAGAIN: /* TRY-AGAIN <handle> <errstr> */
2370 * Requeue this disk, and fall through to the FAILED
2373 if(sched(dp)->dump_attempted) {
2374 char *qname = quote_string(dp->name);
2375 char *qerr = quote_string(result_argv[2]);
2376 log_add(L_FAIL, _("%s %s %s %d [too many dumper retry: %s]"),
2377 dp->host->hostname, qname, sched(dp)->datestamp,
2378 sched(dp)->level, qerr);
2379 g_printf(_("driver: dump failed %s %s %s, too many dumper retry: %s\n"),
2380 result_argv[1], dp->host->hostname, qname, qerr);
2385 case FAILED: /* FAILED <handle> <errstr> */
2386 /*free_serial(result_argv[1]);*/
2387 dumper->result = cmd;
2390 case ABORT_FINISHED: /* ABORT-FINISHED <handle> */
2392 * We sent an ABORT from the NO-ROOM case because this dump
2393 * wasn't going to fit onto the holding disk. We now need to
2394 * clean up the remains of this image, and try to finish
2395 * other dumps that are waiting on disk space.
2397 assert(pending_aborts);
2398 /*free_serial(result_argv[1]);*/
2399 dumper->result = cmd;
2403 /* either EOF or garbage from dumper. Turn it off */
2404 log_add(L_WARNING, _("%s pid %ld is messed up, ignoring it.\n"),
2405 dumper->name, (long)dumper->pid);
2406 if (dumper->ev_read) {
2407 event_release(dumper->ev_read);
2408 dumper->ev_read = NULL;
2412 dumper->down = 1; /* mark it down so it isn't used again */
2414 /* if it was dumping something, zap it and try again */
2415 if(sched(dp)->dump_attempted) {
2416 log_add(L_FAIL, _("%s %s %s %d [%s died]"),
2417 dp->host->hostname, qname, sched(dp)->datestamp,
2418 sched(dp)->level, dumper->name);
2420 log_add(L_WARNING, _("%s died while dumping %s:%s lev %d."),
2421 dumper->name, dp->host->hostname, qname,
2424 dumper->result = cmd;
2431 g_strfreev(result_argv);
2437 run_server_dle_scripts(EXECUTE_ON_POST_DLE_BACKUP,
2438 get_config_name(), dp, sched(dp)->level);
2439 /* check dump not yet started */
2440 for (dp1=runq.head; dp1 != NULL; dp1 = dp1->next) {
2441 if (dp1->host == dp->host)
2444 /* check direct to tape dump */
2445 for (dp1=directq.head; dp1 != NULL; dp1 = dp1->next) {
2446 if (dp1->host == dp->host)
2449 /* check dumping dle */
2450 for (dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
2451 if (dumper->busy && dumper->dp != dp &&
2452 dumper->dp->host == dp->host)
2455 if (last_dump && dp->host->post_script == 0) {
2456 if (dp->host->post_script == 0) {
2457 run_server_host_scripts(EXECUTE_ON_POST_HOST_BACKUP,
2458 get_config_name(), dp->host);
2459 dp->host->post_script = 1;
2464 taper = sched(dp)->taper;
2465 /* send the dumper result to the chunker */
2466 if (dumper->chunker) {
2467 if (dumper->chunker->down == 0 && dumper->chunker->fd != -1 &&
2468 dumper->chunker->result == LAST_TOK) {
2470 chunker_cmd(dumper->chunker, DONE, dp, NULL);
2473 chunker_cmd(dumper->chunker, FAILED, dp, NULL);
2476 if( dumper->result != LAST_TOK &&
2477 dumper->chunker->result != LAST_TOK)
2478 dumper_chunker_result(dp);
2479 } else { /* send the dumper result to the taper */
2481 taper_cmd(DONE, dp, NULL, 0, NULL);
2483 taper_cmd(FAILED, dp, NULL, 0, NULL);
2485 taper->sendresult = 0;
2486 if (taper->dumper && taper->result != LAST_TOK) {
2487 dumper_taper_result(dp);
2490 } while(areads_dataready(dumper->fd));
2495 handle_chunker_result(
2498 chunker_t *chunker = cookie;
2499 assignedhd_t **h=NULL;
2509 assert(chunker != NULL);
2510 dumper = chunker->dumper;
2511 assert(dumper != NULL);
2514 assert(sched(dp) != NULL);
2515 assert(sched(dp)->destname != NULL);
2516 assert(dp != NULL && sched(dp) != NULL && sched(dp)->destname);
2518 if(sched(dp)->holdp) {
2519 h = sched(dp)->holdp;
2520 activehd = sched(dp)->activehd;
2526 cmd = getresult(chunker->fd, 1, &result_argc, &result_argv);
2529 /* result_argv[1] always contains the serial number */
2530 sdp = serial2disk(result_argv[1]);
2532 error(_("Invalid serial number %s"), result_argv[1]);
2533 g_assert_not_reached();
2539 case PARTIAL: /* PARTIAL <handle> <dumpsize> <errstr> */
2540 case DONE: /* DONE <handle> <dumpsize> <errstr> */
2541 if(result_argc != 4) {
2542 error(_("error [chunker %s result_argc != 4: %d]"), cmdstr[cmd],
2546 /*free_serial(result_argv[1]);*/
2548 sched(dp)->dumpsize = (off_t)atof(result_argv[2]);
2550 qname = quote_string(dp->name);
2551 g_printf(_("driver: finished-cmd time %s %s chunked %s:%s\n"),
2552 walltime_str(curclock()), chunker->name,
2553 dp->host->hostname, qname);
2557 event_release(chunker->ev_read);
2559 chunker->result = cmd;
2563 case TRYAGAIN: /* TRY-AGAIN <handle> <errstr> */
2564 event_release(chunker->ev_read);
2566 chunker->result = cmd;
2569 case FAILED: /* FAILED <handle> <errstr> */
2570 /*free_serial(result_argv[1]);*/
2572 event_release(chunker->ev_read);
2574 chunker->result = cmd;
2578 case NO_ROOM: /* NO-ROOM <handle> <missing_size> */
2579 if (!h || activehd < 0) { /* should never happen */
2580 error(_("!h || activehd < 0"));
2583 h[activehd]->used -= OFF_T_ATOI(result_argv[2]);
2584 h[activehd]->reserved -= OFF_T_ATOI(result_argv[2]);
2585 h[activehd]->disk->allocated_space -= OFF_T_ATOI(result_argv[2]);
2586 h[activehd]->disk->disksize -= OFF_T_ATOI(result_argv[2]);
2589 case RQ_MORE_DISK: /* RQ-MORE-DISK <handle> */
2590 if (!h || activehd < 0) { /* should never happen */
2591 error(_("!h || activehd < 0"));
2594 h[activehd]->disk->allocated_dumpers--;
2595 h[activehd]->used = h[activehd]->reserved;
2596 if( h[++activehd] ) { /* There's still some allocated space left.
2597 * Tell the dumper about it. */
2598 sched(dp)->activehd++;
2599 chunker_cmd( chunker, CONTINUE, dp, NULL );
2600 } else { /* !h[++activehd] - must allocate more space */
2601 sched(dp)->act_size = sched(dp)->est_size; /* not quite true */
2602 sched(dp)->est_size = (sched(dp)->act_size/(off_t)20) * (off_t)21; /* +5% */
2603 sched(dp)->est_size = am_round(sched(dp)->est_size, (off_t)DISK_BLOCK_KB);
2604 if (sched(dp)->est_size < sched(dp)->act_size + 2*DISK_BLOCK_KB)
2605 sched(dp)->est_size += 2 * DISK_BLOCK_KB;
2606 h = find_diskspace( sched(dp)->est_size - sched(dp)->act_size,
2610 /* No diskspace available. The reason for this will be
2611 * determined in continue_port_dumps(). */
2612 enqueue_disk( &roomq, dp );
2613 continue_port_dumps();
2614 /* continue flush waiting for new tape */
2617 /* OK, allocate space for disk and have chunker continue */
2618 sched(dp)->activehd = assign_holdingdisk( h, dp );
2619 chunker_cmd( chunker, CONTINUE, dp, NULL );
2625 case ABORT_FINISHED: /* ABORT-FINISHED <handle> */
2627 * We sent an ABORT from the NO-ROOM case because this dump
2628 * wasn't going to fit onto the holding disk. We now need to
2629 * clean up the remains of this image, and try to finish
2630 * other dumps that are waiting on disk space.
2632 /*assert(pending_aborts);*/
2634 /*free_serial(result_argv[1]);*/
2636 event_release(chunker->ev_read);
2638 chunker->result = cmd;
2643 /* either EOF or garbage from chunker. Turn it off */
2644 log_add(L_WARNING, _("%s pid %ld is messed up, ignoring it.\n"),
2645 chunker->name, (long)chunker->pid);
2647 /* if it was dumping something, zap it and try again */
2648 g_assert(h && activehd >= 0);
2649 qname = quote_string(dp->name);
2650 if(sched(dp)->dump_attempted) {
2651 log_add(L_FAIL, _("%s %s %s %d [%s died]"),
2652 dp->host->hostname, qname, sched(dp)->datestamp,
2653 sched(dp)->level, chunker->name);
2655 log_add(L_WARNING, _("%s died while dumping %s:%s lev %d."),
2656 chunker->name, dp->host->hostname, qname,
2662 event_release(chunker->ev_read);
2664 chunker->result = cmd;
2671 g_strfreev(result_argv);
2673 if(chunker->result != LAST_TOK && chunker->dumper->result != LAST_TOK)
2674 dumper_chunker_result(dp);
2676 } while(areads_dataready(chunker->fd));
2687 char *hostname, *diskname, *datestamp;
2691 char *inpline = NULL;
2696 char *qdestname = NULL;
2697 char *conf_infofile;
2699 (void)cookie; /* Quiet unused parameter warning */
2701 event_release(flush_ev_read);
2702 flush_ev_read = NULL;
2704 /* read schedule from stdin */
2705 conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE));
2706 if (open_infofile(conf_infofile)) {
2707 error(_("could not open info db \"%s\""), conf_infofile);
2710 amfree(conf_infofile);
2712 for(line = 0; (inpline = agets(stdin)) != NULL; free(inpline)) {
2716 if (inpline[0] == '\0')
2722 skip_whitespace(s, ch); /* find the command */
2724 error(_("flush line %d: syntax error (no command)"), line);
2728 skip_non_whitespace(s, ch);
2731 if(strcmp(command,"ENDFLUSH") == 0) {
2735 if(strcmp(command,"FLUSH") != 0) {
2736 error(_("flush line %d: syntax error (%s != FLUSH)"), line, command);
2740 skip_whitespace(s, ch); /* find the hostname */
2742 error(_("flush line %d: syntax error (no hostname)"), line);
2746 skip_non_whitespace(s, ch);
2749 skip_whitespace(s, ch); /* find the diskname */
2751 error(_("flush line %d: syntax error (no diskname)"), line);
2755 skip_quoted_string(s, ch);
2756 s[-1] = '\0'; /* terminate the disk name */
2757 diskname = unquote_string(qname);
2759 skip_whitespace(s, ch); /* find the datestamp */
2761 error(_("flush line %d: syntax error (no datestamp)"), line);
2765 skip_non_whitespace(s, ch);
2768 skip_whitespace(s, ch); /* find the level number */
2769 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2770 error(_("flush line %d: syntax error (bad level)"), line);
2773 skip_integer(s, ch);
2775 skip_whitespace(s, ch); /* find the filename */
2777 error(_("flush line %d: syntax error (no filename)"), line);
2781 skip_quoted_string(s, ch);
2783 destname = unquote_string(qdestname);
2785 holding_file_get_dumpfile(destname, &file);
2786 if( file.type != F_DUMPFILE) {
2787 if( file.type != F_CONT_DUMPFILE )
2788 log_add(L_INFO, _("%s: ignoring cruft file."), destname);
2791 dumpfile_free_data(&file);
2795 if(strcmp(hostname, file.name) != 0 ||
2796 strcmp(diskname, file.disk) != 0 ||
2797 strcmp(datestamp, file.datestamp) != 0) {
2798 log_add(L_INFO, _("disk %s:%s not consistent with file %s"),
2799 hostname, diskname, destname);
2802 dumpfile_free_data(&file);
2807 dp = lookup_disk(file.name, file.disk);
2810 log_add(L_INFO, _("%s: disk %s:%s not in database, skipping it."),
2811 destname, file.name, file.disk);
2813 dumpfile_free_data(&file);
2817 if (file.dumplevel < 0 || file.dumplevel > 399) {
2818 log_add(L_INFO, _("%s: ignoring file with bogus dump level %d."),
2819 destname, file.dumplevel);
2821 dumpfile_free_data(&file);
2825 if (holding_file_size(destname,1) <= 0) {
2826 log_add(L_INFO, "%s: removing file with no data.", destname);
2827 holding_file_unlink(destname);
2829 dumpfile_free_data(&file);
2833 dp1 = (disk_t *)alloc(SIZEOF(disk_t));
2835 dp1->next = dp1->prev = NULL;
2837 /* add it to the flushhost list */
2839 flushhost = alloc(SIZEOF(am_host_t));
2840 flushhost->next = NULL;
2841 flushhost->hostname = stralloc("FLUSHHOST");
2842 flushhost->up = NULL;
2843 flushhost->features = NULL;
2845 dp1->hostnext = flushhost->disks;
2846 flushhost->disks = dp1;
2848 sp = (sched_t *) alloc(SIZEOF(sched_t));
2849 sp->destname = destname;
2850 sp->level = file.dumplevel;
2851 sp->dumpdate = NULL;
2852 sp->degr_dumpdate = NULL;
2853 sp->degr_mesg = NULL;
2854 sp->datestamp = stralloc(file.datestamp);
2855 sp->est_nsize = (off_t)0;
2856 sp->est_csize = (off_t)0;
2859 sp->origsize = file.orig_size;
2861 sp->degr_level = -1;
2862 sp->dump_attempted = 0;
2863 sp->taper_attempted = 0;
2864 sp->act_size = holding_file_size(destname, 0);
2865 sp->holdp = build_diskspace(destname);
2866 if(sp->holdp == NULL) continue;
2869 sp->timestamp = (time_t)0;
2871 dp1->up = (char *)sp;
2873 enqueue_disk(&tapeq, dp1);
2874 dumpfile_free_data(&file);
2881 schedule_ev_read = event_register((event_id_t)0, EV_READFD,
2882 read_schedule, NULL);
2894 int level, line, priority;
2895 char *dumpdate, *degr_dumpdate, *degr_mesg;
2897 time_t time, degr_time;
2898 time_t *time_p = &time;
2899 time_t *degr_time_p = °r_time;
2900 off_t nsize, csize, degr_nsize, degr_csize;
2901 unsigned long kps, degr_kps;
2902 char *hostname, *features, *diskname, *datestamp, *inpline = NULL;
2906 off_t flush_size = (off_t)0;
2911 long long degr_nsize_;
2912 long long degr_csize_;
2913 GPtrArray *errarray;
2915 (void)cookie; /* Quiet unused parameter warning */
2917 event_release(schedule_ev_read);
2918 schedule_ev_read = NULL;
2920 /* read schedule from stdin */
2922 for(line = 0; (inpline = agets(stdin)) != NULL; free(inpline)) {
2923 if (inpline[0] == '\0')
2930 skip_whitespace(s, ch); /* find the command */
2932 error(_("schedule line %d: syntax error (no command)"), line);
2936 skip_non_whitespace(s, ch);
2939 if(strcmp(command,"DUMP") != 0) {
2940 error(_("schedule line %d: syntax error (%s != DUMP)"), line, command);
2944 skip_whitespace(s, ch); /* find the host name */
2946 error(_("schedule line %d: syntax error (no host name)"), line);
2950 skip_non_whitespace(s, ch);
2953 skip_whitespace(s, ch); /* find the feature list */
2955 error(_("schedule line %d: syntax error (no feature list)"), line);
2959 skip_non_whitespace(s, ch);
2962 skip_whitespace(s, ch); /* find the disk name */
2964 error(_("schedule line %d: syntax error (no disk name)"), line);
2968 skip_quoted_string(s, ch);
2969 s[-1] = '\0'; /* terminate the disk name */
2970 diskname = unquote_string(qname);
2972 skip_whitespace(s, ch); /* find the datestamp */
2974 error(_("schedule line %d: syntax error (no datestamp)"), line);
2978 skip_non_whitespace(s, ch);
2981 skip_whitespace(s, ch); /* find the priority number */
2982 if(ch == '\0' || sscanf(s - 1, "%d", &priority) != 1) {
2983 error(_("schedule line %d: syntax error (bad priority)"), line);
2986 skip_integer(s, ch);
2988 skip_whitespace(s, ch); /* find the level number */
2989 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2990 error(_("schedule line %d: syntax error (bad level)"), line);
2993 skip_integer(s, ch);
2995 skip_whitespace(s, ch); /* find the dump date */
2997 error(_("schedule line %d: syntax error (bad dump date)"), line);
3001 skip_non_whitespace(s, ch);
3004 skip_whitespace(s, ch); /* find the native size */
3006 if(ch == '\0' || sscanf(s - 1, "%lld", &nsize_) != 1) {
3007 error(_("schedule line %d: syntax error (bad nsize)"), line);
3010 nsize = (off_t)nsize_;
3011 skip_integer(s, ch);
3013 skip_whitespace(s, ch); /* find the compressed size */
3015 if(ch == '\0' || sscanf(s - 1, "%lld", &csize_) != 1) {
3016 error(_("schedule line %d: syntax error (bad csize)"), line);
3019 csize = (off_t)csize_;
3020 skip_integer(s, ch);
3022 skip_whitespace(s, ch); /* find the time number */
3023 if(ch == '\0' || sscanf(s - 1, "%lld", &time_) != 1) {
3024 error(_("schedule line %d: syntax error (bad estimated time)"), line);
3027 *time_p = (time_t)time_;
3028 skip_integer(s, ch);
3030 skip_whitespace(s, ch); /* find the kps number */
3031 if(ch == '\0' || sscanf(s - 1, "%lu", &kps) != 1) {
3032 error(_("schedule line %d: syntax error (bad kps)"), line);
3035 skip_integer(s, ch);
3037 degr_dumpdate = NULL; /* flag if degr fields found */
3038 skip_whitespace(s, ch); /* find the degr level number */
3042 skip_quoted_string(s, ch);
3043 s[-1] = '\0'; /* terminate degr mesg */
3044 degr_mesg = unquote_string(qname);
3046 degr_nsize = (off_t)0;
3047 degr_csize = (off_t)0;
3048 degr_time = (time_t)0;
3050 } else if (ch != '\0') {
3051 if(sscanf(s - 1, "%d", °r_level) != 1) {
3052 error(_("schedule line %d: syntax error (bad degr level)"), line);
3055 skip_integer(s, ch);
3057 skip_whitespace(s, ch); /* find the degr dump date */
3059 error(_("schedule line %d: syntax error (bad degr dump date)"), line);
3062 degr_dumpdate = s - 1;
3063 skip_non_whitespace(s, ch);
3066 skip_whitespace(s, ch); /* find the degr native size */
3067 degr_nsize_ = (off_t)0;
3068 if(ch == '\0' || sscanf(s - 1, "%lld", °r_nsize_) != 1) {
3069 error(_("schedule line %d: syntax error (bad degr nsize)"), line);
3072 degr_nsize = (off_t)degr_nsize_;
3073 skip_integer(s, ch);
3075 skip_whitespace(s, ch); /* find the degr compressed size */
3076 degr_csize_ = (off_t)0;
3077 if(ch == '\0' || sscanf(s - 1, "%lld", °r_csize_) != 1) {
3078 error(_("schedule line %d: syntax error (bad degr csize)"), line);
3081 degr_csize = (off_t)degr_csize_;
3082 skip_integer(s, ch);
3084 skip_whitespace(s, ch); /* find the degr time number */
3085 if(ch == '\0' || sscanf(s - 1, "%lld", &time_) != 1) {
3086 error(_("schedule line %d: syntax error (bad degr estimated time)"), line);
3089 *degr_time_p = (time_t)time_;
3090 skip_integer(s, ch);
3092 skip_whitespace(s, ch); /* find the degr kps number */
3093 if(ch == '\0' || sscanf(s - 1, "%lu", °r_kps) != 1) {
3094 error(_("schedule line %d: syntax error (bad degr kps)"), line);
3097 skip_integer(s, ch);
3099 error(_("schedule line %d: no degraded estimate or message"), line);
3102 dp = lookup_disk(hostname, diskname);
3105 _("schedule line %d: %s:'%s' not in disklist, ignored"),
3106 line, hostname, qname);
3111 sp = (sched_t *) alloc(SIZEOF(sched_t));
3114 sp->dumpdate = stralloc(dumpdate);
3115 sp->est_nsize = DISK_BLOCK_KB + nsize; /* include header */
3116 sp->est_csize = DISK_BLOCK_KB + csize; /* include header */
3117 /* round estimate to next multiple of DISK_BLOCK_KB */
3118 sp->est_csize = am_round(sp->est_csize, DISK_BLOCK_KB);
3119 sp->est_size = sp->est_csize;
3120 sp->est_time = time;
3122 sp->priority = priority;
3123 sp->datestamp = stralloc(datestamp);
3126 sp->degr_level = degr_level;
3127 sp->degr_dumpdate = stralloc(degr_dumpdate);
3128 sp->degr_nsize = DISK_BLOCK_KB + degr_nsize;
3129 sp->degr_csize = DISK_BLOCK_KB + degr_csize;
3130 /* round estimate to next multiple of DISK_BLOCK_KB */
3131 sp->degr_csize = am_round(sp->degr_csize, DISK_BLOCK_KB);
3132 sp->degr_time = degr_time;
3133 sp->degr_kps = degr_kps;
3134 sp->degr_mesg = NULL;
3136 sp->degr_level = -1;
3137 sp->degr_dumpdate = NULL;
3138 sp->degr_mesg = degr_mesg;
3142 sp->dump_attempted = 0;
3143 sp->taper_attempted = 0;
3149 sp->timestamp = (time_t)0;
3150 sp->destname = NULL;
3153 dp->up = (char *) sp;
3154 if(dp->host->features == NULL) {
3155 dp->host->features = am_string_to_feature(features);
3156 if (!dp->host->features) {
3158 _("Invalid feature string from client '%s'"),
3160 dp->host->features = am_set_default_feature_set();
3163 remove_disk(&waitq, dp);
3165 errarray = validate_optionstr(dp);
3166 if (errarray->len > 0) {
3168 for (i=0; i < errarray->len; i++) {
3169 log_add(L_FAIL, _("%s %s %s 0 [%s]"),
3170 dp->host->hostname, qname,
3172 (char *)g_ptr_array_index(errarray, i));
3177 if (dp->data_path == DATA_PATH_DIRECTTCP &&
3178 dp->to_holdingdisk == HOLD_AUTO) {
3179 dp->to_holdingdisk = HOLD_NEVER;
3182 if (dp->to_holdingdisk == HOLD_NEVER) {
3183 enqueue_disk(&directq, dp);
3185 enqueue_disk(&runq, dp);
3187 flush_size += sp->act_size;
3191 g_printf(_("driver: flush size %lld\n"), (long long)flush_size);
3194 log_add(L_WARNING, _("WARNING: got empty schedule from planner"));
3195 if(need_degraded==1) start_degraded_mode(&runq);
3197 run_server_global_scripts(EXECUTE_ON_PRE_BACKUP, get_config_name());
3198 if (empty(runq)) force_flush = 1;
3199 start_some_dumps(&runq);
3203 static unsigned long
3211 unsigned long maxusage=0;
3212 unsigned long curusage=0;
3213 for(p = disklist_netifs(); p != NULL; p = p->next) {
3214 maxusage += interface_get_maxusage(p->config);
3215 curusage += p->curusage;
3217 if (maxusage >= curusage)
3218 res = maxusage - curusage;
3223 if ((unsigned long)interface_get_maxusage(ip->config) >= ip->curusage)
3224 res = interface_get_maxusage(ip->config) - ip->curusage;
3239 g_printf(_("driver: interface-state time %s"), time_str);
3241 for(ip = disklist_netifs(); ip != NULL; ip = ip->next) {
3242 g_printf(_(" if %s: free %lu"), interface_name(ip->config), free_kps(ip));
3252 ip->curusage += kps;
3256 deallocate_bandwidth(
3260 assert(kps <= ip->curusage);
3261 ip->curusage -= kps;
3272 total_free = (off_t)0;
3273 for(ha = holdalloc; ha != NULL; ha = ha->next) {
3274 diff = ha->disksize - ha->allocated_space;
3282 * We return an array of pointers to assignedhd_t. The array contains at
3283 * most one entry per holding disk. The list of pointers is terminated by
3284 * a NULL pointer. Each entry contains a pointer to a holdingdisk and
3285 * how much diskspace to use on that disk. Later on, assign_holdingdisk
3286 * will allocate the given amount of space.
3287 * If there is not enough room on the holdingdisks, NULL is returned.
3290 static assignedhd_t **
3294 assignedhd_t * pref)
3296 assignedhd_t **result = NULL;
3297 holdalloc_t *ha, *minp;
3301 off_t halloc, dalloc, hfree, dfree;
3303 (void)cur_idle; /* Quiet unused parameter warning */
3305 if (size < 2*DISK_BLOCK_KB)
3306 size = 2*DISK_BLOCK_KB;
3307 size = am_round(size, (off_t)DISK_BLOCK_KB);
3309 hold_debug(1, _("find_diskspace: want %lld K\n"),
3312 used = alloc(SIZEOF(*used) * num_holdalloc);/*disks used during this run*/
3313 memset( used, 0, (size_t)num_holdalloc );
3314 result = alloc(SIZEOF(assignedhd_t *) * (num_holdalloc + 1));
3317 while( i < num_holdalloc && size > (off_t)0 ) {
3318 /* find the holdingdisk with the fewest active dumpers and among
3319 * those the one with the biggest free space
3321 minp = NULL; minj = -1;
3322 for(j = 0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3323 if( pref && pref->disk == ha && !used[j] &&
3324 ha->allocated_space <= ha->disksize - (off_t)DISK_BLOCK_KB) {
3329 else if( ha->allocated_space <= ha->disksize - (off_t)(2*DISK_BLOCK_KB) &&
3332 ha->allocated_dumpers < minp->allocated_dumpers ||
3333 (ha->allocated_dumpers == minp->allocated_dumpers &&
3334 ha->disksize-ha->allocated_space > minp->disksize-minp->allocated_space)) ) {
3341 if( !minp ) { break; } /* all holding disks are full */
3344 /* hfree = free space on the disk */
3345 hfree = minp->disksize - minp->allocated_space;
3347 /* dfree = free space for data, remove 1 header for each chunksize */
3348 dfree = hfree - (((hfree-(off_t)1)/holdingdisk_get_chunksize(minp->hdisk))+(off_t)1) * (off_t)DISK_BLOCK_KB;
3350 /* dalloc = space I can allocate for data */
3351 dalloc = ( dfree < size ) ? dfree : size;
3353 /* halloc = space to allocate, including 1 header for each chunksize */
3354 halloc = dalloc + (((dalloc-(off_t)1)/holdingdisk_get_chunksize(minp->hdisk))+(off_t)1) * (off_t)DISK_BLOCK_KB;
3356 hold_debug(1, _("find_diskspace: find diskspace: size %lld hf %lld df %lld da %lld ha %lld\n"),
3363 result[i] = alloc(SIZEOF(assignedhd_t));
3364 result[i]->disk = minp;
3365 result[i]->reserved = halloc;
3366 result[i]->used = (off_t)0;
3367 result[i]->destname = NULL;
3373 if(size != (off_t)0) { /* not enough space available */
3374 g_printf(_("find diskspace: not enough diskspace. Left with %lld K\n"), (long long)size);
3376 free_assignedhd(result);
3380 if (debug_holding > 1) {
3381 for( i = 0; result && result[i]; i++ ) {
3382 hold_debug(1, _("find_diskspace: find diskspace: selected %s free %lld reserved %lld dumpers %d\n"),
3383 holdingdisk_get_diskdir(result[i]->disk->hdisk),
3384 (long long)(result[i]->disk->disksize -
3385 result[i]->disk->allocated_space),
3386 (long long)result[i]->reserved,
3387 result[i]->disk->allocated_dumpers);
3396 assignedhd_t ** holdp,
3401 char *sfn = sanitise_filename(diskp->name);
3403 assignedhd_t **new_holdp;
3406 g_snprintf( lvl, SIZEOF(lvl), "%d", sched(diskp)->level );
3408 size = am_round(sched(diskp)->est_size - sched(diskp)->act_size,
3409 (off_t)DISK_BLOCK_KB);
3411 for( c = 0; holdp[c]; c++ )
3412 (void)c; /* count number of disks */
3414 /* allocate memory for sched(diskp)->holdp */
3415 for(j = 0; sched(diskp)->holdp && sched(diskp)->holdp[j]; j++)
3416 (void)j; /* Quiet lint */
3417 new_holdp = (assignedhd_t **)alloc(SIZEOF(assignedhd_t*)*(j+c+1));
3418 if (sched(diskp)->holdp) {
3419 memcpy(new_holdp, sched(diskp)->holdp, j * SIZEOF(*new_holdp));
3420 amfree(sched(diskp)->holdp);
3422 sched(diskp)->holdp = new_holdp;
3426 if( j > 0 ) { /* This is a request for additional diskspace. See if we can
3427 * merge assignedhd_t's */
3429 if( sched(diskp)->holdp[j-1]->disk == holdp[0]->disk ) { /* Yes! */
3430 sched(diskp)->holdp[j-1]->reserved += holdp[0]->reserved;
3431 holdp[0]->disk->allocated_space += holdp[0]->reserved;
3432 size = (holdp[0]->reserved>size) ? (off_t)0 : size-holdp[0]->reserved;
3433 qname = quote_string(diskp->name);
3434 hold_debug(1, _("assign_holdingdisk: merging holding disk %s to disk %s:%s, add %lld for reserved %lld, left %lld\n"),
3435 holdingdisk_get_diskdir(
3436 sched(diskp)->holdp[j-1]->disk->hdisk),
3437 diskp->host->hostname, qname,
3438 (long long)holdp[0]->reserved,
3439 (long long)sched(diskp)->holdp[j-1]->reserved,
3448 /* copy assignedhd_s to sched(diskp), adjust allocated_space */
3449 for( ; holdp[i]; i++ ) {
3450 holdp[i]->destname = newvstralloc( holdp[i]->destname,
3451 holdingdisk_get_diskdir(holdp[i]->disk->hdisk), "/",
3452 hd_driver_timestamp, "/",
3453 diskp->host->hostname, ".",
3456 sched(diskp)->holdp[j++] = holdp[i];
3457 holdp[i]->disk->allocated_space += holdp[i]->reserved;
3458 size = (holdp[i]->reserved > size) ? (off_t)0 :
3459 (size - holdp[i]->reserved);
3460 qname = quote_string(diskp->name);
3462 _("assign_holdingdisk: %d assigning holding disk %s to disk %s:%s, reserved %lld, left %lld\n"),
3463 i, holdingdisk_get_diskdir(holdp[i]->disk->hdisk),
3464 diskp->host->hostname, qname,
3465 (long long)holdp[i]->reserved,
3468 holdp[i] = NULL; /* so it doesn't get free()d... */
3470 sched(diskp)->holdp[j] = NULL;
3481 assignedhd_t **holdp;
3482 off_t total = (off_t)0;
3485 char *qname, *hqname, *qdest;
3487 (void)cmd; /* Quiet unused parameter warning */
3489 qname = quote_string(diskp->name);
3490 qdest = quote_string(sched(diskp)->destname);
3491 hold_debug(1, _("adjust_diskspace: %s:%s %s\n"),
3492 diskp->host->hostname, qname, qdest);
3494 holdp = sched(diskp)->holdp;
3496 assert(holdp != NULL);
3498 for( i = 0; holdp[i]; i++ ) { /* for each allocated disk */
3499 diff = holdp[i]->used - holdp[i]->reserved;
3500 total += holdp[i]->used;
3501 holdp[i]->disk->allocated_space += diff;
3502 hqname = quote_string(holdingdisk_name(holdp[i]->disk->hdisk));
3503 hold_debug(1, _("adjust_diskspace: hdisk %s done, reserved %lld used %lld diff %lld alloc %lld dumpers %d\n"),
3504 holdingdisk_name(holdp[i]->disk->hdisk),
3505 (long long)holdp[i]->reserved,
3506 (long long)holdp[i]->used,
3508 (long long)holdp[i]->disk->allocated_space,
3509 holdp[i]->disk->allocated_dumpers );
3510 holdp[i]->reserved += diff;
3514 sched(diskp)->act_size = total;
3516 hold_debug(1, _("adjust_diskspace: after: disk %s:%s used %lld\n"),
3517 diskp->host->hostname, qname,
3518 (long long)sched(diskp)->act_size);
3527 assignedhd_t **holdp;
3530 holdp = sched(diskp)->holdp;
3532 assert(holdp != NULL);
3534 for( i = 0; holdp[i]; i++ ) { /* for each disk */
3535 /* find all files of this dump on that disk, and subtract their
3536 * reserved sizes from the disk's allocated space
3538 holdp[i]->disk->allocated_space -= holdp[i]->used;
3541 holding_file_unlink(holdp[0]->destname); /* no need for the entire list,
3542 * because holding_file_unlink
3543 * will walk through all files
3544 * using cont_filename */
3545 free_assignedhd(sched(diskp)->holdp);
3546 sched(diskp)->holdp = NULL;
3547 sched(diskp)->act_size = (off_t)0;
3550 static assignedhd_t **
3557 char buffer[DISK_BLOCK_BYTES];
3559 assignedhd_t **result;
3562 char dirname[1000], *ch;
3564 char *filename = destname;
3566 memset(buffer, 0, sizeof(buffer));
3567 used = alloc(SIZEOF(off_t) * num_holdalloc);
3568 for(i=0;i<num_holdalloc;i++)
3570 result = alloc(SIZEOF(assignedhd_t *) * (num_holdalloc + 1));
3572 while(filename != NULL && filename[0] != '\0') {
3573 strncpy(dirname, filename, 999);
3575 ch = strrchr(dirname,'/');
3578 ch = strrchr(dirname,'/');
3585 g_fprintf(stderr,_("build_diskspace: bogus filename '%s'\n"), filename);
3591 for(j = 0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3592 if(strcmp(dirname, holdingdisk_get_diskdir(ha->hdisk))==0) {
3596 if (!ha || j >= num_holdalloc) {
3597 fprintf(stderr,_("build_diskspace: holding disk file '%s' is not in a holding disk directory.\n"), filename);
3602 if(stat(filename, &finfo) == -1) {
3603 g_fprintf(stderr, _("build_diskspace: can't stat %s: %s\n"),
3604 filename, strerror(errno));
3609 used[j] += ((off_t)finfo.st_size+(off_t)1023)/(off_t)1024;
3610 if((fd = open(filename,O_RDONLY)) == -1) {
3611 g_fprintf(stderr,_("build_diskspace: open of %s failed: %s\n"),
3612 filename, strerror(errno));
3617 if ((buflen = full_read(fd, buffer, SIZEOF(buffer))) > 0) {;
3618 parse_file_header(buffer, &file, buflen);
3621 filename = file.cont_filename;
3624 for(j = 0, i=0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3625 if(used[j] != (off_t)0) {
3626 result[i] = alloc(SIZEOF(assignedhd_t));
3627 result[i]->disk = ha;
3628 result[i]->reserved = used[j];
3629 result[i]->used = used[j];
3630 result[i]->destname = stralloc(destname);
3648 g_printf(_("driver: hdisk-state time %s"), time_str);
3650 for(ha = holdalloc, dsk = 0; ha != NULL; ha = ha->next, dsk++) {
3651 diff = ha->disksize - ha->allocated_space;
3652 g_printf(_(" hdisk %d: free %lld dumpers %d"), dsk,
3653 (long long)diff, ha->allocated_dumpers);
3662 time_t save_timestamp = sched(dp)->timestamp;
3663 /* setting timestamp to 0 removes the current level from the
3664 * database, so that we ensure that it will not be bumped to the
3665 * next level on the next run. If we didn't do this, dumpdates or
3666 * gnutar-lists might have been updated already, and a bumped
3667 * incremental might be created. */
3668 sched(dp)->timestamp = 0;
3669 update_info_dumper(dp, (off_t)-1, (off_t)-1, (time_t)-1);
3670 sched(dp)->timestamp = save_timestamp;
3673 /* ------------------- */
3682 for(len = 0, p = q.head; p != NULL; len++, p = p->next)
3683 (void)len; /* Quiet lint */
3688 short_dump_state(void)
3693 wall_time = walltime_str(curclock());
3695 g_printf(_("driver: state time %s "), wall_time);
3696 g_printf(_("free kps: %lu space: %lld taper: "),
3698 (long long)free_space());
3699 if(degraded_mode) g_printf(_("DOWN"));
3703 for(taper = tapetable; taper < tapetable+conf_taper_parallel_write;
3705 if (taper->state & TAPER_STATE_DUMP_TO_TAPE ||
3706 taper->state & TAPER_STATE_FILE_TO_TAPE)
3710 g_printf(_("writing"));
3712 g_printf(_("idle"));
3715 for(i = 0; i < inparallel; i++) if(!dmptable[i].busy) nidle++;
3716 g_printf(_(" idle-dumpers: %d"), nidle);
3717 g_printf(_(" qlen tapeq: %d"), queue_length(tapeq));
3718 g_printf(_(" runq: %d"), queue_length(runq));
3719 g_printf(_(" roomq: %d"), queue_length(roomq));
3720 g_printf(_(" wakeup: %d"), (int)sleep_time);
3721 g_printf(_(" driver-idle: %s\n"), _(idle_strings[idle_reason]));
3722 interface_state(wall_time);
3723 holdingdisk_state(wall_time);
3730 char **why_no_new_tape)
3732 TapeAction result = TAPE_ACTION_NO_ACTION;
3741 off_t dump_to_disk_size;
3742 int dump_to_disk_terminated;
3743 int nb_taper_active = nb_sent_new_tape;
3744 int nb_taper_flushing = 0;
3746 off_t data_next_tape = 0;
3747 off_t data_free = 0;
3748 off_t data_lost = 0;
3749 off_t data_lost_next_tape = 0;
3750 gboolean allow_size_or_number;
3753 for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
3754 if (dumper->busy && !sched(dumper->dp)->taper)
3755 dumpers_size += sched(dumper->dp)->est_size;
3757 driver_debug(2, _("dumpers_size: %lld\n"), (long long)dumpers_size);
3760 for(dp = runq.head; dp != NULL; dp = dp->next) {
3761 runq_size += sched(dp)->est_size;
3763 driver_debug(2, _("runq_size: %lld\n"), (long long)runq_size);
3766 for(dp = directq.head; dp != NULL; dp = dp->next) {
3767 directq_size += sched(dp)->est_size;
3769 driver_debug(2, _("directq_size: %lld\n"), (long long)directq_size);
3771 tapeq_size = directq_size;
3772 for(dp = tapeq.head; dp != NULL; dp = dp->next) {
3773 tapeq_size += sched(dp)->act_size;
3776 for (taper1 = tapetable; taper1 < tapetable+conf_taper_parallel_write;
3778 if (taper1->state & TAPER_STATE_FILE_TO_TAPE ||
3779 taper1->state & TAPER_STATE_DUMP_TO_TAPE) {
3780 nb_taper_flushing++;
3784 /* Add what is currently written to tape and in the go. */
3785 for (taper1 = tapetable; taper1 < tapetable+conf_taper_parallel_write;
3787 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
3788 tapeq_size -= taper1->left;
3789 dle_free += (conf_max_dle_by_volume - taper1->nb_dle);
3793 if (taper1->dumper) {
3794 data_to_go = sched(taper1->disk)->est_size - taper1->written;
3796 data_to_go = sched(taper1->disk)->act_size - taper1->written;
3798 if (data_to_go > taper1->left) {
3799 data_next_tape += data_to_go - taper1->left;
3800 data_lost += taper1->written + taper1->left;
3801 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
3804 dle_free += conf_max_dle_by_volume - 2;
3807 data_free += taper1->left - data_to_go;
3809 tapeq_size += data_to_go;
3812 data_lost_next_tape = tape_length + data_free - data_next_tape - runq_size - directq_size - tapeq_size;
3813 driver_debug(2, _("dle_free: %d\n"), dle_free);
3814 driver_debug(2, _("data_lost: %lld\n"), (long long)data_lost);
3815 driver_debug(2, _("data_free: %lld\n"), (long long)data_free);
3816 driver_debug(2, _("data_next_tape: %lld\n"), (long long)data_next_tape);
3817 driver_debug(2, _("data_lost_next_tape: %lld\n"), (long long)data_lost_next_tape);
3819 driver_debug(2, _("tapeq_size: %lld\n"), (long long)tapeq_size);
3821 sched_size = runq_size + directq_size + tapeq_size + dumpers_size;
3822 driver_debug(2, _("sched_size: %lld\n"), (long long)sched_size);
3824 dump_to_disk_size = dumpers_size + runq_size + directq_size;
3825 driver_debug(2, _("dump_to_disk_size: %lld\n"), (long long)dump_to_disk_size);
3827 dump_to_disk_terminated = schedule_done && dump_to_disk_size == 0;
3829 for (taper1 = tapetable; taper1 < tapetable + conf_taper_parallel_write;
3831 if (taper1->state & TAPER_STATE_TAPE_STARTED) {
3836 allow_size_or_number = (flush_threshold_dumped < tapeq_size &&
3837 flush_threshold_scheduled < sched_size) ||
3838 (dle_free < (queue_length(runq) +
3839 queue_length(directq) +
3840 queue_length(tapeq)));
3841 driver_debug(2, "queue_length(runq) %d\n", queue_length(runq));
3842 driver_debug(2, "queue_length(directq) %d\n", queue_length(directq));
3843 driver_debug(2, "queue_length(tapeq) %d\n", queue_length(tapeq));
3844 driver_debug(2, "allow_size_or_number %d\n", allow_size_or_number);
3846 // Changing conditionals can produce a driver hang, take care.
3848 // when to start writting to a new tape
3849 if (taper->state & TAPER_STATE_TAPE_REQUESTED) {
3850 driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED\n");
3851 if (current_tape >= conf_runtapes && taper_nb_scan_volume == 0 &&
3852 nb_taper_active == 0) {
3853 *why_no_new_tape = g_strdup_printf(_("%d tapes filled; runtapes=%d "
3854 "does not allow additional tapes"), current_tape, conf_runtapes);
3855 result |= TAPE_ACTION_NO_NEW_TAPE;
3856 } else if (current_tape < conf_runtapes &&
3857 taper_nb_scan_volume == 0 &&
3858 (allow_size_or_number ||
3859 (data_lost > data_lost_next_tape) ||
3860 nb_taper_active == 0) &&
3861 (last_started_taper == NULL ||
3862 last_started_taper == taper)) {
3863 result |= TAPE_ACTION_SCAN;
3865 result |= TAPE_ACTION_MOVE;
3867 } else if ((taper->state & TAPER_STATE_WAIT_FOR_TAPE) &&
3868 ((taper->state & TAPER_STATE_DUMP_TO_TAPE) || // for dump to tape
3869 !empty(directq) || // if a dle is waiting for a dump to tape
3870 !empty(roomq) || // holding disk constraint
3871 idle_reason == IDLE_NO_DISKSPACE || // holding disk constraint
3872 allow_size_or_number ||
3873 (data_lost > data_lost_next_tape) ||
3874 (taperflush < tapeq_size && // taperflush
3875 (force_flush == 1 || // if force_flush
3876 dump_to_disk_terminated)) // or all dump to disk terminated
3878 driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NEW_TAPE\n");
3879 result |= TAPE_ACTION_NEW_TAPE;
3880 // when to stop using new tape
3881 } else if ((taper->state & TAPER_STATE_WAIT_FOR_TAPE) &&
3882 (taperflush >= tapeq_size && // taperflush criteria
3883 (force_flush == 1 || // if force_flush
3884 dump_to_disk_terminated)) // or all dump to disk
3886 driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE B\n");
3887 if (nb_taper_active <= 0) {
3888 if (current_tape >= conf_runtapes) {
3889 *why_no_new_tape = g_strdup_printf(_("%d tapes filled; runtapes=%d "
3890 "does not allow additional tapes"), current_tape, conf_runtapes);
3891 driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NO_NEW_TAPE\n");
3892 result |= TAPE_ACTION_NO_NEW_TAPE;
3893 } else if (dumpers_size <= 0) {
3894 *why_no_new_tape = _("taperflush criteria not met");
3895 driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NO_NEW_TAPE\n");
3896 result |= TAPE_ACTION_NO_NEW_TAPE;
3901 // when to start a flush
3902 if (taper->state & TAPER_STATE_IDLE) {
3903 driver_debug(2, "tape_action: TAPER_STATE_IDLE\n");
3904 if (!degraded_mode && (!empty(tapeq) || !empty(directq)) &&
3905 (taper->state & TAPER_STATE_TAPE_STARTED || // tape already started
3906 !empty(roomq) || // holding disk constraint
3907 idle_reason == IDLE_NO_DISKSPACE || // holding disk constraint
3908 allow_size_or_number ||
3909 (force_flush == 1 && taperflush < tapeq_size))) { // taperflush if force_flush
3911 if (nb_taper_flushing == 0) {
3912 result |= TAPE_ACTION_START_A_FLUSH;
3914 result |= TAPE_ACTION_START_A_FLUSH_FIT;
3922 no_taper_flushing(void)
3926 for (taper = tapetable; taper < tapetable + conf_taper_parallel_write;
3928 if (taper->state & TAPER_STATE_FILE_TO_TAPE)
3943 g_printf("================\n");
3944 g_printf(_("driver state at time %s: %s\n"), walltime_str(curclock()), str);
3945 g_printf(_("free kps: %lu, space: %lld\n"),
3947 (long long)free_space());
3948 if(degraded_mode) g_printf(_("taper: DOWN\n"));
3949 else if(taper->status == TAPER_IDLE) g_printf(_("taper: idle\n"));
3950 else g_printf(_("taper: writing %s:%s.%d est size %lld\n"),
3951 taper->disk->host->hostname, taper->disk->name,
3952 sched(taper->disk)->level,
3953 (long long)sched(taper->disk)->est_size);
3954 for(i = 0; i < inparallel; i++) {
3955 dp = dmptable[i].dp;
3956 if(!dmptable[i].busy)
3957 g_printf(_("%s: idle\n"), dmptable[i].name);
3959 qname = quote_string(dp->name);
3960 g_printf(_("%s: dumping %s:%s.%d est kps %d size %lld time %lu\n"),
3961 dmptable[i].name, dp->host->hostname, qname, sched(dp)->level,
3962 sched(dp)->est_kps, (long long)sched(dp)->est_size, sched(dp)->est_time);
3965 dump_queue("TAPE", tapeq, 5, stdout);
3966 dump_queue("ROOM", roomq, 5, stdout);
3967 dump_queue("RUN ", runq, 5, stdout);
3968 g_printf("================\n");