📄 planner.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1999 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: the Amanda Development Team. Its members are listed in a * file named AUTHORS, in the root directory of this distribution. *//* * $Id: planner.c,v 1.206 2006/08/10 23:57:27 paddy_s Exp $ * * backup schedule planner for the Amanda backup system. */#include "amanda.h"#include "arglist.h"#include "conffile.h"#include "diskfile.h"#include "tapefile.h"#include "infofile.h"#include "logfile.h"#include "clock.h"#include "packet.h"#include "security.h"#include "protocol.h"#include "version.h"#include "amfeatures.h"#include "server_util.h"#include "holding.h"#include "timestamp.h"#define planner_debug(i,x) do { \ if ((i) <= debug_planner) { \ dbprintf(x); \ } \} while (0)#define MAX_LEVELS 3 /* max# of estimates per filesys */#define RUNS_REDZONE 5 /* should be in conf file? */#define PROMOTE_THRESHOLD 0.05 /* if <5% unbalanced, don't promote */#define DEFAULT_DUMPRATE 1024.0 /* K/s *//* configuration file stuff */char * conf_tapetype;off_t conf_maxdumpsize;int conf_runtapes;int conf_dumpcycle;int conf_runspercycle;int conf_tapecycle;time_t conf_etimeout;int conf_reserve;int conf_autoflush;int conf_usetimestamps;#define HOST_READY ((void *)0) /* must be 0 */#define HOST_ACTIVE ((void *)1)#define HOST_DONE ((void *)2)#define DISK_READY 0 /* must be 0 */#define DISK_ACTIVE 1#define DISK_PARTIALY_DONE 2#define DISK_DONE 3typedef struct est_s { int state; int got_estimate; int dump_priority; int dump_level; off_t dump_nsize; /* native size */ off_t dump_csize; /* compressed size */ int degr_level; /* if dump_level == 0, what would be the inc level */ off_t degr_nsize; /* native degraded size */ off_t degr_csize; /* compressed degraded size */ int last_level; off_t last_lev0size; int next_level0; int level_days; int promote; double fullrate, incrrate; double fullcomp, incrcomp; char *errstr; int level[MAX_LEVELS]; char *dumpdate[MAX_LEVELS]; off_t est_size[MAX_LEVELS];} est_t;#define est(dp) ((est_t *)(dp)->up)/* pestq = partial estimate */disklist_t startq, waitq, pestq, estq, failq, schedq;off_t total_size;double total_lev0, balanced_size, balance_threshold;off_t tape_length;size_t tape_mark;tapetype_t *tape;size_t tt_blocksize;size_t tt_blocksize_kb;int runs_per_cycle = 0;time_t today;char *planner_timestamp = NULL;static am_feature_t *our_features = NULL;static char *our_feature_string = NULL;/* We keep a LIFO queue of before images for all modifications made * to schedq in our attempt to make the schedule fit on the tape. * Enough information is stored to reinstate a dump if it turns out * that it shouldn't have been touched after all. */typedef struct bi_s { struct bi_s *next; struct bi_s *prev; int deleted; /* 0=modified, 1=deleted */ disk_t *dp; /* The disk that was changed */ int level; /* The original level */ off_t nsize; /* The original native size */ off_t csize; /* The original compressed size */ char *errstr; /* A message describing why this disk is here */} bi_t;typedef struct bilist_s { bi_t *head, *tail;} bilist_t;bilist_t biq; /* The BI queue itself *//* * ======================================================================== * MAIN PROGRAM * */static void setup_estimate(disk_t *dp);static void get_estimates(void);static void analyze_estimate(disk_t *dp);static void handle_failed(disk_t *dp);static void delay_dumps(void);static int promote_highest_priority_incremental(void);static int promote_hills(void);static void output_scheduleline(disk_t *dp);int main(int, char **);intmain( int argc, char ** argv){ disklist_t origq; disk_t *dp; int moved_one; int diskarg_offset; off_t initial_size; int i; char *conf_diskfile; char *conf_tapelist; char *conf_infofile; times_t section_start; char *qname; int nb_disk; char *errstr = NULL; config_overwrites_t *cfg_ovr = NULL; char *cfg_opt = NULL; /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); /* drop root privileges */ if (!set_root_privs(0)) { error(_("planner must be run setuid root")); } safe_fd(-1, 0); set_pname("planner"); dbopen(DBG_SUBDIR_SERVER); cfg_ovr = extract_commandline_config_overwrites(&argc, &argv); if (argc > 1) cfg_opt = argv[1]; config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD | CONFIG_INIT_FATAL, cfg_opt); apply_config_overwrites(cfg_ovr); safe_cd(); check_running_as(RUNNING_AS_DUMPUSER); dbrename(config_name, DBG_SUBDIR_SERVER); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); setvbuf(stderr, (char *)NULL, (int)_IOLBF, 0); erroutput_type = (ERR_AMANDALOG|ERR_INTERACTIVE); set_logerror(logerror); startclock(); section_start = curclock(); our_features = am_init_feature_set(); our_feature_string = am_feature_to_string(our_features); g_fprintf(stderr, _("%s: pid %ld executable %s version %s\n"), get_pname(), (long) getpid(), argv[0], version()); for (i = 0; version_info[i] != NULL; i++) g_fprintf(stderr, _("%s: %s"), get_pname(), version_info[i]); diskarg_offset = 2; if (argc > 3 && strcmp(argv[2], "--starttime") == 0) { planner_timestamp = stralloc(argv[3]); diskarg_offset += 2; } /* * 1. Networking Setup * */ protocol_init(); /* * 2. Read in Configuration Information * * All the Amanda configuration files are loaded before we begin. */ g_fprintf(stderr,_("READING CONF INFO...\n")); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); if (read_diskfile(conf_diskfile, &origq) < 0) { error(_("could not load disklist \"%s\""), conf_diskfile); /*NOTREACHED*/ } if(origq.head == NULL) { error(_("empty disklist \"%s\""), conf_diskfile); /*NOTREACHED*/ } errstr = match_disklist(&origq, argc-diskarg_offset, argv+diskarg_offset); if (errstr) { g_fprintf(stderr,"%s",errstr); amfree(errstr); } nb_disk = 0; for(dp = origq.head; dp != NULL; dp = dp->next) { if(dp->todo) { qname = quote_string(dp->name); log_add(L_DISK, "%s %s", dp->host->hostname, qname); amfree(qname); nb_disk++; } } if(nb_disk == 0) { error(_("no DLE to backup")); /*NOTREACHED*/ } amfree(conf_diskfile); conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE)); if(open_infofile(conf_infofile)) { error(_("could not open info db \"%s\""), conf_infofile); /*NOTREACHED*/ } if (check_infofile(conf_infofile, &origq, &errstr) == -1) { log_add(L_WARNING, "problem copying infofile: %s", errstr); amfree(errstr); } amfree(conf_infofile); conf_tapetype = getconf_str(CNF_TAPETYPE); conf_maxdumpsize = getconf_am64(CNF_MAXDUMPSIZE); conf_runtapes = getconf_int(CNF_RUNTAPES); conf_dumpcycle = getconf_int(CNF_DUMPCYCLE); conf_runspercycle = getconf_int(CNF_RUNSPERCYCLE); conf_tapecycle = getconf_int(CNF_TAPECYCLE); conf_etimeout = (time_t)getconf_int(CNF_ETIMEOUT); conf_reserve = getconf_int(CNF_RESERVE); conf_autoflush = getconf_boolean(CNF_AUTOFLUSH); conf_usetimestamps = getconf_boolean(CNF_USETIMESTAMPS); today = time(0); if (planner_timestamp) { if (conf_usetimestamps == 0) { planner_timestamp[8] = '\0'; } } else if(conf_usetimestamps == 0) { planner_timestamp = get_datestamp_from_time(0); } else { planner_timestamp = get_timestamp_from_time(0); } log_add(L_START, _("date %s"), planner_timestamp); g_printf("DATE %s\n", planner_timestamp); fflush(stdout); g_fprintf(stderr, _("%s: timestamp %s\n"), get_pname(), planner_timestamp); /* some initializations */ if(conf_runspercycle == 0) { runs_per_cycle = conf_dumpcycle; } else if(conf_runspercycle == -1 ) { runs_per_cycle = guess_runs_from_tapelist(); } else runs_per_cycle = conf_runspercycle; if (runs_per_cycle <= 0) { runs_per_cycle = 1; } /* * do some basic sanity checking */ if(conf_tapecycle <= runs_per_cycle) { log_add(L_WARNING, _("tapecycle (%d) <= runspercycle (%d)"), conf_tapecycle, runs_per_cycle); } tape = lookup_tapetype(conf_tapetype); if(conf_maxdumpsize > (off_t)0) { tape_length = (off_t)conf_maxdumpsize; } else { tape_length = tapetype_get_length(tape) * (off_t)conf_runtapes; } tape_mark = (size_t)tapetype_get_filemark(tape); tt_blocksize_kb = (size_t)tapetype_get_blocksize(tape); tt_blocksize = tt_blocksize_kb * 1024; g_fprintf(stderr, _("%s: time %s: startup took %s secs\n"), get_pname(), walltime_str(curclock()), walltime_str(timessub(curclock(), section_start))); /* * 3. Send autoflush dumps left on the holding disks * * This should give us something to do while we generate the new * dump schedule. */ g_fprintf(stderr,_("\nSENDING FLUSHES...\n")); if(conf_autoflush) { dumpfile_t file; GSList *holding_list, *holding_file; char *qdisk, *qhname; /* get *all* flushable files in holding */ holding_list = holding_get_files_for_flush(NULL); for(holding_file=holding_list; holding_file != NULL; holding_file = holding_file->next) { holding_file_get_dumpfile((char *)holding_file->data, &file); if (holding_file_size((char *)holding_file->data, 1) <= 0) { log_add(L_INFO, "%s: removing file with no data.", (char *)holding_file->data); holding_file_unlink((char *)holding_file->data); continue; } qdisk = quote_string(file.disk); qhname = quote_string((char *)holding_file->data); log_add(L_DISK, "%s %s", file.name, qdisk); g_fprintf(stderr, "FLUSH %s %s %s %d %s\n", file.name, qdisk, file.datestamp, file.dumplevel, qhname); g_fprintf(stdout, "FLUSH %s %s %s %d %s\n", file.name, qdisk, file.datestamp, file.dumplevel, qhname); amfree(qdisk); amfree(qhname); } g_slist_free_full(holding_list); holding_list = NULL; } g_fprintf(stderr, _("ENDFLUSH\n")); g_fprintf(stdout, _("ENDFLUSH\n")); fflush(stdout); /* * 4. Calculate Preliminary Dump Levels * * Before we can get estimates from the remote slave hosts, we make a * first attempt at guessing what dump levels we will be dumping at * based on the curinfo database. */ g_fprintf(stderr,_("\nSETTING UP FOR ESTIMATES...\n")); section_start = curclock(); startq.head = startq.tail = NULL; while(!empty(origq)) { disk_t *dp = dequeue_disk(&origq); if(dp->todo == 1) { setup_estimate(dp); } } g_fprintf(stderr, _("%s: time %s: setting up estimates took %s secs\n"), get_pname(), walltime_str(curclock()), walltime_str(timessub(curclock(), section_start))); /* * 5. Get Dump Size Estimates from Remote Client Hosts * * Each host is queried (in parallel) for dump size information on all * of its disks, and the results gathered as they come in. */ /* go out and get the dump estimates */ g_fprintf(stderr,_("\nGETTING ESTIMATES...\n")); section_start = curclock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -