/*
* Amanda, The Advanced Maryland Automatic Network Disk Archiver
* Copyright (c) 1991-1998 University of Maryland at College Park
+ * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software and its
static void continue_port_dumps(void);
static void update_failed_dump(disk_t *);
static int no_taper_flushing(void);
+static int active_dumper(void);
typedef enum {
TAPE_ACTION_NO_ACTION = 0,
identlist_t il;
unsigned long reserve = 100;
char *conf_diskfile;
- char **result_argv = NULL;
char *taper_program;
char *conf_tapetype;
tapetype_t *tape;
amfree(dumper_program);
amfree(taper_program);
- if (result_argv)
- g_strfreev(result_argv);
dbclose();
enqueue_disk(&directq, diskp);
diskp->to_holdingdisk = HOLD_NEVER;
}
- if (empty(*rq)) force_flush = 1;
+ if (empty(*rq) && active_dumper() == 0) { force_flush = 1;}
}
} else if (client_constrained(diskp)) {
free_assignedhd(holdp);
sched(diskp)->level);
dumper_cmd(dumper, PORT_DUMP, diskp, NULL);
}
- diskp->host->start_t = now + 15;
- if (empty(*rq)) force_flush = 1;
+ diskp->host->start_t = now + 5;
+ if (empty(*rq) && active_dumper() == 0) { force_flush = 1;}
if (result_argv)
g_strfreev(result_argv);
taper_nb_wait_reply++;
taper_cmd(PORT_WRITE, diskp, NULL, sched(diskp)->level,
sched(diskp)->datestamp);
- diskp->host->start_t = now + 15;
+ diskp->host->start_t = now + 5;
state_changed = TRUE;
}
disklist_t newq;
off_t est_full_size;
char *qname;
+ taper_t *taper;
+
+ if (need_degraded == 0) {
+ for(taper = tapetable;
+ taper < tapetable+conf_taper_parallel_write;
+ taper++) {
+ if (!(taper->state & TAPER_STATE_DONE))
+ return;
+ }
+ need_degraded = 1;
+ }
+
+ if (!schedule_done || degraded_mode) {
+ return;
+ }
+
+ if (need_degraded == 0) {
+ for(taper = tapetable;
+ taper < tapetable+conf_taper_parallel_write;
+ taper++) {
+ if (!(taper->state & TAPER_STATE_DONE))
+ return;
+ }
+ need_degraded = 1;
+ }
newq.head = newq.tail = 0;
amfree(qname);
break;
}
- if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
+ if (strcmp(result_argv[3], "TAPE-ERROR") == 0 ||
+ strcmp(result_argv[3], "TAPE-CONFIG") == 0) {
taper->state &= ~TAPER_STATE_TAPE_STARTED;
taper->tape_error = newstralloc(taper->tape_error, result_argv[5]);
taper->result = FAILED;
amfree(qname);
break;
}
- if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
+ if (strcmp(result_argv[3], "TAPE-ERROR") == 0 ||
+ strcmp(result_argv[3], "TAPE-CONFIG") == 0) {
taper->state &= ~TAPER_STATE_TAPE_STARTED;
taper->tape_error = newstralloc(taper->tape_error, result_argv[6]);
taper->result = FAILED;
s = strstr(result_argv[4], " kb ");
if (s) {
s += 4;
- sched(dp)->dumpsize = atol(s);
+ sched(dp)->dumpsize = OFF_T_ATOI(s);
} else {
s = strstr(result_argv[4], " bytes ");
if (s) {
s += 7;
- sched(dp)->dumpsize = atol(s)/1024;
+ sched(dp)->dumpsize = OFF_T_ATOI(s)/1024;
}
}
s = strstr(result_argv[5], " kb ");
if (s) {
s += 4;
- partsize = atol(s);
+ partsize = OFF_T_ATOI(s);
} else {
s = strstr(result_argv[5], " bytes ");
if (s) {
s += 7;
- partsize = atol(s)/1024;
+ partsize = OFF_T_ATOI(s)/1024;
}
}
taper->left -= partsize;
if (strcmp(result_argv[1], "SETUP") == 0) {
taper_nb_wait_reply = 0;
taper_nb_scan_volume = 0;
+ need_degraded = 1;
} else {
taper = taper_from_name(result_argv[1]);
taper->state = TAPER_STATE_DONE;
taper_nb_scan_volume--;
}
if (taper_nb_wait_reply == 0) {
+ need_degraded = 1;
event_release(taper_ev_read);
taper_ev_read = NULL;
}
- need_degraded = 1;
- if (schedule_done && !degraded_mode) {
- start_degraded_mode(&runq);
- }
+ start_degraded_mode(&runq);
start_some_dumps(&runq);
break;
sched(dp)->level);
/* tell the dumper to dump to a port */
dumper_cmd(dumper, PORT_DUMP, dp, NULL);
- dp->host->start_t = time(NULL) + 15;
+ dp->host->start_t = time(NULL) + 5;
amfree(dp->dataport_list);
taper->state |= TAPER_STATE_DUMP_TO_TAPE;
for (taper = tapetable;
taper < tapetable + conf_taper_parallel_write;
taper++) {
- if (taper && taper->disk && taper->result != LAST_TOK) {
+ if (taper && taper->disk) {
taper->tape_error = newstralloc(taper->tape_error,"BOGUS");
taper->result = cmd;
if (taper->dumper) {
file_taper_result(taper->disk);
}
}
-
}
taper = NULL;
taper_ev_read = NULL;
taper_nb_wait_reply = 0;
}
+ need_degraded = 1;
start_degraded_mode(&runq);
tapeq.head = tapeq.tail = NULL;
aclose(taper_fd);
dumper->chunker->result != LAST_TOK)
dumper_chunker_result(dp);
} else { /* send the dumper result to the taper */
- if (taper->sendresult) {
- if (cmd == DONE) {
- taper_cmd(DONE, dp, NULL, 0, NULL);
- } else {
- taper_cmd(FAILED, dp, NULL, 0, NULL);
- }
- taper->sendresult = 0;
+ if (cmd == DONE) {
+ taper_cmd(DONE, dp, NULL, 0, NULL);
+ } else {
+ taper_cmd(FAILED, dp, NULL, 0, NULL);
}
+ taper->sendresult = 0;
if (taper->dumper && taper->result != LAST_TOK) {
dumper_taper_result(dp);
}
amfree(inpline);
if(line == 0)
log_add(L_WARNING, _("WARNING: got empty schedule from planner"));
- if(need_degraded==1) start_degraded_mode(&runq);
schedule_done = 1;
+ start_degraded_mode(&runq);
run_server_global_scripts(EXECUTE_ON_PRE_BACKUP, get_config_name());
if (empty(runq)) force_flush = 1;
start_some_dumps(&runq);
int dump_to_disk_terminated;
int nb_taper_active = nb_sent_new_tape;
int nb_taper_flushing = 0;
- int dle_free = 0;
+ int dle_free = 0; /* number of dle that fit on started tape */
+ int new_dle = 0; /* number of dle that doesn't fit on started tape */
+ off_t new_data = 0; /* size of dle that doesn't fit on started tape */
off_t data_next_tape = 0;
off_t data_free = 0;
off_t data_lost = 0;
off_t data_lost_next_tape = 0;
- gboolean allow_size_or_number;
+ gboolean taperflush_criteria;
+ gboolean flush_criteria;
+ driver_debug(2, "tape_action: ENTER %p\n", taper);
dumpers_size = 0;
for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
if (dumper->busy && !sched(dumper->dp)->taper)
dumpers_size += sched(dumper->dp)->est_size;
}
- driver_debug(1, _("dumpers_size: %lld\n"), (long long)dumpers_size);
+ driver_debug(2, _("dumpers_size: %lld\n"), (long long)dumpers_size);
runq_size = 0;
for(dp = runq.head; dp != NULL; dp = dp->next) {
runq_size += sched(dp)->est_size;
}
- driver_debug(1, _("runq_size: %lld\n"), (long long)runq_size);
+ driver_debug(2, _("runq_size: %lld\n"), (long long)runq_size);
directq_size = 0;
for(dp = directq.head; dp != NULL; dp = dp->next) {
directq_size += sched(dp)->est_size;
}
- driver_debug(1, _("directq_size: %lld\n"), (long long)directq_size);
+ driver_debug(2, _("directq_size: %lld\n"), (long long)directq_size);
tapeq_size = directq_size;
for(dp = tapeq.head; dp != NULL; dp = dp->next) {
}
/* Add what is currently written to tape and in the go. */
+ new_data = 0;
for (taper1 = tapetable; taper1 < tapetable+conf_taper_parallel_write;
taper1++) {
if (taper1->state & TAPER_STATE_TAPE_STARTED) {
- tapeq_size -= taper1->left;
+ if (taper1->nb_dle < conf_max_dle_by_volume) {
+ tapeq_size -= taper1->left;
+ }
dle_free += (conf_max_dle_by_volume - taper1->nb_dle);
}
if (taper1->disk) {
off_t data_to_go;
+ off_t t_size;
if (taper1->dumper) {
- data_to_go = sched(taper1->disk)->est_size - taper1->written;
+ t_size = sched(taper1->disk)->est_size;
} else {
- data_to_go = sched(taper1->disk)->act_size - taper1->written;
+ t_size = sched(taper1->disk)->act_size;
}
+ data_to_go = t_size - taper1->written;
if (data_to_go > taper1->left) {
data_next_tape += data_to_go - taper1->left;
data_lost += taper1->written + taper1->left;
- dle_free--;
+ if (taper1->state & TAPER_STATE_TAPE_STARTED) {
+ dle_free -= (conf_max_dle_by_volume - taper1->nb_dle) + 1;
+ } else {
+ dle_free -= 2;
+ new_data += t_size;
+ }
} else {
+ if (!(taper1->state & TAPER_STATE_TAPE_STARTED)) {
+ dle_free--;
+ new_data += t_size;
+ }
data_free += taper1->left - data_to_go;
}
tapeq_size += data_to_go;
}
}
+
+ new_dle = queue_length(tapeq) - dle_free;
+ driver_debug(2, _("dle_free: %d\n"), dle_free);
+ driver_debug(2, _("new_dle: %d\n"), new_dle);
+ if (new_dle > 0) {
+ if (taperflush == 0 &&
+ flush_threshold_dumped == 0 &&
+ flush_threshold_scheduled == 0) {
+ /* shortcut, will trigger taperflush_criteria and/or flush_criteria */
+ new_data += 1;
+ } else {
+ /* sum the size of the first new-dle in tapeq */
+ /* they should be the reverse taperalgo */
+ for (dp = tapeq.head;
+ dp != NULL && new_dle > 0;
+ dp = dp->next, new_dle--) {
+ new_data += sched(dp)->act_size;
+ }
+ }
+ if (tapeq_size < new_data) {
+ tapeq_size = new_data;
+ }
+ }
+ driver_debug(2, _("new_data: %lld\n"), (long long)new_data);
data_lost_next_tape = tape_length + data_free - data_next_tape - runq_size - directq_size - tapeq_size;
- driver_debug(1, _("data_lost: %lld\n"), (long long)data_lost);
- driver_debug(1, _("data_free: %lld\n"), (long long)data_free);
- driver_debug(1, _("data_next_tape: %lld\n"), (long long)data_next_tape);
- driver_debug(1, _("data_lost_next_tape: %lld\n"), (long long)data_lost_next_tape);
+ driver_debug(2, _("data_lost: %lld\n"), (long long)data_lost);
+ driver_debug(2, _("data_free: %lld\n"), (long long)data_free);
+ driver_debug(2, _("data_next_tape: %lld\n"), (long long)data_next_tape);
+ driver_debug(2, _("data_lost_next_tape: %lld\n"), (long long)data_lost_next_tape);
;
- driver_debug(1, _("tapeq_size: %lld\n"), (long long)tapeq_size);
+ driver_debug(2, _("tapeq_size: %lld\n"), (long long)tapeq_size);
sched_size = runq_size + directq_size + tapeq_size + dumpers_size;
- driver_debug(1, _("sched_size: %lld\n"), (long long)sched_size);
+ driver_debug(2, _("sched_size: %lld\n"), (long long)sched_size);
dump_to_disk_size = dumpers_size + runq_size + directq_size;
- driver_debug(1, _("dump_to_disk_size: %lld\n"), (long long)dump_to_disk_size);
+ driver_debug(2, _("dump_to_disk_size: %lld\n"), (long long)dump_to_disk_size);
dump_to_disk_terminated = schedule_done && dump_to_disk_size == 0;
}
}
- allow_size_or_number = (flush_threshold_dumped < tapeq_size &&
- flush_threshold_scheduled < sched_size) ||
- (dle_free < (queue_length(runq) +
- queue_length(directq) +
- queue_length(tapeq)));
+ taperflush_criteria = (taperflush < tapeq_size &&
+ (force_flush == 1 || dump_to_disk_terminated));
+ flush_criteria = (flush_threshold_dumped < tapeq_size &&
+ flush_threshold_scheduled < sched_size) ||
+ taperflush_criteria;
+
+ driver_debug(2, "taperflush %lld\n", (long long)taperflush);
+ driver_debug(2, "flush_threshold_dumped %lld\n", (long long)flush_threshold_dumped);
+ driver_debug(2, "flush_threshold_scheduled %lld\n", (long long)flush_threshold_scheduled);
+ driver_debug(2, "force_flush %d\n", force_flush);
+ driver_debug(2, "dump_to_disk_terminated %d\n", dump_to_disk_terminated);
+ driver_debug(2, "queue_length(runq) %d\n", queue_length(runq));
+ driver_debug(2, "queue_length(directq) %d\n", queue_length(directq));
+ driver_debug(2, "queue_length(tapeq) %d\n", queue_length(tapeq));
+ driver_debug(2, "taperflush_criteria %d\n", taperflush_criteria);
+ driver_debug(2, "flush_criteria %d\n", flush_criteria);
// Changing conditionals can produce a driver hang, take care.
- //
+ //
// when to start writting to a new tape
if (taper->state & TAPER_STATE_TAPE_REQUESTED) {
+ driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED\n");
if (current_tape >= conf_runtapes && taper_nb_scan_volume == 0 &&
nb_taper_active == 0) {
*why_no_new_tape = g_strdup_printf(_("%d tapes filled; runtapes=%d "
"does not allow additional tapes"), current_tape, conf_runtapes);
+ driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED return TAPE_ACTION_NO_NEW_TAPE\n");
result |= TAPE_ACTION_NO_NEW_TAPE;
} else if (current_tape < conf_runtapes &&
taper_nb_scan_volume == 0 &&
- (allow_size_or_number ||
+ (flush_criteria ||
(data_lost > data_lost_next_tape) ||
nb_taper_active == 0) &&
(last_started_taper == NULL ||
last_started_taper == taper)) {
+ driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED return TAPE_ACTION_SCAN\n");
result |= TAPE_ACTION_SCAN;
} else {
+ driver_debug(2, "tape_action: TAPER_STATE_TAPE_REQUESTED return TAPE_ACTION_MOVE\n");
result |= TAPE_ACTION_MOVE;
}
} else if ((taper->state & TAPER_STATE_WAIT_FOR_TAPE) &&
!empty(directq) || // if a dle is waiting for a dump to tape
!empty(roomq) || // holding disk constraint
idle_reason == IDLE_NO_DISKSPACE || // holding disk constraint
- allow_size_or_number ||
- (data_lost > data_lost_next_tape) ||
- (taperflush < tapeq_size && // taperflush
- (force_flush == 1 || // if force_flush
- dump_to_disk_terminated)) // or all dump to disk terminated
+ flush_criteria || // flush criteria
+ data_lost > data_lost_next_tape
)) {
+ driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NEW_TAPE\n");
result |= TAPE_ACTION_NEW_TAPE;
// when to stop using new tape
} else if ((taper->state & TAPER_STATE_WAIT_FOR_TAPE) &&
(force_flush == 1 || // if force_flush
dump_to_disk_terminated)) // or all dump to disk
) {
+ driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE B\n");
if (nb_taper_active <= 0) {
if (current_tape >= conf_runtapes) {
*why_no_new_tape = g_strdup_printf(_("%d tapes filled; runtapes=%d "
"does not allow additional tapes"), current_tape, conf_runtapes);
- } else {
+ driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NO_NEW_TAPE\n");
+ result |= TAPE_ACTION_NO_NEW_TAPE;
+ } else if (dumpers_size <= 0) {
*why_no_new_tape = _("taperflush criteria not met");
+ driver_debug(2, "tape_action: TAPER_STATE_WAIT_FOR_TAPE return TAPE_ACTION_NO_NEW_TAPE\n");
+ result |= TAPE_ACTION_NO_NEW_TAPE;
}
- result |= TAPE_ACTION_NO_NEW_TAPE;
}
}
// when to start a flush
if (taper->state & TAPER_STATE_IDLE) {
+ driver_debug(2, "tape_action: TAPER_STATE_IDLE\n");
if (!degraded_mode && (!empty(tapeq) || !empty(directq)) &&
(taper->state & TAPER_STATE_TAPE_STARTED || // tape already started
!empty(roomq) || // holding disk constraint
idle_reason == IDLE_NO_DISKSPACE || // holding disk constraint
- allow_size_or_number ||
- (force_flush == 1 && taperflush < tapeq_size))) { // taperflush if force_flush
+ flush_criteria)) { // flush
if (nb_taper_flushing == 0) {
+ driver_debug(2, "tape_action: TAPER_STATE_IDLE return TAPE_ACTION_START_A_FLUSH\n");
result |= TAPE_ACTION_START_A_FLUSH;
} else {
+ driver_debug(2, "tape_action: TAPER_STATE_IDLE return TAPE_ACTION_START_A_FLUSH_FIT\n");
result |= TAPE_ACTION_START_A_FLUSH_FIT;
}
+ } else {
+ driver_debug(2, "tape_action: TAPER_STATE_IDLE return TAPE_ACTION_NO_ACTION\n");
}
}
return result;
return 1;
}
+static int
+active_dumper(void)
+{
+ int i, nidle=0;
+
+ for(i = 0; i < inparallel; i++) if(!dmptable[i].busy) nidle++;
+ return inparallel - nidle;
+}
#if 0
static void
dump_state(