static struct timeval next_removal_check;
/** Creation time of the snapshot currently being created. */
static int64_t current_snapshot_creation_time;
-/** The snapshot currently being removed. */
+/* Set by the pre-rm hook, cleared by handle_remove_exit(). */
struct snapshot *snapshot_currently_being_removed;
/** Needed by the post-create hook. */
static char *path_to_last_complete_snapshot;
fprintf(log, "\n*** internal state ***\n\n");
fprintf(log,
"pid: %d\n"
- "logile: %s\n"
+ "logfile: %s\n"
"snapshot_currently_being_removed: %s\n"
"path_to_last_complete_snapshot: %s\n"
"reference_snapshot: %s\n"
static int64_t compute_next_snapshot_time(void)
{
int64_t x = 0, now = get_current_time(), unit_interval
- = 24 * 3600 * OPT_UINT32_VAL(DSS, UNIT_INTERVAL), ret;
+ = 24 * 3600 * OPT_UINT32_VAL(DSS, UNIT_INTERVAL), ret,
+ last_completion_time;
unsigned wanted = desired_number_of_snapshots(0,
OPT_UINT32_VAL(DSS, NUM_INTERVALS)),
num_complete = 0;
continue;
num_complete++;
x += s->completion_time - s->creation_time;
+ last_completion_time = s->completion_time;
}
assert(x >= 0);
x /= num_complete; /* avg time to create one snapshot */
if (unit_interval < x * wanted) /* oops, no sleep at all */
goto out;
- ret = s->completion_time + unit_interval / wanted - x;
+ ret = last_completion_time + unit_interval / wanted - x;
out:
free_snapshot_list(&sl);
return ret;
return strcmp(s->name, name_of_reference_snapshot)? 0 : 1;
}
-/*
- * return: 0: no redundant snapshots, 1: rm process started, negative: error
- */
static struct snapshot *find_redundant_snapshot(struct snapshot_list *sl)
{
int i, interval;
int i, num_complete;
struct snapshot *s, *ref = NULL;
+ DSS_DEBUG_LOG(("picking snapshot with earliest creation time\n"));
num_complete = num_complete_snapshots(sl);
if (num_complete <= OPT_UINT32_VAL(DSS, MIN_COMPLETE))
return NULL;
ref = s;
continue;
}
- DSS_INFO_LOG(("oldest removable snapshot: %s\n", s->name));
return s;
}
assert(ref);
switch (sig) {
case SIGINT:
case SIGTERM:
- kill_children();
- ret = -E_SIGNAL;
- break;
+ return -E_SIGNAL;
case SIGHUP:
ret = handle_sighup();
break;
static void create_rsync_argv(char ***argv, int64_t *num)
{
char *logname;
- int i = 0, j, N = OPT_GIVEN(DSS, RSYNC_OPTION);
+ int i = 0, j, N;
struct snapshot_list sl;
static bool seeded;
name_of_reference_snapshot = name_of_newest_complete_snapshot(&sl);
free_snapshot_list(&sl);
- *argv = dss_malloc((15 + N) * sizeof(char *));
+ /*
+ * We specify up to 6 arguments, one argument per given rsync option
+ * and one argument per given source dir. We also need space for the
+ * terminating NULL pointer.
+ */
+ N = OPT_GIVEN(DSS, RSYNC_OPTION) + OPT_GIVEN(DSS, SOURCE_DIR);
+ *argv = dss_malloc((7 + N) * sizeof(char *));
(*argv)[i++] = dss_strdup("rsync");
(*argv)[i++] = dss_strdup("-a");
(*argv)[i++] = dss_strdup("--delete");
DSS_NOTICE_LOG(("adding --checksum to rsync options\n"));
(*argv)[i++] = dss_strdup("--checksum");
}
- for (j = 0; j < N; j++)
+ for (j = 0; j < OPT_GIVEN(DSS, RSYNC_OPTION); j++)
(*argv)[i++] = dss_strdup(lls_string_val(j,
OPT_RESULT(DSS, RSYNC_OPTION)));
if (name_of_reference_snapshot) {
} else
DSS_INFO_LOG(("no suitable reference snapshot found\n"));
logname = dss_logname();
- if (use_rsync_locally(logname))
- (*argv)[i++] = dss_strdup(OPT_STRING_VAL(DSS, SOURCE_DIR));
- else
- (*argv)[i++] = make_message("%s@%s:%s/",
- OPT_GIVEN(DSS, REMOTE_USER)?
- OPT_STRING_VAL(DSS, REMOTE_USER) : logname,
- OPT_STRING_VAL(DSS, REMOTE_HOST),
- OPT_STRING_VAL(DSS, SOURCE_DIR));
+ if (use_rsync_locally(logname)) {
+ for (j = 0; j < OPT_GIVEN(DSS, SOURCE_DIR); j++)
+ (*argv)[i++] = dss_strdup(lls_string_val(j,
+ OPT_RESULT(DSS, SOURCE_DIR)));
+ } else {
+ /*
+ * dss-1.0 and earlier did not support multiple source
+ * directories. These versions appended a slash to the end of
+ * the source directory to make sure that only the contents of
+ * the single source directory, but not the directory itself,
+ * are copied to the destination. For multiple source
+ * directories, however, this is not a good idea because the
+ * source directories may well contain identical file names,
+ * which would then be copied to the same location on the
+ * destination, overwriting each other. Moreover, we want the
+ * directory on the destination match the source. To preserve
+ * the old behaviour, we thus have to special-case N=1.
+ */
+ for (j = 0; j < OPT_GIVEN(DSS, SOURCE_DIR); j++) {
+ (*argv)[i++] = make_message("%s@%s:%s%s",
+ OPT_GIVEN(DSS, REMOTE_USER)?
+ OPT_STRING_VAL(DSS, REMOTE_USER) : logname,
+ OPT_STRING_VAL(DSS, REMOTE_HOST),
+ lls_string_val(j, OPT_RESULT(DSS, SOURCE_DIR)),
+ N == 1? "/" : ""
+ );
+ }
+ }
free(logname);
*num = get_current_time();
(*argv)[i++] = incomplete_name(*num);
{
int ret;
+ assert(argv);
ret = rename_resume_snap(current_snapshot_creation_time);
if (ret < 0)
return ret;
victim = find_redundant_snapshot(&sl);
if (victim)
goto rm;
+ dss_msg("nothing to prune\n");
ret = 0;
goto out;
rm:
ret = wait_for_remove_process();
if (ret < 0)
goto out;
+ ret = -E_HOOK_FAILED;
if (snapshot_removal_status != HS_PRE_SUCCESS)
goto out;
}
ret = wait_for_remove_process();
if (ret < 0)
goto out;
- if (snapshot_removal_status != HS_SUCCESS)
- goto out;
+ assert(snapshot_removal_status == HS_SUCCESS);
post_remove_hook();
- if (snapshot_removal_status != HS_POST_RUNNING)
- goto out;
+ assert(snapshot_removal_status == HS_POST_RUNNING);
ret = wait_for_remove_process();
if (ret < 0)
goto out;
else if (OPT_GIVEN(DSS, HELP))
txt = lls_short_help(CMD_PTR(DSS));
else if (OPT_GIVEN(DSS, VERSION))
- txt = dss_strdup(VERSION_STRING);
+ txt = make_message("%s\n", VERSION_STRING);
else
return;
printf("%s", txt);