Merge lp:~mterry/deja-dup/simple-threshold into lp:deja-dup/24

Proposed by Michael Terry
Status: Merged
Merged at revision: 1354
Proposed branch: lp:~mterry/deja-dup/simple-threshold
Merge into: lp:deja-dup/24
Diff against target: 281 lines (+46/-134)
9 files modified
common/CommonUtils.vala (+9/-29)
data/org.gnome.DejaDup.gschema.xml.in (+5/-0)
tests/Makefile.am (+0/-1)
tests/backup/full (+0/-89)
tests/scripts/threshold-full.test (+15/-0)
tests/scripts/threshold-inc.test (+16/-0)
widgets/ConfigDelete.vala (+0/-6)
widgets/ConfigLabelPolicy.vala (+1/-7)
widgets/ConfigPeriod.vala (+0/-2)
To merge this branch: bzr merge lp:~mterry/deja-dup/simple-threshold
Reviewer Review Type Date Requested Status
Ken VanDine Approve
Review via email: mp+111431@code.launchpad.net

Description of the change

Some backstory:

Deja Dup needs to make the occasional fresh, full backup. Further, it makes sure to always keep two of these around.

It does this so that it can delete old complete chains (if your backup was just one full backup a year ago and incrementals since, it couldn't delete any of it). And so that if something went wrong with one of your backups, you'll always have a second. Plus, upstream duplicity recommends the practice.

However, users have been complaining that Deja Dup makes a full backup too frequently (typically when they change the schedule to daily, which triggers monthly full backups). And some administrators have requested the ability to tune this value for their users.

This branch does a few things:

1) Allow a user/administrator to set (only via gsettings) the "how many days since the last full backup?" threshold for a new full backup.
2) Set that new setting to 90 (three months, which is the same default for weekly backups as before, but for users with daily backups, this represents a change from one month).
3) Removes UI options to backup at "two weeks" and "monthly" intervals (keeping "daily" and the default "weekly"). The user can still set a custom value in gsettings.
4) Removes UI options to only hold backups for "one month", "two months", and "three months" (keeping "six months", "one year", and the default "forever"). The user can still set a custom value in gsettings.
5) Vastly simplifies the existing 'threshold' logic to just look up in gsettings what the value should be. Previously it calculated it based on the user's delete date (divide by 2) and backup interval (multiply by 12) with clamps of (1 month, 6 months).

The reason for 3 is because I've been trying to encourage shorter backup intervals. This seemed like a good time to drop those options, while I was futzing with these things.

The reason for 4 is because if we're always keeping two full backups, spaced three months apart, the soonest we will delete anything is six months.

And while I was at it, I converted the relevant old-style test to a new-style one.

To post a comment you must log in.
lp:~mterry/deja-dup/simple-threshold updated
1354. By Michael Terry

whoops, forgot to update the new test thresholds to match 90 instead of 84

Revision history for this message
Ken VanDine (ken-vandine) wrote :

I'm having trouble figuring out how to run the new style tests, in the tests/scripts directory. It looks like I should run "make check" in the tests/runner directory, but they all fail. Tips?

Revision history for this message
Michael Terry (mterry) wrote :

Yeah, make check should work. Maybe they assume something that only happens to be true for my dev machine. Let's chat on IRC about it.

Revision history for this message
Ken VanDine (ken-vandine) wrote :

My test failures were due to ~/Downloads being a symlink on my box, tests pass on another box.

Looks good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'common/CommonUtils.vala'
--- common/CommonUtils.vala 2012-04-30 06:19:13 +0000
+++ common/CommonUtils.vala 2012-06-21 17:50:33 +0000
@@ -33,6 +33,7 @@
33public const string PERIODIC_KEY = "periodic";33public const string PERIODIC_KEY = "periodic";
34public const string PERIODIC_PERIOD_KEY = "periodic-period";34public const string PERIODIC_PERIOD_KEY = "periodic-period";
35public const string DELETE_AFTER_KEY = "delete-after";35public const string DELETE_AFTER_KEY = "delete-after";
36public const string FULL_BACKUP_PERIOD_KEY = "full-backup-period";
3637
37public errordomain BackupError {38public errordomain BackupError {
38 BAD_CONFIG,39 BAD_CONFIG,
@@ -501,43 +502,22 @@
501502
502public int get_full_backup_threshold()503public int get_full_backup_threshold()
503{504{
504 int threshold = 7 * 6; // default to 6 weeks
505 // So, there are a few factors affecting how often to make a fresh full505 // So, there are a few factors affecting how often to make a fresh full
506 // backup:506 // backup:
507 //
507 // 1) The longer we wait, the more we're filling up the backend with 508 // 1) The longer we wait, the more we're filling up the backend with
508 // iterations on the same crap.509 // iterations on the same crap.
509 // 2) The longer we wait, there's a higher risk that some bit will flip510 // 2) The longer we wait, there's a higher risk that some bit will flip
510 // and the whole backup is toast.511 // and the whole incremental chain afterwards is toast.
511 // 3) The longer we wait, the less annoying we are, since full backups 512 // 3) The longer we wait, the less annoying we are, since full backups
512 // take a long time.513 // take a long time.
513 // So we try to do them at reasonable times. But almost nobody should be514 //
514 // going longer than 6 months without a full backup. Further, we want515 // We default to 3 months.
515 // to try to keep at least 2 full backups around, so also don't allow a516
516 // longer full threshold than half the delete age.
517 //
518 // 'daily' gets 2 weeks: 1 * 12 => 2 * 7
519 // 'weekly' gets 3 months: 7 * 12
520 // 'biweekly' gets 6 months: 14 * 12
521 // 'monthly' gets 6 months: 28 * 12 => 24 * 7
522 var max = 24 * 7; // 6 months
523 var min = 4 * 7; // 4 weeks
524 var scale = 12;
525 var min_fulls = 2;
526
527 var settings = get_settings();517 var settings = get_settings();
528 var delete_age = settings.get_int(DELETE_AFTER_KEY);518 var threshold = settings.get_int(FULL_BACKUP_PERIOD_KEY);
529 if (delete_age > 0)519 if (threshold < 1)
530 max = int.max(int.min(delete_age/min_fulls, max), min);520 threshold = 84; // 3 months
531
532 var periodic = settings.get_boolean(PERIODIC_KEY);
533 if (periodic) {
534 var period = settings.get_int(PERIODIC_PERIOD_KEY);
535 threshold = period * scale;
536 threshold.clamp(min, max);
537 }
538 else
539 threshold = max;
540
541 return threshold;521 return threshold;
542}522}
543523
544524
=== modified file 'data/org.gnome.DejaDup.gschema.xml.in'
--- data/org.gnome.DejaDup.gschema.xml.in 2011-08-31 03:50:06 +0000
+++ data/org.gnome.DejaDup.gschema.xml.in 2012-06-21 17:50:33 +0000
@@ -55,6 +55,11 @@
55 <_summary>How long to keep backup files</_summary>55 <_summary>How long to keep backup files</_summary>
56 <_description>The number of days to keep backup files on the backup location. A value of 0 means forever. This is a minimum number of days; the files may be kept longer.</_description>56 <_description>The number of days to keep backup files on the backup location. A value of 0 means forever. This is a minimum number of days; the files may be kept longer.</_description>
57 </key>57 </key>
58 <key name="full-backup-period" type="i">
59 <default>90</default>
60 <_summary>How long to wait between full backups</_summary>
61 <_description>Déjà Dup needs to occasionally make fresh full backups. This is the number of days to wait between full backups.</_description>
62 </key>
58 <key name="backend" type="s">63 <key name="backend" type="s">
59 <choices>64 <choices>
60 <choice value='auto'/>65 <choice value='auto'/>
6166
=== modified file 'tests/Makefile.am'
--- tests/Makefile.am 2012-04-18 14:02:29 +0000
+++ tests/Makefile.am 2012-06-21 17:50:33 +0000
@@ -29,7 +29,6 @@
29 backup/delete \29 backup/delete \
30 backup/encrypt \30 backup/encrypt \
31 backup/exclude \31 backup/exclude \
32 backup/full \
33 backup/mkdir \32 backup/mkdir \
34 backup/permissions \33 backup/permissions \
35 backup/quiescent \34 backup/quiescent \
3635
=== removed file 'tests/backup/full'
--- tests/backup/full 2011-12-06 15:20:21 +0000
+++ tests/backup/full 1970-01-01 00:00:00 +0000
@@ -1,89 +0,0 @@
1#!/usr/bin/env python
2# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-
3#
4# This file is part of Déjà Dup.
5# For copyright information, see AUTHORS.
6#
7# Déjà Dup is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 3 of the License, or
10# (at your option) any later version.
11#
12# Déjà Dup is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15# General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Déjà Dup. If not, see <http://www.gnu.org/licenses/>.
19
20# Test whether we correctly switch to full backup mode vs incremental
21
22import sys
23sys.path.insert(0, sys.path[0]+'/..')
24import base
25import ldtp
26
27max_allowed = 24 * 7
28scale = 12
29
30def max_inc():
31 base.setup()
32 base.backup_simple(backend='file', encrypt=False, includes=['data/simple'])
33 # Change date to maximum allowed incremental, confirm next is incremental
34 base.last_date_change('%d days ago' % (max_allowed))
35 base.backup_simple(encrypt=None)
36 assert base.last_type() == 'inc', base.list_manifests()
37
38def max_full():
39 base.setup()
40 base.backup_simple(backend='file', encrypt=False, includes=['data/simple'])
41 # Change date to maximum allowed incremental+1, confirm next is full
42 base.last_date_change('%d days ago' % (max_allowed+1))
43 base.backup_simple(encrypt=None)
44 assert base.last_type() == 'full', base.list_manifests()
45
46def half_inc():
47 base.setup()
48 base.set_settings_value("delete-after", '80')
49 base.backup_simple(backend='file', encrypt=False, includes=['data/simple'])
50 # Change date to maximum allowed incremental, confirm next is inc
51 base.last_date_change('%d days ago' % (40))
52 base.backup_simple(encrypt=None)
53 assert base.last_type() == 'inc', base.list_manifests()
54
55def half_full():
56 base.setup()
57 base.set_settings_value("delete-after", '80')
58 base.backup_simple(backend='file', encrypt=False, includes=['data/simple'])
59 # Change date to maximum allowed incremental+1, confirm next is full
60 base.last_date_change('%d days ago' % (41))
61 base.backup_simple(encrypt=None)
62 assert base.last_type() == 'full', base.list_manifests()
63
64def period_inc():
65 base.setup()
66 base.set_settings_value("periodic", 'true')
67 base.set_settings_value("periodic-period", '7')
68 base.backup_simple(backend='file', encrypt=False, includes=['data/simple'])
69 # Change date to maximum allowed incremental, confirm next is inc
70 base.last_date_change('%d days ago' % (7*scale))
71 base.backup_simple(encrypt=None)
72 assert base.last_type() == 'inc', base.list_manifests()
73
74def period_full():
75 base.setup()
76 base.set_settings_value("periodic", 'true')
77 base.set_settings_value("periodic-period", '7')
78 base.backup_simple(backend='file', encrypt=False, includes=['data/simple'])
79 # Change date to maximum allowed incremental+1, confirm next is full
80 base.last_date_change('%d days ago' % ((7*scale)+1))
81 base.backup_simple(encrypt=None)
82 assert base.last_type() == 'full', base.list_manifests()
83
84base.run(max_inc)
85base.run(max_full)
86base.run(half_inc)
87base.run(half_full) # optimism!
88base.run(period_inc)
89base.run(period_full)
900
=== added file 'tests/scripts/threshold-full.test'
--- tests/scripts/threshold-full.test 1970-01-01 00:00:00 +0000
+++ tests/scripts/threshold-full.test 2012-06-21 17:50:33 +0000
@@ -0,0 +1,15 @@
1# Confirm that we are doing the right thing with full backup thresholds.
2# Specifically, that when we are right over the threshold, we do a full backup.
3
4[Operation]
5Type=backup
6IsFull=true
7
8[Duplicity]
9Runs=status;dry;backup;
10
11[Duplicity status]
12#echo "INFO 3"
13#echo "chain-complete"
14#echo " full $(date --utc --date='91 days ago' +%Y%m%dT%H%M%SZ) 1 enc"
15OutputScript=true
016
=== added file 'tests/scripts/threshold-inc.test'
--- tests/scripts/threshold-inc.test 1970-01-01 00:00:00 +0000
+++ tests/scripts/threshold-inc.test 2012-06-21 17:50:33 +0000
@@ -0,0 +1,16 @@
1# Confirm that we are doing the right thing with full backup thresholds.
2# Specifically, that when we are right under the threshold, we still do an
3# incremental.
4
5[Operation]
6Type=backup
7IsFull=false
8
9[Duplicity]
10Runs=status;dry;backup;
11
12[Duplicity status]
13#echo "INFO 3"
14#echo "chain-complete"
15#echo " full $(date --utc --date='90 days ago' +%Y%m%dT%H%M%SZ) 1 enc"
16OutputScript=true
017
=== modified file 'widgets/ConfigDelete.vala'
--- widgets/ConfigDelete.vala 2011-10-27 15:38:04 +0000
+++ widgets/ConfigDelete.vala 2012-06-21 17:50:33 +0000
@@ -23,9 +23,6 @@
2323
24public class ConfigDelete : ConfigChoice24public class ConfigDelete : ConfigChoice
25{25{
26 public static const int MONTHLY = 28;
27 public static const int BIMONTHLY = 28*2;
28 public static const int TRIMONTHLY = 28*3;
29 public static const int SEMIANNUALLY = 365/2;26 public static const int SEMIANNUALLY = 365/2;
30 public static const int ANNUALLY = 365;27 public static const int ANNUALLY = 365;
31 public static int FOREVER = int.MAX;28 public static int FOREVER = int.MAX;
@@ -40,9 +37,6 @@
40 Gtk.TreeIter iter;37 Gtk.TreeIter iter;
41 int i = 0;38 int i = 0;
42 39
43 store.insert_with_values(out iter, i++, 0, _("At least a month"), 1, MONTHLY);
44 store.insert_with_values(out iter, i++, 0, _("At least two months"), 1, BIMONTHLY);
45 store.insert_with_values(out iter, i++, 0, _("At least three months"), 1, TRIMONTHLY);
46 store.insert_with_values(out iter, i++, 0, _("At least six months"), 1, SEMIANNUALLY);40 store.insert_with_values(out iter, i++, 0, _("At least six months"), 1, SEMIANNUALLY);
47 store.insert_with_values(out iter, i++, 0, _("At least a year"), 1, ANNUALLY);41 store.insert_with_values(out iter, i++, 0, _("At least a year"), 1, ANNUALLY);
48 store.insert_with_values(out iter, i++, 0, _("Forever"), 1, FOREVER);42 store.insert_with_values(out iter, i++, 0, _("Forever"), 1, FOREVER);
4943
=== modified file 'widgets/ConfigLabelPolicy.vala'
--- widgets/ConfigLabelPolicy.vala 2011-10-31 13:15:46 +0000
+++ widgets/ConfigLabelPolicy.vala 2012-06-21 17:50:33 +0000
@@ -60,13 +60,7 @@
60 if (delete_after <= 0)60 if (delete_after <= 0)
61 delete_after = ConfigDelete.FOREVER;61 delete_after = ConfigDelete.FOREVER;
62 62
63 if (delete_after == ConfigDelete.MONTHLY)63 if (delete_after == ConfigDelete.SEMIANNUALLY)
64 policy = _("Old backups will be kept for at least a month or until the backup location is low on space.");
65 else if (delete_after == ConfigDelete.BIMONTHLY)
66 policy = _("Old backups will be kept for at least two months or until the backup location is low on space.");
67 else if (delete_after == ConfigDelete.TRIMONTHLY)
68 policy = _("Old backups will be kept for at least three months or until the backup location is low on space.");
69 else if (delete_after == ConfigDelete.SEMIANNUALLY)
70 policy = _("Old backups will be kept for at least six months or until the backup location is low on space.");64 policy = _("Old backups will be kept for at least six months or until the backup location is low on space.");
71 else if (delete_after == ConfigDelete.ANNUALLY)65 else if (delete_after == ConfigDelete.ANNUALLY)
72 policy = _("Old backups will be kept for at least a year or until the backup location is low on space.");66 policy = _("Old backups will be kept for at least a year or until the backup location is low on space.");
7367
=== modified file 'widgets/ConfigPeriod.vala'
--- widgets/ConfigPeriod.vala 2011-10-07 14:43:17 +0000
+++ widgets/ConfigPeriod.vala 2012-06-21 17:50:33 +0000
@@ -35,8 +35,6 @@
35 35
36 store.insert_with_values(out iter, i++, 0, _("Daily"), 1, 1);36 store.insert_with_values(out iter, i++, 0, _("Daily"), 1, 1);
37 store.insert_with_values(out iter, i++, 0, _("Weekly"), 1, 7);37 store.insert_with_values(out iter, i++, 0, _("Weekly"), 1, 7);
38 store.insert_with_values(out iter, i++, 0, _("Every 2 weeks"), 1, 14);
39 store.insert_with_values(out iter, i++, 0, _("Monthly"), 1, 28);
40 38
41 store.set_sort_column_id(1, Gtk.SortType.ASCENDING);39 store.set_sort_column_id(1, Gtk.SortType.ASCENDING);
42 40

Subscribers

People subscribed via source and target branches