This patch changes the way the --checksum option works by having the receiving side perform a checksum-read of every file in the file list as the list is received (if the sizes are equal), marking non-matching items with a flag. The idea is that the checksum pass on the sender and the receiver can then happen in parallel instead of having the reciever to its checksum pass during its normal find-the-different-files pass. I have benchmarked this a little, and it appears to slow things down for a local copy, so the old algorithm is used for local copies. To use this patch, run these commands for a successful build: patch -p1 flags |= FLAG_SUM_DIFFERS; + } + } } #ifdef SUPPORT_ACLS --- old/generator.c +++ new/generator.c @@ -73,6 +73,7 @@ extern int protocol_version; extern int file_total; extern int fuzzy_basis; extern int always_checksum; +extern int pre_checksum; extern int checksum_len; extern char *partial_dir; extern char *basis_dir[]; @@ -617,7 +618,8 @@ void itemize(const char *fnamecmp, struc /* Perform our quick-check heuristic for determining if a file is unchanged. */ -int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st) +int unchanged_file(char *fn, int fnamecmp_type, struct file_struct *file, + STRUCT_STAT *st) { if (st->st_size != F_LENGTH(file)) return 0; @@ -626,6 +628,8 @@ int unchanged_file(char *fn, struct file of the file time to determine whether to sync */ if (always_checksum > 0 && S_ISREG(st->st_mode)) { char sum[MAX_DIGEST_LEN]; + if (pre_checksum && fnamecmp_type == FNAMECMP_FNAME) + return !(file->flags & FLAG_SUM_DIFFERS); file_checksum(fn, sum, st->st_size); return memcmp(sum, F_SUM(file), checksum_len) == 0; } @@ -846,7 +850,7 @@ static int try_dests_reg(struct file_str match_level = 1; /* FALL THROUGH */ case 1: - if (!unchanged_file(cmpbuf, file, &sxp->st)) + if (!unchanged_file(cmpbuf, 0, file, &sxp->st)) continue; best_match = j; match_level = 2; @@ -1638,7 +1642,7 @@ static void recv_generator(char *fname, ; else if (fnamecmp_type == FNAMECMP_FUZZY) ; - else if (unchanged_file(fnamecmp, file, &sx.st)) { + else if (unchanged_file(fnamecmp, fnamecmp_type, file, &sx.st)) { if (partialptr) { do_unlink(partialptr); handle_partial_dir(partialptr, PDIR_DELETE); --- old/hlink.c +++ new/hlink.c @@ -353,7 +353,7 @@ int hard_link_check(struct file_struct * } break; } - if (!unchanged_file(cmpbuf, file, &alt_sx.st)) + if (!unchanged_file(cmpbuf, 0, file, &alt_sx.st)) continue; statret = 1; if (unchanged_attrs(cmpbuf, file, &alt_sx)) --- old/main.c +++ new/main.c @@ -46,6 +46,7 @@ extern int module_id; extern int copy_links; extern int copy_dirlinks; extern int keep_dirlinks; +extern int always_checksum; extern int preserve_hard_links; extern int protocol_version; extern int file_total; @@ -78,6 +79,9 @@ extern struct filter_list_struct server_ extern iconv_t ic_send; #endif +extern char curr_dir[MAXPATHLEN]; + +int pre_checksum = 0; int local_server = 0; int daemon_over_rsh = 0; mode_t orig_umask = 0; @@ -850,6 +854,7 @@ static void do_server_recv(int f_in, int struct file_list *flist; char *local_name = NULL; char *dir = NULL; + char olddir[sizeof curr_dir]; int save_verbose = verbose; if (filesfrom_fd >= 0) { @@ -896,6 +901,10 @@ static void do_server_recv(int f_in, int filesfrom_fd = -1; } + strlcpy(olddir, curr_dir, sizeof olddir); + if (always_checksum && !local_server && argc > 0) + pre_checksum = push_dir(argv[0], 0); + flist = recv_file_list(f_in); if (!flist) { rprintf(FERROR,"server_recv: recv_file_list error\n"); @@ -905,6 +914,9 @@ static void do_server_recv(int f_in, int recv_additional_file_list(f_in); verbose = save_verbose; + if (pre_checksum) + pop_dir(olddir); + if (argc > 0) local_name = get_local_name(flist,argv[0]); @@ -981,6 +993,7 @@ int client_run(int f_in, int f_out, pid_ { struct file_list *flist = NULL; int exit_code = 0, exit_code2 = 0; + char olddir[sizeof curr_dir]; char *local_name = NULL; cleanup_child_pid = pid; @@ -1058,12 +1071,19 @@ int client_run(int f_in, int f_out, pid_ filesfrom_fd = -1; } + strlcpy(olddir, curr_dir, sizeof olddir); + if (always_checksum && !local_server) + pre_checksum = push_dir(argv[0], 0); + if (write_batch && !am_server) start_write_batch(f_in); flist = recv_file_list(f_in); if (inc_recurse && file_total == 1) recv_additional_file_list(f_in); + if (pre_checksum) + pop_dir(olddir); + if (flist && flist->used > 0) { local_name = get_local_name(flist, argv[0]); --- old/rsync.h +++ new/rsync.h @@ -73,6 +73,7 @@ #define FLAG_HLINK_DONE (1<<8) /* receiver/generator */ #define FLAG_LENGTH64 (1<<9) /* sender/receiver/generator */ #define FLAG_SKIP_GROUP (1<<10) /* receiver/generator */ +#define FLAG_SUM_DIFFERS (1<<11)/* receiver/generator */ /* These flags are passed to functions but not stored. */