Commit 6a98bce8 authored by bescoto's avatar bescoto

Added session number like '3B' to general time specification


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@415 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent b323d84d
...@@ -20,6 +20,10 @@ forthcoming attr/facl utilities. ...@@ -20,6 +20,10 @@ forthcoming attr/facl utilities.
Fixed problems with --restrict options that would cause proper Fixed problems with --restrict options that would cause proper
sessions to fail. Thanks to Randall Nortman for error report. sessions to fail. Thanks to Randall Nortman for error report.
Added new time specification by backup number. So now you can
'--remove-older-than 2B' or '--list-at-time 0B'. Original suggestion
by Alan Bailward.
New in v0.13.1 (2003/08/08) New in v0.13.1 (2003/08/08)
--------------------------- ---------------------------
......
See if regressing takes too much memory (large directories). See if regressing takes too much memory (large directories).
Alan Bailward's suggestion to add removing older than 4 sessions.
write test case for --calculate-statistics write test case for --calculate-statistics
Use ctime to check whether files have been changed. See message: Use ctime to check whether files have been changed. See message:
......
...@@ -536,6 +536,10 @@ A date format of the form YYYY/MM/DD, YYYY-MM-DD, MM/DD/YYYY, or ...@@ -536,6 +536,10 @@ A date format of the form YYYY/MM/DD, YYYY-MM-DD, MM/DD/YYYY, or
MM/DD/YYYY, which indicates midnight on the day in question, relative MM/DD/YYYY, which indicates midnight on the day in question, relative
to the current timezone settings. For instance, "2002/3/5", to the current timezone settings. For instance, "2002/3/5",
"03-05-2002", and "2002-3-05" all mean March 5th, 2002. "03-05-2002", and "2002-3-05" all mean March 5th, 2002.
.IP 6.
A backup session specification which is a non-negative integer
followed by 'B'. For instance, '0B' specifies the time of the current
mirror, and '3B' specifies the time of the 3rd newest increment.
.SH REMOTE OPERATION .SH REMOTE OPERATION
In order to access remote files, rdiff-backup opens up a pipe to a In order to access remote files, rdiff-backup opens up a pipe to a
......
...@@ -413,11 +413,11 @@ def Restore(src_rp, dest_rp, restore_as_of = None): ...@@ -413,11 +413,11 @@ def Restore(src_rp, dest_rp, restore_as_of = None):
restore_set_fs_globals(dest_rp) restore_set_fs_globals(dest_rp)
src_rp = restore_init_quoting(src_rp) src_rp = restore_init_quoting(src_rp)
restore_check_backup_dir(restore_root, src_rp, restore_as_of) restore_check_backup_dir(restore_root, src_rp, restore_as_of)
inc_rpath = Globals.rbdir.append_path('increments', restore_index)
if restore_as_of: if restore_as_of:
try: time = Time.genstrtotime(restore_timestr) try: time = Time.genstrtotime(restore_timestr, rp = inc_rpath)
except Time.TimeException, exc: Log.FatalError(str(exc)) except Time.TimeException, exc: Log.FatalError(str(exc))
else: time = src_rp.getinctime() else: time = src_rp.getinctime()
inc_rpath = Globals.rbdir.append_path('increments', restore_index)
restore_set_select(restore_root, dest_rp) restore_set_select(restore_root, dest_rp)
restore_start_log(src_rp, dest_rp, time) restore_start_log(src_rp, dest_rp, time)
restore.Restore(restore_root.new_index(restore_index), restore.Restore(restore_root.new_index(restore_index),
...@@ -632,9 +632,9 @@ def rot_check_dir(rootrp): ...@@ -632,9 +632,9 @@ def rot_check_dir(rootrp):
def ListChangedSince(rp): def ListChangedSince(rp):
"""List all the files under rp that have changed since restoretime""" """List all the files under rp that have changed since restoretime"""
assert restore_set_root(rp)
try: rest_time = Time.genstrtotime(restore_timestr) try: rest_time = Time.genstrtotime(restore_timestr)
except Time.TimeException, exc: Log.FatalError(str(exc)) except Time.TimeException, exc: Log.FatalError(str(exc))
assert restore_set_root(rp)
restore_check_backup_dir(restore_root) restore_check_backup_dir(restore_root)
mirror_rp = restore_root.new_index(restore_index) mirror_rp = restore_root.new_index(restore_index)
inc_rp = mirror_rp.append_path("increments", restore_index) inc_rp = mirror_rp.append_path("increments", restore_index)
...@@ -643,9 +643,9 @@ def ListChangedSince(rp): ...@@ -643,9 +643,9 @@ def ListChangedSince(rp):
def ListAtTime(rp): def ListAtTime(rp):
"""List files in archive under rp that are present at restoretime""" """List files in archive under rp that are present at restoretime"""
assert restore_set_root(rp)
try: rest_time = Time.genstrtotime(restore_timestr) try: rest_time = Time.genstrtotime(restore_timestr)
except Time.TimeException, exc: Log.FatalError(str(exc)) except Time.TimeException, exc: Log.FatalError(str(exc))
assert restore_set_root(rp)
restore_check_backup_dir(restore_root) restore_check_backup_dir(restore_root)
mirror_rp = restore_root.new_index(restore_index) mirror_rp = restore_root.new_index(restore_index)
inc_rp = mirror_rp.append_path("increments", restore_index) inc_rp = mirror_rp.append_path("increments", restore_index)
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
"""Provide time related exceptions and functions""" """Provide time related exceptions and functions"""
import time, types, re import time, types, re, sys
import Globals import Globals
...@@ -28,6 +28,7 @@ class TimeException(Exception): pass ...@@ -28,6 +28,7 @@ class TimeException(Exception): pass
_interval_conv_dict = {"s": 1, "m": 60, "h": 3600, "D": 86400, _interval_conv_dict = {"s": 1, "m": 60, "h": 3600, "D": 86400,
"W": 7*86400, "M": 30*86400, "Y": 365*86400} "W": 7*86400, "M": 30*86400, "Y": 365*86400}
_integer_regexp = re.compile("^[0-9]+$") _integer_regexp = re.compile("^[0-9]+$")
_session_regexp = re.compile("^[0-9]+B$")
_interval_regexp = re.compile("^([0-9]+)([smhDWMY])") _interval_regexp = re.compile("^([0-9]+)([smhDWMY])")
_genstr_date_regexp1 = re.compile("^(?P<year>[0-9]{4})[-/]" _genstr_date_regexp1 = re.compile("^(?P<year>[0-9]{4})[-/]"
"(?P<month>[0-9]{1,2})[-/](?P<day>[0-9]{1,2})$") "(?P<month>[0-9]{1,2})[-/](?P<day>[0-9]{1,2})$")
...@@ -174,8 +175,27 @@ def cmp(time1, time2): ...@@ -174,8 +175,27 @@ def cmp(time1, time2):
elif time1 == time2: return 0 elif time1 == time2: return 0
else: return 1 else: return 1
def genstrtotime(timestr, curtime = None): def time_from_session(session_num, rp = None):
"""Convert a generic time string to a time in seconds""" """Return time in seconds of given backup
The current mirror is session_num 0, the next oldest increment has
number 1, etc. Requires that the Globals.rbdir directory be set.
"""
session_times = Globals.rbdir.conn.restore.MirrorStruct \
.get_increment_times()
session_times.sort()
if len(session_times) < session_num:
return session_times[0] # Use oldest if two few backups
return session_times[-session_num-1]
def genstrtotime(timestr, curtime = None, rp = None):
"""Convert a generic time string to a time in seconds
rp is used when the time is of the form "4B" or similar. Then the
times of the increments of that particular file are used.
"""
if curtime is None: curtime = globals()['curtime'] if curtime is None: curtime = globals()['curtime']
if timestr == "now": return curtime if timestr == "now": return curtime
...@@ -196,6 +216,10 @@ the day).""" % timestr) ...@@ -196,6 +216,10 @@ the day).""" % timestr)
t = stringtotime(timestr) or stringtotime(timestr+gettzd()) t = stringtotime(timestr) or stringtotime(timestr+gettzd())
if t: return t if t: return t
# Test for time given as number of backups, like 3B
if _session_regexp.search(timestr):
return time_from_session(int(timestr[:-1]), rp)
try: # test for an interval, like "2 days ago" try: # test for an interval, like "2 days ago"
return curtime - intstringtoseconds(timestr) return curtime - intstringtoseconds(timestr)
except TimeException: pass except TimeException: pass
...@@ -209,3 +233,4 @@ the day).""" % timestr) ...@@ -209,3 +233,4 @@ the day).""" % timestr)
t = stringtotime(timestr) t = stringtotime(timestr)
if t: return t if t: return t
else: error() else: error()
...@@ -125,16 +125,20 @@ class MirrorStruct: ...@@ -125,16 +125,20 @@ class MirrorStruct:
older one here. older one here.
""" """
global _rest_time inctimes = cls.get_increment_times()
base_incs = get_inclist(Globals.rbdir.append("increments"))
if not base_incs: return _mirror_time
inctimes = [inc.getinctime() for inc in base_incs]
inctimes.append(_mirror_time)
older_times = filter(lambda time: time <= restore_to_time, inctimes) older_times = filter(lambda time: time <= restore_to_time, inctimes)
if older_times: return max(older_times) if older_times: return max(older_times)
else: # restore time older than oldest increment, just return that else: # restore time older than oldest increment, just return that
return min(inctimes) return min(inctimes)
def get_increment_times(cls, rp = None):
"""Return list of times of backups, including current mirror"""
if not _mirror_time: return_list = [cls.get_mirror_time()]
else: return_list = [_mirror_time]
if not rp or not rp.index: rp = Globals.rbdir.append("increments")
for inc in get_inclist(rp): return_list.append(inc.getinctime())
return return_list
def initialize_rf_cache(cls, mirror_base, inc_base): def initialize_rf_cache(cls, mirror_base, inc_base):
"""Set cls.rf_cache to CachedRF object""" """Set cls.rf_cache to CachedRF object"""
inc_list = get_inclist(inc_base) inc_list = get_inclist(inc_base)
......
from __future__ import generators
import unittest, os, re, sys, time import unittest, os, re, sys, time
from commontest import * from commontest import *
from rdiff_backup import Globals, log, rpath, robust, FilenameMapping from rdiff_backup import Globals, log, rpath, robust, FilenameMapping
...@@ -333,6 +334,8 @@ class FinalMisc(PathSetter): ...@@ -333,6 +334,8 @@ class FinalMisc(PathSetter):
self.set_connections(None, None, None, None) self.set_connections(None, None, None, None)
self.exec_rb_extra_args(None, '--list-changed-since 10000', self.exec_rb_extra_args(None, '--list-changed-since 10000',
'testfiles/restoretest3') 'testfiles/restoretest3')
self.exec_rb_extra_args(None, '--list-changed-since 2B',
'testfiles/restoretest3')
def testListChangeSinceRemote(self): def testListChangeSinceRemote(self):
"""Test --list-changed-since mode remotely. Uses restoretest3""" """Test --list-changed-since mode remotely. Uses restoretest3"""
...@@ -364,6 +367,42 @@ class FinalMisc(PathSetter): ...@@ -364,6 +367,42 @@ class FinalMisc(PathSetter):
self.exec_rb_extra_args(None, "--list-increment-sizes", self.exec_rb_extra_args(None, "--list-increment-sizes",
"testfiles/restoretest3") "testfiles/restoretest3")
def get_all_increments(self, rp):
"""Iterate all increments at or below given directory"""
assert rp.isdir()
dirlist = rp.listdir()
dirlist.sort()
for filename in dirlist:
subrp = rp.append(filename)
if subrp.isincfile(): yield subrp
elif subrp.isdir():
for subsubrp in self.get_all_increments(subrp):
yield subsubrp
def testRemoveOlderThan(self):
"""Test --remove-older-than. Uses restoretest3"""
Myrm("testfiles/output")
assert not os.system("cp -a testfiles/restoretest3 testfiles/output")
self.set_connections(None, None, None, None)
self.exec_rb_extra_args(None, "--remove-older-than 20000",
"testfiles/output")
rbdir = rpath.RPath(Globals.local_connection,
"testfiles/output/rdiff-backup-data")
for inc in self.get_all_increments(rbdir):
assert inc.getinctime() >= 20000
def testRemoveOlderThan2(self):
"""Test --remove-older-than, but '1B'. Uses restoretest3"""
Myrm("testfiles/output")
assert not os.system("cp -a testfiles/restoretest3 testfiles/output")
self.set_connections(None, None, None, None)
self.exec_rb_extra_args(None, "--remove-older-than 1B --force",
"testfiles/output")
rbdir = rpath.RPath(Globals.local_connection,
"testfiles/output/rdiff-backup-data")
for inc in self.get_all_increments(rbdir):
assert inc.getinctime() >= 30000
class FinalSelection(PathSetter): class FinalSelection(PathSetter):
"""Test selection options""" """Test selection options"""
......
...@@ -51,6 +51,26 @@ class RestoreFileComparer: ...@@ -51,6 +51,26 @@ class RestoreFileComparer:
for t in self.time_rp_dict.keys(): self.compare_at_time(t) for t in self.time_rp_dict.keys(): self.compare_at_time(t)
class RestoreTimeTest(unittest.TestCase):
def test_time_from_session(self):
"""Test getting time from session number (as in Time.time_from_session)
Test here instead of in timetest because it depends on an
rdiff-backup-data directory already being laid out.
"""
restore._mirror_time = None # Reset
Globals.rbdir = rpath.RPath(lc,
"testfiles/restoretest3/rdiff-backup-data")
assert Time.genstrtotime("0B") == Time.time_from_session(0)
assert Time.genstrtotime("2B") == Time.time_from_session(2)
assert Time.genstrtotime("23B") == Time.time_from_session(23)
assert Time.time_from_session(0) == 40000, Time.time_from_session(0)
assert Time.time_from_session(2) == 20000, Time.time_from_session(2)
assert Time.time_from_session(5) == 10000, Time.time_from_session(5)
class RestoreTest(unittest.TestCase): class RestoreTest(unittest.TestCase):
"""Test Restore class""" """Test Restore class"""
def get_rfcs(self): def get_rfcs(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment