]> git.ipfire.org Git - thirdparty/rsync.git/commitdiff
- Per-file dynamic block size is now sqrt(file length).
authorJ.W. Schultz <jw@samba.org>
Thu, 10 Apr 2003 02:04:58 +0000 (02:04 +0000)
committerJ.W. Schultz <jw@samba.org>
Thu, 10 Apr 2003 02:04:58 +0000 (02:04 +0000)
    - The per-file checksum size is determined according
to an algorythm provided by Donovan Baarda which
reduces the probability of rsync algorithm
corrupting data and falling back using the whole md4
checksums.

NEWS
generator.c
options.c
rsync.h

diff --git a/NEWS b/NEWS
index 4a9406ce406901985dd7e9e3ddb04929c8884549..ec1966d7807448423c7842d99fe859f5f58b26ad 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,5 @@
 NEWS for rsync version 2.5.7
-Protocol: 26 (unchanged)
+Protocol: 27 (changed)
 Changes since version 2.5.6:
 
   ENHANCEMENTS:
@@ -8,9 +8,31 @@ Changes since version 2.5.6:
       Note that --from0 affects the line-ending character for all the
       --*-from options. (Wayne Davison)
 
+    -  Length of csum2 is now per-file starting with protocol verison
+       27. (J.W. Schultz)
+
+    -   Per-file dynamic block size is now sqrt(file length).
+
+       The per-file checksum size is determined according
+       to an algorythm provided by Donovan Baarda which
+       reduces the probability of rsync algorithm
+       corrupting data and falling back using the whole md4
+       checksums. (J.W. Schultz, Donovan Baarda)
+
   BUG FIXES:
 
-    - Fixed a crash bug when interacting with older rsync versions and
+    -   for protocol version >= 27, mdfour_tail() is called when the
+       block size (including checksum_seed) is a multiple of 64.
+       Previously it was not called, giving the wrong MD4 checksum.
+       (Craig Barratt)
+  
+    -   for protocol version >= 27, a 64 bit bit counter is used in
+       mdfour.c as required by the RFC.  Previously only a 32 bit bit
+       counter was used, causing incorrect MD4 file checksums for
+       file sizes >= 512MB - 4.  (Craig Barratt)
+
+
+    - Fixed a crash bug when interacting with  Craiolder rsync versioss and
       multiple files of the same name are destined for the same dir.
       (Wayne Davison)
 
index 740ce668e1f92d5ce6730efd03ea8cf8fced1a4b..aca5f7b27863aaa1581b659368e771a7982fe1d1 100644 (file)
@@ -32,7 +32,6 @@ extern int preserve_devices;
 extern int preserve_hard_links;
 extern int update_only;
 extern int opt_ignore_existing;
-extern int block_size;
 extern int csum_length;
 extern int ignore_times;
 extern int size_only;
@@ -100,24 +99,9 @@ static int skip_file(char *fname,
 }
 
 
-/* use a larger block size for really big files */
-static int adapt_block_size(struct file_struct *file, int bsize)
-{
-       int ret;
-
-       if (bsize != BLOCK_SIZE) return bsize;
-
-       ret = file->length / (10000); /* rough heuristic */
-       ret = ret & ~15; /* multiple of 16 */
-       if (ret < bsize) ret = bsize;
-       if (ret > CHUNK_SIZE/2) ret = CHUNK_SIZE/2;
-       return ret;
-}
-
-
 /*
  *     NULL sum_struct means we have no checksums
 */
+ */
 
 void write_sum_head(int f, struct sum_struct *sum)
 {
@@ -133,7 +117,87 @@ void write_sum_head(int f, struct sum_struct *sum)
        write_int(f, sum->remainder);
 }
 
+/* 
+ * set (initialize) the size entries in the per-file sum_struct
+ * calulating dynamic block ans checksum sizes.
+ *
+ * This is only called from generate_and_send_sums() but is a seperate
+ * function to encapsulate the logic.
+ *
+ * The block size is a rounded square root of file length.
+ *
+ * The checksum size is determined according to:
+ *     blocksum_bits = BLOCKSUM_EXP + 2*log2(file_len) - log2(block_len)
+ * provided by Donovan Baarda which gives a probability of rsync
+ * algorithm corrupting data and falling back using the whole md4
+ * checksums.
+ *
+ * This might be made one of several selectable heuristics.
+ */
 
+static void sum_sizes_sqroot_baarda(struct sum_struct *sum, uint64 len)
+{
+       extern int block_size;
+       int blength, s2length, b;
+       uint32 c;
+       uint64 l;
+
+       if (block_size) {
+               blength = block_size;
+       } else if (len <= BLOCK_SIZE * BLOCK_SIZE) {
+               blength = BLOCK_SIZE;
+       } else {
+               l = len;
+               c = 1;
+               while (l >>= 2) {
+                       c <<= 1;
+               }
+               blength = 0;
+               do {
+                       blength |= c;
+                       if (len < (uint64)(blength * blength))
+                               blength &= ~c;
+                       c >>= 1;
+               } while (c >= 8);       /* round to multiple of 8 */
+               blength = MAX(blength, BLOCK_SIZE);
+       }
+
+       if (remote_version < 27) {
+               s2length = csum_length;
+       } else if (csum_length == SUM_LENGTH) {
+               s2length = SUM_LENGTH;
+       } else {
+               b = BLOCKSUM_BIAS;
+               l = len;
+               while (l >>= 1) {
+                       b += 2;
+               }
+               c = blength;
+               while (c >>= 1 && b) {
+                       b--;
+               }
+               s2length = (b + 1 - 32 + 7) / 8; /* add a bit,
+                                                 * subtract rollsum,
+                                                 * round up
+                                                 *    --optimize in compiler--
+                                                 */
+               s2length = MAX(s2length, csum_length);
+               s2length = MIN(s2length, SUM_LENGTH);
+       }
+
+       sum->flength    = len;
+       sum->blength    = blength;
+       sum->s2length   = s2length;
+       sum->count      = (len + (blength - 1)) / blength;
+       sum->remainder  = (len % blength);
+
+       if (sum->count && verbose > 2) {
+               rprintf(FINFO, "count=%ld rem=%ld blength=%ld s2length=%ld flength=%.0f\n",
+                       (long) sum->count, (long) sum->remainder,
+                       (long) sum->blength, (long) sum->s2length,
+                       (double) sum->flength);
+       }
+}
 
 /**
  * Perhaps we want to just send an empty checksum set for this file,
@@ -163,30 +227,18 @@ static BOOL disable_deltas_p(void)
  *
  * Generate approximately one checksum every block_len bytes.
  */
-static void generate_and_send_sums(struct map_struct *buf, OFF_T len,
-                                  int block_len, int f_out)
+static void generate_and_send_sums(struct map_struct *buf, OFF_T len, int f_out)
 {
        size_t i;
        struct sum_struct sum;
        OFF_T offset = 0;
 
-       sum.count = (len + (block_len - 1)) / block_len;
-       sum.remainder = (len % block_len);
-       sum.blength     = block_len;
-       sum.flength = len;
-       sum.s2length    = csum_length;
-       /* not needed here  sum.sums = NULL; */
-
-       if (sum.count && verbose > 3) {
-               rprintf(FINFO, "count=%ld rem=%ld n=%ld flength=%.0f\n",
-                       (long) sum.count, (long) sum.remainder,
-                       (long) sum.blength, (double) sum.flength);
-       }
+       sum_sizes_sqroot_baarda(&sum, len);
 
        write_sum_head(f_out, &sum);
 
        for (i = 0; i < sum.count; i++) {
-               int n1 = MIN(len, block_len);
+               int n1 = MIN(len, sum.blength);
                char *map = map_ptr(buf, offset, n1);
                uint32 sum1 = get_checksum1(map, n1);
                char sum2[SUM_LENGTH];
@@ -465,8 +517,7 @@ void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
                rprintf(FINFO, "generating and sending sums for %d\n", i);
 
        write_int(f_out,i);
-       generate_and_send_sums(buf, st.st_size,
-                              adapt_block_size(file, block_size), f_out);
+       generate_and_send_sums(buf, st.st_size, f_out);
 
        close(fd);
        if (buf) unmap_file(buf);
index 772a87fa9e8d3286c1139b2212d905ce8154fbb2..14019a23034af995906add865810ff334692948c 100644 (file)
--- a/options.c
+++ b/options.c
@@ -77,7 +77,7 @@ int do_progress=0;
 int keep_partial=0;
 int safe_symlinks=0;
 int copy_unsafe_links=0;
-int block_size=BLOCK_SIZE;
+int block_size=0;
 int size_only=0;
 int bwlimit=0;
 int delete_after=0;
@@ -775,7 +775,7 @@ void server_options(char **args,int *argc)
 
        if (x != 1) args[ac++] = argstr;
 
-       if (block_size != BLOCK_SIZE) {
+       if (block_size) {
                snprintf(bsize,sizeof(bsize),"-B%d",block_size);
                args[ac++] = bsize;
        }
diff --git a/rsync.h b/rsync.h
index 0dd3e654e9ef30c165055fddf7628135455c0c50..e3cbe5709660c816431342f1282ea2b4aab1fe7a 100644 (file)
--- a/rsync.h
+++ b/rsync.h
@@ -341,6 +341,8 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
 /* the length of the md4 checksum */
 #define MD4_SUM_LENGTH 16
 #define SUM_LENGTH 16
+#define SHORT_SUM_LENGTH 2
+#define BLOCKSUM_BIAS 10
 
 #ifndef MAXPATHLEN
 #define MAXPATHLEN 1024