📄 planner.c
字号:
estq.head = estq.tail = NULL; pestq.head = pestq.tail = NULL; waitq.head = waitq.tail = NULL; failq.head = failq.tail = NULL; get_estimates(); g_fprintf(stderr, _("%s: time %s: getting estimates took %s secs\n"), get_pname(), walltime_str(curclock()), walltime_str(timessub(curclock(), section_start))); /* * At this point, all disks with estimates are in estq, and * all the disks on hosts that didn't respond to our inquiry * are in failq. */ dump_queue("FAILED", failq, 15, stderr); dump_queue("DONE", estq, 15, stderr); /* * 6. Analyze Dump Estimates * * Each disk's estimates are looked at to determine what level it * should dump at, and to calculate the expected size and time taking * historical dump rates and compression ratios into account. The * total expected size is accumulated as well. */ g_fprintf(stderr,_("\nANALYZING ESTIMATES...\n")); section_start = curclock(); /* an empty tape still has a label and an endmark */ total_size = ((off_t)tt_blocksize_kb + (off_t)tape_mark) * (off_t)2; total_lev0 = 0.0; balanced_size = 0.0; schedq.head = schedq.tail = NULL; while(!empty(estq)) analyze_estimate(dequeue_disk(&estq)); while(!empty(failq)) handle_failed(dequeue_disk(&failq)); /* * At this point, all the disks are on schedq sorted by priority. * The total estimated size of the backups is in total_size. */ { disk_t *dp; g_fprintf(stderr, _("INITIAL SCHEDULE (size %lld):\n"), (long long)total_size); for(dp = schedq.head; dp != NULL; dp = dp->next) { qname = quote_string(dp->name); g_fprintf(stderr, _(" %s %s pri %d lev %d nsize %lld csize %lld\n"), dp->host->hostname, qname, est(dp)->dump_priority, est(dp)->dump_level, (long long)est(dp)->dump_nsize, (long long)est(dp)->dump_csize); amfree(qname); } } /* * 7. Delay Dumps if Schedule Too Big * * If the generated schedule is too big to fit on the tape, we need to * delay some full dumps to make room. Incrementals will be done * instead (except for new or forced disks). * * In extreme cases, delaying all the full dumps is not even enough. * If so, some low-priority incrementals will be skipped completely * until the dumps fit on the tape. */ g_fprintf(stderr, _("\nDELAYING DUMPS IF NEEDED, total_size %lld, tape length %lld mark %zu\n"), (long long)total_size, (long long)tape_length, tape_mark); initial_size = total_size; delay_dumps(); /* XXX - why bother checking this? */ if(empty(schedq) && total_size < initial_size) { error(_("cannot fit anything on tape, bailing out")); /*NOTREACHED*/ } /* * 8. Promote Dumps if Schedule Too Small * * Amanda attempts to balance the full dumps over the length of the * dump cycle. If this night's full dumps are too small relative to * the other nights, promote some high-priority full dumps that will be * due for the next run, to full dumps for tonight, taking care not to * overflow the tape size. * * This doesn't work too well for small sites. For these we scan ahead * looking for nights that have an excessive number of dumps and promote * one of them. * * Amanda never delays full dumps just for the sake of balancing the * schedule, so it can take a full cycle to balance the schedule after * a big bump. */ g_fprintf(stderr, _("\nPROMOTING DUMPS IF NEEDED, total_lev0 %1.0lf, balanced_size %1.0lf...\n"), total_lev0, balanced_size); balance_threshold = balanced_size * PROMOTE_THRESHOLD; moved_one = 1; while((balanced_size - total_lev0) > balance_threshold && moved_one) moved_one = promote_highest_priority_incremental(); moved_one = promote_hills(); g_fprintf(stderr, _("%s: time %s: analysis took %s secs\n"), get_pname(), walltime_str(curclock()), walltime_str(timessub(curclock(), section_start))); /* * 9. Output Schedule * * The schedule goes to stdout, presumably to driver. A copy is written * on stderr for the debug file. */ g_fprintf(stderr,_("\nGENERATING SCHEDULE:\n--------\n")); while(!empty(schedq)) output_scheduleline(dequeue_disk(&schedq)); g_fprintf(stderr, _("--------\n")); close_infofile(); log_add(L_FINISH, _("date %s time %s"), planner_timestamp, walltime_str(curclock())); clear_tapelist(); amfree(planner_timestamp); amfree(our_feature_string); am_release_feature_set(our_features); our_features = NULL; dbclose(); return 0;}/* * ======================================================================== * SETUP FOR ESTIMATES * */static void askfor(est_t *, int, int, info_t *);static int last_level(info_t *info); /* subroutines */static off_t est_size(disk_t *dp, int level);static off_t est_tape_size(disk_t *dp, int level);static int next_level0(disk_t *dp, info_t *info);static int runs_at(info_t *info, int lev);static off_t bump_thresh(int level, off_t size_level_0, int bumppercent, off_t bumpsize, double bumpmult);static int when_overwrite(char *label);static void askfor( est_t *ep, /* esimate data block */ int seq, /* sequence number of request */ int lev, /* dump level being requested */ info_t *info) /* info block for disk */{ if(seq < 0 || seq >= MAX_LEVELS) { error(_("error [planner askfor: seq out of range 0..%d: %d]"), MAX_LEVELS, seq); /*NOTREACHED*/ } if(lev < -1 || lev >= DUMP_LEVELS) { error(_("error [planner askfor: lev out of range -1..%d: %d]"), DUMP_LEVELS, lev); /*NOTREACHED*/ } if (lev == -1) { ep->level[seq] = -1; ep->dumpdate[seq] = (char *)0; ep->est_size[seq] = (off_t)-2; return; } ep->level[seq] = lev; ep->dumpdate[seq] = stralloc(get_dumpdate(info,lev)); ep->est_size[seq] = (off_t)-2; return;}static voidsetup_estimate( disk_t *dp){ est_t *ep; info_t info; int i; char *qname; int overwrite_runs; assert(dp && dp->host); qname = quote_string(dp->name); g_fprintf(stderr, _("%s: time %s: setting up estimates for %s:%s\n"), get_pname(), walltime_str(curclock()), dp->host->hostname, qname); /* get current information about disk */ if(get_info(dp->host->hostname, dp->name, &info)) { /* no record for this disk, make a note of it */ log_add(L_INFO, _("Adding new disk %s:%s."), dp->host->hostname, dp->name); } /* setup working data struct for disk */ ep = alloc(SIZEOF(est_t)); dp->up = (void *) ep; ep->state = DISK_READY; ep->dump_nsize = (off_t)-1; ep->dump_csize = (off_t)-1; ep->dump_priority = dp->priority; ep->errstr = 0; ep->promote = 0; /* calculated fields */ if (ISSET(info.command, FORCE_FULL)) { /* force a level 0, kind of like a new disk */ if(dp->strategy == DS_NOFULL) { /* * XXX - Not sure what it means to force a no-full disk. The * purpose of no-full is to just dump changes relative to a * stable base, for example root partitions that vary only * slightly from a site-wide prototype. Only the variations * are dumped. * * If we allow a level 0 onto the Amanda cycle, then we are * hosed when that tape gets re-used next. Disallow this for * now. */ log_add(L_ERROR, _("Cannot force full dump of %s:%s with no-full option."), dp->host->hostname, qname); /* clear force command */ CLR(info.command, FORCE_FULL); if(put_info(dp->host->hostname, dp->name, &info)) { error(_("could not put info record for %s:%s: %s"), dp->host->hostname, qname, strerror(errno)); /*NOTREACHED*/ } ep->last_level = last_level(&info); ep->next_level0 = next_level0(dp, &info); } else { ep->last_level = -1; ep->next_level0 = -conf_dumpcycle; log_add(L_INFO, _("Forcing full dump of %s:%s as directed."), dp->host->hostname, qname); } } else if(dp->strategy == DS_NOFULL) { /* force estimate of level 1 */ ep->last_level = 1; ep->next_level0 = next_level0(dp, &info); } else { ep->last_level = last_level(&info); ep->next_level0 = next_level0(dp, &info); } /* adjust priority levels */ /* warn if dump will be overwritten */ if (ep->last_level > -1 && strlen(info.inf[0].label) > 0) { overwrite_runs = when_overwrite(info.inf[0].label); if(overwrite_runs == 0) { log_add(L_WARNING, _("Last full dump of %s:%s " "on tape %s overwritten on this run."), dp->host->hostname, qname, info.inf[0].label); } else if(overwrite_runs <= RUNS_REDZONE) { log_add(L_WARNING, plural(_("Last full dump of %s:%s on tape %s overwritten in %d run."), _("Last full dump of %s:%s on tape %s overwritten in %d runs."), overwrite_runs), dp->host->hostname, qname, info.inf[0].label, overwrite_runs); } } /* warn if last level 1 will be overwritten */ if (ep->last_level > 1 && strlen(info.inf[1].label) > 0) { overwrite_runs = when_overwrite(info.inf[1].label); if(overwrite_runs == 0) { log_add(L_WARNING, _("Last level 1 dump of %s:%s " "on tape %s overwritten on this run, resetting to level 1"), dp->host->hostname, qname, info.inf[1].label); ep->last_level = 0; } else if(overwrite_runs <= RUNS_REDZONE) { log_add(L_WARNING, plural(_("Last level 1 dump of %s:%s on tape %s overwritten in %d run."), _("Last level 1 dump of %s:%s on tape %s overwritten in %d runs."), overwrite_runs), dp->host->hostname, qname, info.inf[1].label, overwrite_runs); } } if(ep->next_level0 < 0) { g_fprintf(stderr,plural(_("%s:%s overdue %d day for level 0\n"), _("%s:%s overdue %d days for level 0\n"), (-ep->next_level0)), dp->host->hostname, qname, (-ep->next_level0)); ep->dump_priority -= ep->next_level0; } else if (ISSET(info.command, FORCE_FULL)) ep->dump_priority += 1; /* else XXX bump up the priority of incrementals that failed last night */ /* handle external level 0 dumps */ if(dp->skip_full && dp->strategy != DS_NOINC) { if(ep->next_level0 <= 0) { /* update the date field */ info.inf[0].date = today; CLR(info.command, FORCE_FULL); ep->next_level0 += conf_dumpcycle; ep->last_level = 0; if(put_info(dp->host->hostname, dp->name, &info)) { error(_("could not put info record for %s:%s: %s"), dp->host->hostname, qname, strerror(errno)); /*NOTREACHED*/ } log_add(L_INFO, _("Skipping full dump of %s:%s today."), dp->host->hostname, qname); g_fprintf(stderr,_("%s:%s lev 0 skipped due to skip-full flag\n"), dp->host->hostname, qname); /* don't enqueue the disk */ askfor(ep, 0, -1, &info); askfor(ep, 1, -1, &info); askfor(ep, 2, -1, &info); g_fprintf(stderr, _("%s: SKIPPED %s %s 0 [skip-full]\n"), get_pname(), dp->host->hostname, qname); log_add(L_SUCCESS, _("%s %s %s 0 [skipped: skip-full]"), dp->host->hostname, qname, planner_timestamp); amfree(qname); return; } if(ep->last_level == -1) { /* probably a new disk, but skip-full means no full! */ ep->last_level = 0; } if(ep->next_level0 == 1) { log_add(L_WARNING, _("Skipping full dump of %s:%s tomorrow."), dp->host->hostname, qname); } } if(dp->strategy == DS_INCRONLY && ep->last_level == -1 && !ISSET(info.command, FORCE_FULL)) { /* don't enqueue the disk */ askfor(ep, 0, -1, &info); askfor(ep, 1, -1, &info); askfor(ep, 2, -1, &info); log_add(L_FAIL, _("%s %s 19000101 1 [Skipping incronly because no full dump were done]"), dp->host->hostname, qname); g_fprintf(stderr,_("%s:%s lev 1 skipped due to strategy incronly and no full dump were done\n"), dp->host->hostname, qname); amfree(qname); return; } /* handle "skip-incr" type archives */ if(dp->skip_incr && ep->next_level0 > 0) { g_fprintf(stderr,_("%s:%s lev 1 skipped due to skip-incr flag\n"), dp->host->hostname, qname); /* don't enqueue the disk */ askfor(ep, 0, -1, &info); askfor(ep, 1, -1, &info); askfor(ep, 2, -1, &info); g_fprintf(stderr, _("%s: SKIPPED %s %s 1 [skip-incr]\n"), get_pname(), dp->host->hostname, qname); log_add(L_SUCCESS, _("%s %s %s 1 [skipped: skip-incr]"), dp->host->hostname, qname, planner_timestamp); amfree(qname); return; } if( ep->last_level == -1 && ep->next_level0 > 0 && dp->strategy != DS_NOFULL && dp->strategy != DS_INCRONLY && conf_reserve == 100) { log_add(L_WARNING, _("%s:%s mismatch: no tapelist record, " "but curinfo next_level0: %d."), dp->host->hostname, qname, ep->next_level0); ep->next_level0 = 0; } if(ep->last_level == 0) ep->level_days = 0; else ep->level_days = runs_at(&info, ep->last_level); ep->last_lev0size = info.inf[0].csize; ep->fullrate = perf_average(info.full.rate, 0.0); ep->incrrate = perf_average(info.incr.rate, 0.0); ep->fullcomp = perf_average(info.full.comp, dp->comprate[0]); ep->incrcomp = perf_average(info.incr.comp, dp->comprate[1]); /* determine which estimates to get */ i = 0; if (dp->strategy == DS_NOINC || (!dp->skip_full && (!ISSET(info.command, FORCE_BUMP) || dp->skip_incr || ep->last_level == -1))) { if(info.command & FORCE_BUMP && ep->last_level == -1) { log_add(L_INFO, _("Remove force-bump command of %s:%s because it's a new disk."), dp->host->hostname, qname); } switch (dp->strategy) { case DS_STANDARD: case DS_NOINC: askfor(ep, i++, 0, &info); if(dp->skip_full) { log_add(L_INFO, _("Ignoring skip_full for %s:%s " "because the strategy is NOINC."), dp->host->hostname, qname); } if(info.command & FORCE_BUMP) { log_add(L_INFO, _("Ignoring FORCE_BUMP for %s:%s because the strategy is NOINC."), dp->host->hostname, qname); } break; case DS_NOFULL: break; case DS_INCRONLY: if (ISSET(info.command, FORCE_FULL)) ep->last_level = 0; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -