Adding the manpage writeup from Matt.
[rsync/rsync-patches.git] / early-checksum.diff
CommitLineData
2d2150f6
WD
1This patch changes the way the --checksum option works by having the
2receiving side perform a checksum-read of every file in the file list
d47d38c7 3as the list is received (if the sizes are equal), marking non-matching
2d2150f6
WD
4items with a flag. The idea is that the checksum pass on the sender and
5the receiver can then happen in parallel instead of having the reciever
6to its checksum pass during its normal find-the-different-files pass.
7
d47d38c7
WD
8I have benchmarked this a little, and it appears to slow things down
9for a local copy, so the old algorithm is used for local copies.
2d2150f6 10
03019e41
WD
11To use this patch, run these commands for a successful build:
12
13 patch -p1 <patches/early-checksum.diff
14 ./configure (optional if already run)
15 make
16
9a7eef96
WD
17--- old/flist.c
18+++ new/flist.c
b5abdf47 19@@ -31,6 +31,7 @@ extern int am_daemon;
2d2150f6
WD
20 extern int am_sender;
21 extern int do_progress;
22 extern int always_checksum;
23+extern int pre_checksum;
24 extern int module_id;
25 extern int ignore_errors;
26 extern int numeric_ids;
7c15d5aa
WD
27@@ -785,6 +786,15 @@ static struct file_struct *recv_file_ent
28 memcpy(bp, F_SUM(first), checksum_len);
29 } else
30 read_buf(f, bp, checksum_len);
70891d26 31+ if (pre_checksum && sum_len) {
2d2150f6 32+ STRUCT_STAT st;
bd68c3c2 33+ char *fname = f_name(file, NULL);
2d2150f6 34+ if (stat(fname, &st) == 0 && st.st_size == file_length) {
70891d26
WD
35+ file_checksum(fname, tmp_sum, st.st_size);
36+ if (memcmp(bp, tmp_sum, checksum_len) != 0)
2d2150f6
WD
37+ file->flags |= FLAG_SUM_DIFFERS;
38+ }
39+ }
40 }
41
9a7eef96
WD
42 return file;
43--- old/generator.c
44+++ new/generator.c
1aa236e1 45@@ -70,6 +70,7 @@ extern int ignore_timeout;
2d2150f6
WD
46 extern int protocol_version;
47 extern int fuzzy_basis;
48 extern int always_checksum;
49+extern int pre_checksum;
d57e621e 50 extern int checksum_len;
2d2150f6
WD
51 extern char *partial_dir;
52 extern char *basis_dir[];
7c15d5aa 53@@ -577,7 +578,8 @@ void itemize(struct file_struct *file, i
2d2150f6
WD
54
55
56 /* Perform our quick-check heuristic for determining if a file is unchanged. */
f20eb450
WD
57-int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
58+int unchanged_file(char *fn, int fnamecmp_type, struct file_struct *file,
59+ STRUCT_STAT *st)
2d2150f6 60 {
1aa236e1 61 if (st->st_size != F_LENGTH(file))
2d2150f6 62 return 0;
7c15d5aa 63@@ -586,6 +588,8 @@ int unchanged_file(char *fn, struct file
2d2150f6
WD
64 of the file time to determine whether to sync */
65 if (always_checksum && S_ISREG(st->st_mode)) {
66 char sum[MD4_SUM_LENGTH];
67+ if (pre_checksum && fnamecmp_type == FNAMECMP_FNAME)
68+ return !(file->flags & FLAG_SUM_DIFFERS);
69 file_checksum(fn, sum, st->st_size);
70891d26 70 return memcmp(sum, F_SUM(file), checksum_len) == 0;
d57e621e 71 }
7c15d5aa 72@@ -825,7 +829,7 @@ static int try_dests_reg(struct file_str
f20eb450
WD
73 match_level = 1;
74 /* FALL THROUGH */
75 case 1:
76- if (!unchanged_file(cmpbuf, file, stp))
77+ if (!unchanged_file(cmpbuf, 0, file, stp))
78 continue;
79 best_match = j;
80 match_level = 2;
7c15d5aa 81@@ -1511,7 +1515,7 @@ static void recv_generator(char *fname,
2d2150f6
WD
82 ;
83 else if (fnamecmp_type == FNAMECMP_FUZZY)
84 ;
85- else if (unchanged_file(fnamecmp, file, &st)) {
86+ else if (unchanged_file(fnamecmp, fnamecmp_type, file, &st)) {
d57e621e
WD
87 if (partialptr) {
88 do_unlink(partialptr);
89 handle_partial_dir(partialptr, PDIR_DELETE);
9a7eef96
WD
90--- old/hlink.c
91+++ new/hlink.c
7c15d5aa 92@@ -448,7 +448,7 @@ int hard_link_check(struct file_struct *
7b80cd0e
WD
93 }
94 break;
95 }
96- if (!unchanged_file(cmpbuf, file, &alt_st))
97+ if (!unchanged_file(cmpbuf, 0, file, &alt_st))
98 continue;
99 statret = 1;
100 *stp = alt_st;
9a7eef96
WD
101--- old/main.c
102+++ new/main.c
b5abdf47 103@@ -47,6 +47,7 @@ extern int copy_dirlinks;
2d2150f6
WD
104 extern int keep_dirlinks;
105 extern int preserve_hard_links;
106 extern int protocol_version;
107+extern int always_checksum;
108 extern int recurse;
109 extern int relative_paths;
b5abdf47 110 extern int sanitize_paths;
60a8bf36
WD
111@@ -71,6 +72,9 @@ extern char *batch_name;
112 extern char curr_dir[MAXPATHLEN];
f4e59d46 113 extern struct filter_list_struct server_filter_list;
2d2150f6 114
af7eb67a
WD
115+extern char curr_dir[MAXPATHLEN];
116+
2d2150f6 117+int pre_checksum = 0;
d9a67109 118 int local_server = 0;
60a8bf36 119 int new_root_dir = 0;
d9a67109 120 mode_t orig_umask = 0;
7b80cd0e 121@@ -788,6 +792,7 @@ static void do_server_recv(int f_in, int
2d2150f6
WD
122 struct file_list *flist;
123 char *local_name = NULL;
124 char *dir = NULL;
125+ char olddir[sizeof curr_dir];
126 int save_verbose = verbose;
127
128 if (filesfrom_fd >= 0) {
7c15d5aa
WD
129@@ -831,6 +836,10 @@ static void do_server_recv(int f_in, int
130 filesfrom_fd = -1;
131 }
2d2150f6
WD
132
133+ strlcpy(olddir, curr_dir, sizeof olddir);
d47d38c7 134+ if (always_checksum && !local_server && argc > 0)
de565f59 135+ pre_checksum = push_dir(argv[0], 0);
2d2150f6
WD
136+
137 flist = recv_file_list(f_in);
138 verbose = save_verbose;
139 if (!flist) {
7c15d5aa 140@@ -839,6 +848,9 @@ static void do_server_recv(int f_in, int
2d2150f6
WD
141 }
142 the_file_list = flist;
143
144+ if (pre_checksum)
145+ pop_dir(olddir);
146+
147 if (argc > 0)
148 local_name = get_local_name(flist,argv[0]);
149
7c15d5aa 150@@ -918,6 +930,7 @@ int client_run(int f_in, int f_out, pid_
2d2150f6
WD
151 {
152 struct file_list *flist = NULL;
153 int exit_code = 0, exit_code2 = 0;
154+ char olddir[sizeof curr_dir];
155 char *local_name = NULL;
156
157 cleanup_child_pid = pid;
7c15d5aa
WD
158@@ -992,11 +1005,18 @@ int client_run(int f_in, int f_out, pid_
159 filesfrom_fd = -1;
160 }
2d2150f6
WD
161
162+ strlcpy(olddir, curr_dir, sizeof olddir);
d47d38c7 163+ if (always_checksum && !local_server)
de565f59 164+ pre_checksum = push_dir(argv[0], 0);
2d2150f6
WD
165+
166 if (write_batch && !am_server)
167 start_write_batch(f_in);
168 flist = recv_file_list(f_in);
169 the_file_list = flist;
170
171+ if (pre_checksum)
172+ pop_dir(olddir);
173+
174 if (flist && flist->count > 0) {
175 local_name = get_local_name(flist, argv[0]);
176
9a7eef96
WD
177--- old/rsync.h
178+++ new/rsync.h
7c15d5aa 179@@ -68,6 +68,7 @@
1aa236e1 180 #define FLAG_HLINK_LAST (1<<7) /* receiver/generator */
7b80cd0e
WD
181 #define FLAG_HLINK_DONE (1<<8) /* receiver/generator */
182 #define FLAG_LENGTH64 (1<<9) /* sender/receiver/generator */
183+#define FLAG_SUM_DIFFERS (1<<10)/* receiver/generator */
1aa236e1 184
7b80cd0e
WD
185 #define BITS_SET(val,bits) (((val) & (bits)) == (bits))
186 #define BITS_SETnUNSET(val,onbits,offbits) (((val) & ((onbits)|(offbits))) == (onbits))