When snapshotting large file systems whose contents do not change much between
snapshots, we end up removing large amounts of files just to recreate (hard
links to) most of them afterwards. This patch changes snapshot creation so that
outdated, redundant and orphaned snapshots are reused as the basis for new
snapshots. Only if no existing snapshot is suitable for recycling, a new one is
created.
static int rename_resume_snap(int64_t creation_time)
{
struct snapshot_list sl = {.num_snapshots = 0};
static int rename_resume_snap(int64_t creation_time)
{
struct snapshot_list sl = {.num_snapshots = 0};
+ struct snapshot *s = NULL;
char *new_name = incomplete_name(creation_time);
int ret;
char *new_name = incomplete_name(creation_time);
int ret;
ret = 0;
if (conf.no_resume_given)
goto out;
dss_get_snapshot_list(&sl);
ret = 0;
if (conf.no_resume_given)
goto out;
dss_get_snapshot_list(&sl);
+ /*
+ * Snapshot recycling: We first look at the newest snapshot. If this
+ * snapshot happens to be incomplete, the last rsync process was
+ * aborted and we reuse this one. Otherwise we look at snapshots which
+ * could be removed (outdated and redundant snapshots) as candidates
+ * for recycling. If no outdated/redundant snapshot exists, we check if
+ * there is an orphaned snapshot, which likely is useless anyway.
+ *
+ * Only if no existing snapshot is suitable for recycling, we bite the
+ * bullet and create a new one.
+ */
s = get_newest_snapshot(&sl);
s = get_newest_snapshot(&sl);
+ if (!s) /* no snapshots at all */
- if ((s->flags & SS_COMPLETE) != 0) /* complete */
+ /* re-use last snapshot if it is incomplete */
+ why = "aborted";
+ if ((s->flags & SS_COMPLETE) == 0)
- DSS_INFO_LOG("resuming: reusing %s as destination dir\n", s->name);
- ret = dss_rename(s->name, new_name);
+ why = "outdated";
+ s = find_outdated_snapshot(&sl);
+ if (s)
+ goto out;
+ why = "redundant";
+ s = find_redundant_snapshot(&sl);
+ if (s)
+ goto out;
+ why = "orphaned";
+ s = find_orphaned_snapshot(&sl);
+ if (s) {
+ DSS_INFO_LOG("reusing %s snapshot %s\n", why, s->name);
+ ret = dss_rename(s->name, new_name);
+ }
if (ret >= 0)
DSS_NOTICE_LOG("creating new snapshot %s\n", new_name);
free(new_name);
if (ret >= 0)
DSS_NOTICE_LOG("creating new snapshot %s\n", new_name);
free(new_name);