📄 driver.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998 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: driver.c 6512 2007-05-24 17:00:24Z ian $ * * controlling process for the Amanda backup system *//* * XXX possibly modify tape queue to be cognizant of how much room is left on * tape. Probably not effective though, should do this in planner. */#include "amanda.h"#include "clock.h"#include "conffile.h"#include "diskfile.h"#include "event.h"#include "holding.h"#include "infofile.h"#include "logfile.h"#include "fsusage.h"#include "version.h"#include "driverio.h"#include "server_util.h"#include "timestamp.h"#define driver_debug(i, ...) do { \ if ((i) <= debug_driver) { \ dbprintf(__VA_ARGS__); \ } \} while (0)#define hold_debug(i, ...) do { \ if ((i) <= debug_holding) { \ dbprintf(__VA_ARGS__); \ } \} while (0)static disklist_t waitq; // dle waiting estimate resultstatic disklist_t runq; // dle waiting to be dumped to holding diskstatic disklist_t directq; // dle waiting to be dumped directly to tapestatic disklist_t tapeq; // dle on holding disk waiting to be written // to tapestatic disklist_t roomq; // dle waiting for more space on holding diskstatic int pending_aborts;static disk_t *taper_disk;static int degraded_mode;static off_t reserved_space;static off_t total_disksize;static char *dumper_program;static char *chunker_program;static int inparallel;static int nodump = 0;static off_t tape_length = (off_t)0;static off_t tape_left = (off_t)0;static int current_tape = 0;static int conf_taperalgo;static int conf_runtapes;static time_t sleep_time;static int idle_reason;static char *driver_timestamp;static char *hd_driver_timestamp;static am_host_t *flushhost = NULL;static int need_degraded=0;static holdalloc_t *holdalloc;static int num_holdalloc;static event_handle_t *dumpers_ev_time = NULL;static event_handle_t *schedule_ev_read = NULL;static int conf_flush_threshold_dumped;static int conf_flush_threshold_scheduled;static int conf_taperflush;static off_t flush_threshold_dumped;static off_t flush_threshold_scheduled;static off_t taperflush;static int schedule_done; // 1 if we don't wait for a // schedule from the plannerstatic int force_flush; // All dump are terminated, we // must now respect taper_flushstatic int wait_children(int count);static void wait_for_children(void);static void allocate_bandwidth(netif_t *ip, unsigned long kps);static int assign_holdingdisk(assignedhd_t **holdp, disk_t *diskp);static void adjust_diskspace(disk_t *diskp, cmd_t cmd);static void delete_diskspace(disk_t *diskp);static assignedhd_t **build_diskspace(char *destname);static int client_constrained(disk_t *dp);static void deallocate_bandwidth(netif_t *ip, unsigned long kps);static void dump_schedule(disklist_t *qp, char *str);static void dump_to_tape(disk_t *dp);static assignedhd_t **find_diskspace(off_t size, int *cur_idle, assignedhd_t *preferred);static unsigned long free_kps(netif_t *ip);static off_t free_space(void);static void dumper_chunker_result(disk_t *dp);static void dumper_taper_result(disk_t *dp);static void file_taper_result(disk_t *dp);static void handle_dumper_result(void *);static void handle_chunker_result(void *);static void handle_dumpers_time(void *);static void handle_taper_result(void *);static void holdingdisk_state(char *time_str);static dumper_t *idle_dumper(void);static void interface_state(char *time_str);static int queue_length(disklist_t q);static disklist_t read_flush(void);static void read_schedule(void *cookie);static void short_dump_state(void);static void startaflush(void);static void start_degraded_mode(disklist_t *queuep);static void start_some_dumps(disklist_t *rq);static void continue_port_dumps(void);static void update_failed_dump_to_tape(disk_t *);typedef enum { TAPE_ACTION_NO_ACTION = 0, TAPE_ACTION_NEW_TAPE = (1 << 0), TAPE_ACTION_NO_NEW_TAPE = (1 << 1), TAPE_ACTION_START_A_FLUSH = (1 << 2)} TapeAction;static TapeAction tape_action(void);static const char *idle_strings[] = {#define NOT_IDLE 0 T_("not-idle"),#define IDLE_NO_DUMPERS 1 T_("no-dumpers"),#define IDLE_START_WAIT 2 T_("start-wait"),#define IDLE_NO_HOLD 3 T_("no-hold"),#define IDLE_CLIENT_CONSTRAINED 4 T_("client-constrained"),#define IDLE_NO_BANDWIDTH 5 T_("no-bandwidth"),#define IDLE_NO_DISKSPACE 6 T_("no-diskspace")};intmain( int argc, char ** argv){ disklist_t origq; disk_t *diskp; int dsk; dumper_t *dumper; char *newdir = NULL; struct fs_usage fsusage; holdingdisk_t *hdp; unsigned long reserve = 100; char *conf_diskfile; cmd_t cmd; int result_argc; char *result_argv[MAX_ARGS+1]; char *taper_program; char *conf_tapetype; tapetype_t *tape; char *line; char hostname[1025]; intmax_t kb_avail; config_overwrites_t *cfg_ovr = NULL; char *cfg_opt = NULL; holdalloc_t *ha, *ha_last; /* * 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"); safe_fd(-1, 0); setvbuf(stdout, (char *)NULL, (int)_IOLBF, 0); setvbuf(stderr, (char *)NULL, (int)_IOLBF, 0); set_pname("driver"); dbopen(DBG_SUBDIR_SERVER); atexit(wait_for_children); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); erroutput_type = (ERR_AMANDALOG|ERR_INTERACTIVE); set_logerror(logerror); startclock(); 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); g_printf(_("%s: pid %ld executable %s version %s\n"), get_pname(), (long) getpid(), argv[0], version()); if(argc > 2) { if(strncmp(argv[2], "nodump", 6) == 0) { nodump = 1; } } safe_cd(); /* do this *after* config_init */ check_running_as(RUNNING_AS_DUMPUSER); dbrename(config_name, DBG_SUBDIR_SERVER); amfree(driver_timestamp); /* read timestamp from stdin */ while ((line = agets(stdin)) != NULL) { if (line[0] != '\0') break; amfree(line); } if ( line == NULL ) { error(_("Did not get DATE line from planner")); /*NOTREACHED*/ } driver_timestamp = alloc(15); strncpy(driver_timestamp, &line[5], 14); driver_timestamp[14] = '\0'; amfree(line); log_add(L_START,_("date %s"), driver_timestamp); gethostname(hostname, SIZEOF(hostname)); log_add(L_STATS,_("hostname %s"), hostname); /* check that we don't do many dump in a day and usetimestamps is off */ if(strlen(driver_timestamp) == 8) { if (!nodump) { char *conf_logdir = getconf_str(CNF_LOGDIR); char *logfile = vstralloc(conf_logdir, "/log.", driver_timestamp, ".0", NULL); char *oldlogfile = vstralloc(conf_logdir, "/oldlog/log.", driver_timestamp, ".0", NULL); if(access(logfile, F_OK) == 0 || access(oldlogfile, F_OK) == 0) { 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.")); } amfree(oldlogfile); amfree(logfile); } hd_driver_timestamp = get_timestamp_from_time(0); } else { hd_driver_timestamp = stralloc(driver_timestamp); } taper_program = vstralloc(amlibexecdir, "/", "taper", versionsuffix(), NULL); dumper_program = vstralloc(amlibexecdir, "/", "dumper", versionsuffix(), NULL); chunker_program = vstralloc(amlibexecdir, "/", "chunker", versionsuffix(), NULL); conf_taperalgo = getconf_taperalgo(CNF_TAPERALGO); conf_tapetype = getconf_str(CNF_TAPETYPE); conf_runtapes = getconf_int(CNF_RUNTAPES); tape = lookup_tapetype(conf_tapetype); tape_length = tapetype_get_length(tape); conf_flush_threshold_dumped = getconf_int(CNF_FLUSH_THRESHOLD_DUMPED); conf_flush_threshold_scheduled = getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED); conf_taperflush = getconf_int(CNF_TAPERFLUSH); flush_threshold_dumped = (conf_flush_threshold_dumped * tape_length) / 100; flush_threshold_scheduled = (conf_flush_threshold_scheduled * tape_length) / 100; taperflush = (conf_taperflush *tape_length) / 100; driver_debug(1, _("flush_threshold_dumped: %lld\n"), (long long)flush_threshold_dumped); driver_debug(1, _("flush_threshold_scheduled: %lld\n"), (long long)flush_threshold_scheduled); driver_debug(1, _("taperflush: %lld\n"), (long long)taperflush); /* start initializing: read in databases */ 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*/ } amfree(conf_diskfile); /* set up any configuration-dependent variables */ inparallel = getconf_int(CNF_INPARALLEL); reserve = (unsigned long)getconf_int(CNF_RESERVE); total_disksize = (off_t)0; ha_last = NULL; num_holdalloc = 0; for(hdp = getconf_holdingdisks(), dsk = 0; hdp != NULL; hdp = holdingdisk_next(hdp), dsk++) { ha = alloc(SIZEOF(holdalloc_t)); num_holdalloc++; /* link the list in the same order as getconf_holdingdisks's results */ ha->next = NULL; if (ha_last == NULL) holdalloc = ha; else ha_last->next = ha; ha_last = ha; ha->hdisk = hdp; ha->allocated_dumpers = 0; ha->allocated_space = (off_t)0; ha->disksize = holdingdisk_get_disksize(hdp); /* get disk size */ if(get_fs_usage(holdingdisk_get_diskdir(hdp), NULL, &fsusage) == -1 || access(holdingdisk_get_diskdir(hdp), W_OK) == -1) { log_add(L_WARNING, _("WARNING: ignoring holding disk %s: %s\n"), holdingdisk_get_diskdir(hdp), strerror(errno)); ha->disksize = 0L; continue; } /* do the division first to avoid potential integer overflow */ if (fsusage.fsu_bavail_top_bit_set) kb_avail = 0; else kb_avail = fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize; if(ha->disksize > (off_t)0) { if(ha->disksize > kb_avail) { log_add(L_WARNING, _("WARNING: %s: %lld KB requested, " "but only %lld KB available."), holdingdisk_get_diskdir(hdp), (long long)ha->disksize, (long long)kb_avail); ha->disksize = kb_avail; } } /* ha->disksize is negative; use all but that amount */ else if(kb_avail < -ha->disksize) { log_add(L_WARNING, _("WARNING: %s: not %lld KB free."), holdingdisk_get_diskdir(hdp), (long long)-ha->disksize); ha->disksize = (off_t)0; continue; } else ha->disksize += kb_avail; g_printf(_("driver: adding holding disk %d dir %s size %lld chunksize %lld\n"), dsk, holdingdisk_get_diskdir(hdp), (long long)ha->disksize, (long long)(holdingdisk_get_chunksize(hdp))); newdir = newvstralloc(newdir, holdingdisk_get_diskdir(hdp), "/", hd_driver_timestamp, NULL); if(!mkholdingdir(newdir)) { ha->disksize = (off_t)0; } total_disksize += ha->disksize; } reserved_space = total_disksize * (off_t)(reserve / 100); g_printf(_("reserving %lld out of %lld for degraded-mode dumps\n"), (long long)reserved_space, (long long)free_space()); amfree(newdir); if(inparallel > MAX_DUMPERS) inparallel = MAX_DUMPERS; /* taper takes a while to get going, so start it up right away */ init_driverio(); if(conf_runtapes > 0) { startup_tape_process(taper_program); taper_cmd(START_TAPER, driver_timestamp, NULL, 0, NULL); } /* fire up the dumpers now while we are waiting */ if(!nodump) startup_dump_processes(dumper_program, inparallel, driver_timestamp); /* * Read schedule from stdin. Usually, this is a pipe from planner, * so the effect is that we wait here for the planner to * finish, but meanwhile the taper is rewinding the tape, reading * the label, checking it, writing a new label and all that jazz * in parallel with the planner. */ runq.head = NULL; runq.tail = NULL; directq.head = NULL; directq.tail = NULL; waitq = origq; taper_state = TAPER_STATE_DEFAULT; tapeq = read_flush(); roomq.head = roomq.tail = NULL; log_add(L_STATS, _("startup time %s"), walltime_str(curclock())); g_printf(_("driver: start time %s inparallel %d bandwidth %lu diskspace %lld "), walltime_str(curclock()), inparallel, free_kps(NULL), (long long)free_space()); g_printf(_(" dir %s datestamp %s driver: drain-ends tapeq %s big-dumpers %s\n"), "OBSOLETE", driver_timestamp, taperalgo2str(conf_taperalgo), getconf_str(CNF_DUMPORDER)); fflush(stdout); /* ok, planner is done, now lets see if the tape is ready */ if (conf_runtapes > 0) { cmd = getresult(taper, 1, &result_argc, result_argv, MAX_ARGS+1); if (cmd != TAPER_OK) { /* no tape, go into degraded mode: dump to holding disk */ need_degraded = 1; } } else { need_degraded = 1; } tape_left = tape_length; taper_busy = 0; taper_input_error = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -