Commit 2463d5fa authored by bescoto's avatar bescoto

Final changes for 0.12.1, including librsync block size scaling


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@354 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent d4d5d4a0
New in v0.12.1 (2003/07/??) New in v0.12.1 (2003/07/22)
--------------------------- ---------------------------
Added --no-change-dir-inc-perms switch, to avoid some weird errors on Added --no-change-dir-inc-perms switch, to avoid some weird errors on
...@@ -8,6 +8,11 @@ report. ...@@ -8,6 +8,11 @@ report.
Fixed bug when regressing destination directory made with Fixed bug when regressing destination directory made with
--windows-mode. Reported by Tucker Sylvestro. --windows-mode. Reported by Tucker Sylvestro.
The librsync blocksize is now chosen based on filesize. This should
make operations on large files faster (in some cases, orders of
magnitude faster). Thanks to Ty! Boyack for bringing this issue to my
attention.
New in v0.12.0 (2003/06/26) New in v0.12.0 (2003/06/26)
--------------------------- ---------------------------
......
...@@ -7,7 +7,7 @@ DistDir = "dist" ...@@ -7,7 +7,7 @@ DistDir = "dist"
# Various details about the files must also be specified by the rpm # Various details about the files must also be specified by the rpm
# spec template. # spec template.
spec_template = "dist/rdiff-backup.spec" spec_template = "dist/rdiff-backup.spec.template"
#redhat_spec_template = "dist/rdiff-backup.rh7x.spec" #redhat_spec_template = "dist/rdiff-backup.rh7x.spec"
def CopyMan(destination, version): def CopyMan(destination, version):
...@@ -115,7 +115,8 @@ def MakeTar(): ...@@ -115,7 +115,8 @@ def MakeTar():
def MakeSpecFile(): def MakeSpecFile():
"""Create spec file using spec template""" """Create spec file using spec template"""
specfile = "rdiff-backup-%s-2.spec" % Version #specfile = "rdiff-backup-%s-2.spec" % Version
specfile = "rdiff-backup.spec" # Fedora standard name
VersionedCopy(spec_template, specfile) VersionedCopy(spec_template, specfile)
return specfile return specfile
......
...@@ -6,23 +6,24 @@ rpmroot = "/home/ben/rpm" ...@@ -6,23 +6,24 @@ rpmroot = "/home/ben/rpm"
if len(sys.argv) == 2: if len(sys.argv) == 2:
version = sys.argv[1] version = sys.argv[1]
specfile = "rdiff-backup-%s-2.spec" % version specfile = "rdiff-backup.spec"
print "Using specfile %s" % specfile print "Using specfile %s" % specfile
else: else:
print "Syntax: %s version_number" % sys.argv[0] print "Syntax: %s version_number" % sys.argv[0]
sys.exit(1) sys.exit(1)
base = ".".join(specfile.split(".")[:-1]) base = "rdiff-backup-%s" % (version,)
srcrpm = base+".src.rpm" tarfile = base + ".tar.gz"
i386rpm = base+".i386.rpm" rpmbase = base + "-0.fdr.1" # Fedora suffix, with release number 1
source_rpm = base+".src.rpm" i386_rpm = rpmbase + ".i386.rpm"
tarfile = "-".join(base.split("-")[:-1]) + ".tar.gz" source_rpm = rpmbase + ".src.rpm"
# These assume the rpm root directory $HOME/rpm. The # These assume the rpm root directory $HOME/rpm. The
# nonstandard location allows for building by non-root user. # nonstandard location allows for building by non-root user.
assert not os.system("cp %s %s/SOURCES" % (tarfile, rpmroot)) assert not os.system("cp %s %s/SOURCES" % (tarfile, rpmroot))
#assert not os.system("rpm -ba --sign -vv --target i386 " + specfile) #assert not os.system("rpm -ba --sign -vv --target i386 " + specfile)
assert not os.system("rpmbuild -ba -v --sign " + specfile) assert not os.system("rpmbuild -ba -v --sign " + specfile)
assert not os.system("mv %s/RPMS/i386/%s ." % (rpmroot, i386rpm)) assert not os.system("mv %s/RPMS/i386/%s ." % (rpmroot, i386_rpm))
assert not os.system("mv %s/SRPMS/%s ." % (rpmroot, source_rpm)) assert not os.system("mv %s/SRPMS/%s ." % (rpmroot, source_rpm))
...@@ -3,13 +3,14 @@ ...@@ -3,13 +3,14 @@
Version: $version Version: $version
Summary: Convenient and transparent local/remote incremental mirror/backup Summary: Convenient and transparent local/remote incremental mirror/backup
Name: rdiff-backup Name: rdiff-backup
Release: 2 Release: 0.fdr.1
URL: http://www.stanford.edu/~bescoto/rdiff-backup/ Epoch: 0
Source: %{name}-%{version}.tar.gz URL: http://rdiff-backup.stanford.edu/
Copyright: GPL Source: http://rdiff-backup.stanford.edu/%{name}-%{version}.tar.gz
License: GPL
Group: Applications/Archiving Group: Applications/Archiving
BuildRoot: %{_tmppath}/%{name}-root BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
requires: librsync >= 0.9.5.1, %{PYTHON_NAME} >= 2.2 Requires: librsync >= 0.9.5.1, %{PYTHON_NAME} >= 2.2
BuildPrereq: %{PYTHON_NAME}-devel >= 2.2, librsync-devel >= 0.9.5.1 BuildPrereq: %{PYTHON_NAME}-devel >= 2.2, librsync-devel >= 0.9.5.1
%description %description
...@@ -38,12 +39,15 @@ differences from the previous backup will be transmitted. ...@@ -38,12 +39,15 @@ differences from the previous backup will be transmitted.
%files %files
%defattr(-,root,root) %defattr(-,root,root)
/usr/bin/rdiff-backup %{_bindir}/rdiff-backup
/usr/share/man/man1 %{_mandir}/man1/rdiff-backup*
/usr/lib %{_libdir}/
%doc CHANGELOG COPYING FAQ.html README %doc CHANGELOG COPYING FAQ.html README
%changelog %changelog
* Sun Jul 20 2003 Ben Escoto <bescoto@stanford.edu>
- Minor changes to comply with Fedora standards.
* Sun Jan 19 2002 Troels Arvin <troels@arvin.dk> * Sun Jan 19 2002 Troels Arvin <troels@arvin.dk>
- Builds, no matter if Python 2.2 is called python2-2.2 or python-2.2. - Builds, no matter if Python 2.2 is called python2-2.2 or python-2.2.
......
...@@ -23,10 +23,24 @@ import os, librsync ...@@ -23,10 +23,24 @@ import os, librsync
import Globals, log, static, TempFile, rpath import Globals, log, static, TempFile, rpath
def get_signature(rp): def get_signature(rp, blocksize = None):
"""Take signature of rpin file and return in file object""" """Take signature of rpin file and return in file object"""
log.Log("Getting signature of %s" % rp.get_indexpath(), 7) if not blocksize: blocksize = find_blocksize(rp.getsize())
return librsync.SigFile(rp.open("rb")) log.Log("Getting signature of %s with blocksize %s" %
(rp.get_indexpath(), blocksize), 7)
return librsync.SigFile(rp.open("rb"), blocksize)
def find_blocksize(file_len):
"""Return a reasonable block size to use on files of length file_len
If the block size is too big, deltas will be bigger than is
necessary. If the block size is too small, making deltas and
patching can take a really long time.
"""
if file_len < 1024000: return 512 # set minimum of 512 bytes
else: # Split file into about 2000 pieces, rounding to 512
return long((file_len/(2000*512))*512)
def get_delta_sigfileobj(sig_fileobj, rp_new): def get_delta_sigfileobj(sig_fileobj, rp_new):
"""Like get_delta but signature is in a file object""" """Like get_delta but signature is in a file object"""
...@@ -43,8 +57,7 @@ def write_delta(basis, new, delta, compress = None): ...@@ -43,8 +57,7 @@ def write_delta(basis, new, delta, compress = None):
"""Write rdiff delta which brings basis to new""" """Write rdiff delta which brings basis to new"""
log.Log("Writing delta %s from %s -> %s" % log.Log("Writing delta %s from %s -> %s" %
(basis.path, new.path, delta.path), 7) (basis.path, new.path, delta.path), 7)
sigfile = librsync.SigFile(basis.open("rb")) deltafile = librsync.DeltaFile(get_signature(basis), new.open("rb"))
deltafile = librsync.DeltaFile(sigfile, new.open("rb"))
delta.write_from_fileobj(deltafile, compress) delta.write_from_fileobj(deltafile, compress)
def write_patched_fp(basis_fp, delta_fp, out_fp): def write_patched_fp(basis_fp, delta_fp, out_fp):
...@@ -79,8 +92,8 @@ def patch_local(rp_basis, rp_delta, outrp = None, delta_compressed = None): ...@@ -79,8 +92,8 @@ def patch_local(rp_basis, rp_delta, outrp = None, delta_compressed = None):
def copy_local(rpin, rpout, rpnew = None): def copy_local(rpin, rpout, rpnew = None):
"""Write rpnew == rpin using rpout as basis. rpout and rpnew local""" """Write rpnew == rpin using rpout as basis. rpout and rpnew local"""
assert rpout.conn is Globals.local_connection assert rpout.conn is Globals.local_connection
sigfile = librsync.SigFile(rpout.open("rb")) deltafile = rpin.conn.librsync.DeltaFile(get_signature(rpout),
deltafile = rpin.conn.librsync.DeltaFile(sigfile, rpin.open("rb")) rpin.open("rb"))
patched_file = librsync.PatchedFile(rpout.open("rb"), deltafile) patched_file = librsync.PatchedFile(rpout.open("rb"), deltafile)
if rpnew: rpnew.write_from_fileobj(patched_file) if rpnew: rpnew.write_from_fileobj(patched_file)
......
...@@ -41,15 +41,16 @@ static PyObject* ...@@ -41,15 +41,16 @@ static PyObject*
_librsync_new_sigmaker(PyObject* self, PyObject* args) _librsync_new_sigmaker(PyObject* self, PyObject* args)
{ {
_librsync_SigMakerObject* sm; _librsync_SigMakerObject* sm;
long blocklen;
if (!PyArg_ParseTuple(args,":new_sigmaker")) if (!PyArg_ParseTuple(args, "l:new_sigmaker", &blocklen))
return NULL; return NULL;
sm = PyObject_New(_librsync_SigMakerObject, &_librsync_SigMakerType); sm = PyObject_New(_librsync_SigMakerObject, &_librsync_SigMakerType);
if (sm == NULL) return NULL; if (sm == NULL) return NULL;
sm->x_attr = NULL; sm->x_attr = NULL;
sm->sig_job = rs_sig_begin((size_t)RS_DEFAULT_BLOCK_LEN, sm->sig_job = rs_sig_begin((size_t)blocklen,
(size_t)RS_DEFAULT_STRONG_LEN); (size_t)RS_DEFAULT_STRONG_LEN);
return (PyObject*)sm; return (PyObject*)sm;
} }
......
...@@ -108,7 +108,7 @@ class LikeFile: ...@@ -108,7 +108,7 @@ class LikeFile:
class SigFile(LikeFile): class SigFile(LikeFile):
"""File-like object which incrementally generates a librsync signature""" """File-like object which incrementally generates a librsync signature"""
def __init__(self, infile): def __init__(self, infile, blocksize = _librsync.RS_DEFAULT_BLOCK_LEN):
"""SigFile initializer - takes basis file """SigFile initializer - takes basis file
basis file only needs to have read() and close() methods. It basis file only needs to have read() and close() methods. It
...@@ -116,7 +116,7 @@ class SigFile(LikeFile): ...@@ -116,7 +116,7 @@ class SigFile(LikeFile):
""" """
LikeFile.__init__(self, infile) LikeFile.__init__(self, infile)
try: self.maker = _librsync.new_sigmaker() try: self.maker = _librsync.new_sigmaker(blocksize)
except _librsync.librsyncError, e: raise librsyncError(str(e)) except _librsync.librsyncError, e: raise librsyncError(str(e))
class DeltaFile(LikeFile): class DeltaFile(LikeFile):
...@@ -163,9 +163,9 @@ class SigGenerator: ...@@ -163,9 +163,9 @@ class SigGenerator:
module, not filelike object module, not filelike object
""" """
def __init__(self): def __init__(self, blocksize = _librsync.RS_DEFAULT_BLOCK_LEN):
"""Return new signature instance""" """Return new signature instance"""
try: self.sig_maker = _librsync.new_sigmaker() try: self.sig_maker = _librsync.new_sigmaker(blocksize)
except _librsync.librsyncError, e: raise librsyncError(str(e)) except _librsync.librsyncError, e: raise librsyncError(str(e))
self.gotsig = None self.gotsig = None
self.buffer = "" self.buffer = ""
......
import unittest, random import unittest, random
from commontest import * from commontest import *
from rdiff_backup import librsync from rdiff_backup import librsync, log
def MakeRandomFile(path): def MakeRandomFile(path, length = None):
"""Writes a random file of length between 10000 and 100000""" """Writes a random file of given length, or random len if unspecified"""
fp = open(path, "w") if not length: length = random.randrange(5000, 100000)
randseq = [] fp = open(path, "wb")
for i in xrange(random.randrange(5000, 30000)): fp_random = open('/dev/urandom', 'rb')
randseq.append(chr(random.randrange(256)))
fp.write("".join(randseq))
fp.close()
# Old slow way, may still be of use on systems without /dev/urandom
#randseq = []
#for i in xrange(random.randrange(5000, 30000)):
# randseq.append(chr(random.randrange(256)))
#fp.write("".join(randseq))
fp.write(fp_random.read(length))
fp.close()
fp_random.close()
class LibrsyncTest(unittest.TestCase): class LibrsyncTest(unittest.TestCase):
"""Test various librsync wrapper functions""" """Test various librsync wrapper functions"""
...@@ -20,23 +26,33 @@ class LibrsyncTest(unittest.TestCase): ...@@ -20,23 +26,33 @@ class LibrsyncTest(unittest.TestCase):
sig = RPath(Globals.local_connection, "testfiles/signature") sig = RPath(Globals.local_connection, "testfiles/signature")
sig2 = RPath(Globals.local_connection, "testfiles/signature2") sig2 = RPath(Globals.local_connection, "testfiles/signature2")
delta = RPath(Globals.local_connection, "testfiles/delta") delta = RPath(Globals.local_connection, "testfiles/delta")
def testSigFile(self): def sig_file_test_helper(self, blocksize, iterations, file_len = None):
"""Make sure SigFile generates same data as rdiff""" """Compare SigFile output to rdiff output at given blocksize"""
for i in range(5): for i in range(iterations):
MakeRandomFile(self.basis.path) MakeRandomFile(self.basis.path, file_len)
self.sig.delete() if self.sig.lstat(): self.sig.delete()
assert not os.system("rdiff signature %s %s" % assert not os.system("rdiff -b %s signature %s %s" %
(self.basis.path, self.sig.path)) (blocksize, self.basis.path, self.sig.path))
fp = self.sig.open("rb") fp = self.sig.open("rb")
rdiff_sig = fp.read() rdiff_sig = fp.read()
fp.close() fp.close()
sf = librsync.SigFile(self.basis.open("rb")) sf = librsync.SigFile(self.basis.open("rb"), blocksize)
librsync_sig = sf.read() librsync_sig = sf.read()
sf.close() sf.close()
assert rdiff_sig == librsync_sig, \ assert rdiff_sig == librsync_sig, \
(len(rdiff_sig), len(librsync_sig)) (len(rdiff_sig), len(librsync_sig))
def testSigFile(self):
"""Make sure SigFile generates same data as rdiff, blocksize 512"""
self.sig_file_test_helper(512, 5)
def testSigFile2(self):
"""Test SigFile like above, but try various blocksize"""
self.sig_file_test_helper(2048, 1, 60000)
self.sig_file_test_helper(7168, 1, 6000)
self.sig_file_test_helper(204800, 1, 40*1024*1024)
def testSigGenerator(self): def testSigGenerator(self):
"""Test SigGenerator, make sure it's same as SigFile""" """Test SigGenerator, make sure it's same as SigFile"""
......
...@@ -2,7 +2,7 @@ import unittest, random ...@@ -2,7 +2,7 @@ import unittest, random
from commontest import * from commontest import *
from rdiff_backup import Globals, Rdiff, selection, log, rpath from rdiff_backup import Globals, Rdiff, selection, log, rpath
Log.setverbosity(6) Log.setverbosity(7)
def MakeRandomFile(path): def MakeRandomFile(path):
"""Writes a random file of length between 10000 and 100000""" """Writes a random file of length between 10000 and 100000"""
...@@ -28,7 +28,7 @@ class RdiffTest(unittest.TestCase): ...@@ -28,7 +28,7 @@ class RdiffTest(unittest.TestCase):
sig = rpath.RPath(self.lc, sig = rpath.RPath(self.lc,
"testfiles/various_file_types/regular_file.sig") "testfiles/various_file_types/regular_file.sig")
sigfp = sig.open("r") sigfp = sig.open("r")
rfsig = Rdiff.get_signature(RPath(self.lc, "testfiles/various_file_types/regular_file")) rfsig = Rdiff.get_signature(RPath(self.lc, "testfiles/various_file_types/regular_file"), 2048)
assert rpath.cmpfileobj(sigfp, rfsig) assert rpath.cmpfileobj(sigfp, rfsig)
sigfp.close() sigfp.close()
rfsig.close() rfsig.close()
......
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