From 372bd02a7118d82a070a88f4accdae4738acf41f Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Mon, 10 Jan 2005 10:26:21 +0000 Subject: [PATCH] Delay the renaming of all the temp files until the end of the transfer. --- delay-renames.diff | 179 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 delay-renames.diff diff --git a/delay-renames.diff b/delay-renames.diff new file mode 100644 index 0000000..dca4cd1 --- /dev/null +++ b/delay-renames.diff @@ -0,0 +1,179 @@ +Delay the renaming of all the temp files until the end of the transfer. + +--- options.c 1 Jan 2005 21:08:14 -0000 1.193 ++++ options.c 10 Jan 2005 10:16:54 -0000 +@@ -97,6 +97,7 @@ int modify_window = 0; + int blocking_io = -1; + int checksum_seed = 0; + int inplace = 0; ++int delay_renames = 0; + long block_size = 0; /* "long" because popt can't set an int32. */ + + +@@ -278,6 +279,7 @@ void usage(enum logcode F) + rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n"); + rprintf(F," --partial keep partially transferred files\n"); + rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n"); ++ rprintf(F," --delay-renames renames transferred files into place at end\n"); + rprintf(F," --force force deletion of directories even if not empty\n"); + rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); + rprintf(F," --timeout=TIME set I/O timeout in seconds\n"); +@@ -390,6 +392,7 @@ static struct poptOption long_options[] + {"progress", 0, POPT_ARG_NONE, &do_progress, 0, 0, 0 }, + {"partial", 0, POPT_ARG_NONE, &keep_partial, 0, 0, 0 }, + {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 }, ++ {"delay-renames", 0, POPT_ARG_NONE, &delay_renames, 0, 0, 0 }, + {"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 }, + {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 }, + {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 }, +@@ -944,11 +947,15 @@ int parse_arguments(int *argc, const cha + bwlimit_writemax = 512; + } + ++ if (delay_renames && !partial_dir) ++ partial_dir = ".~tmp~"; ++ + if (inplace) { + #if HAVE_FTRUNCATE + if (partial_dir) { + snprintf(err_buf, sizeof err_buf, +- "--inplace cannot be used with --partial-dir\n"); ++ "--inplace cannot be used with --%s\n", ++ delay_renames ? "delay-renames" : "partial-dir"); + return 0; + } + keep_partial = 0; +@@ -1185,6 +1192,8 @@ void server_options(char **args,int *arg + if (partial_dir && am_sender) { + args[ac++] = "--partial-dir"; + args[ac++] = partial_dir; ++ if (delay_renames) ++ args[ac++] = "--delay-renames"; + } else if (keep_partial) + args[ac++] = "--partial"; + +--- receiver.c 10 Jan 2005 10:03:10 -0000 1.113 ++++ receiver.c 10 Jan 2005 10:16:54 -0000 +@@ -52,6 +52,7 @@ extern int orig_umask; + extern int keep_partial; + extern int checksum_seed; + extern int inplace; ++extern int delay_renames; + + extern struct exclude_list_struct server_exclude_list; + +@@ -344,6 +345,7 @@ int recv_files(int f_in, struct file_lis + char fnametmp[MAXPATHLEN]; + char *fnamecmp, *partialptr; + char fnamecmpbuf[MAXPATHLEN]; ++ uchar *delayed_bits = NULL; + struct file_struct *file; + struct stats initial_stats; + int save_make_backups = make_backups; +@@ -357,6 +359,12 @@ int recv_files(int f_in, struct file_lis + flist->hlink_pool = NULL; + } + ++ if (delay_renames) { ++ if (!(delayed_bits = new_array(char, (flist->count + 7) / 8))) ++ out_of_memory("recv_files"); ++ memset(delayed_bits, 0, (flist->count + 7) / 8); ++ } ++ + while (1) { + cleanup_disable(); + +@@ -566,7 +574,7 @@ int recv_files(int f_in, struct file_lis + exit_cleanup(RERR_FILEIO); + } + +- if (recv_ok || inplace) { ++ if ((recv_ok && !delay_renames) || inplace) { + finish_transfer(fname, fnametmp, file, recv_ok, 1); + if (partialptr != fname && fnamecmp == partialptr) { + do_unlink(partialptr); +@@ -576,6 +584,8 @@ int recv_files(int f_in, struct file_lis + && handle_partial_dir(partialptr, PDIR_CREATE)) { + finish_transfer(partialptr, fnametmp, file, recv_ok, + !partial_dir); ++ if (delay_renames && recv_ok) ++ delayed_bits[i/8] |= 1 << (i % 8); + } else { + partialptr = NULL; + do_unlink(fnametmp); +@@ -615,6 +625,33 @@ int recv_files(int f_in, struct file_lis + } + make_backups = save_make_backups; + ++ if (delay_renames) { ++ for (i = 0; i < flist->count; i++) { ++ struct file_struct *file = flist->files[i]; ++ if (!file->basename ++ || !(delayed_bits[i/8] & (1 << (i % 8)))) ++ continue; ++ fname = local_name ? local_name : f_name(file); ++ partialptr = partial_dir_fname(fname); ++ if (partialptr) { ++ if (make_backups && !make_backup(fname)) ++ continue; ++ if (verbose > 2) { ++ rprintf(FINFO, "renaming %s to %s\n", ++ partialptr, fname); ++ } ++ if (do_rename(partialptr, fname) < 0) { ++ rsyserr(FERROR, errno, ++ "rename failed for %s (from %s)", ++ fname, partialptr); ++ } else { ++ handle_partial_dir(partialptr, ++ PDIR_DELETE); ++ } ++ } ++ } ++ } ++ + if (delete_after && recurse && !local_name && flist->count > 0) + delete_files(flist); + +--- rsync.yo 8 Dec 2004 17:30:40 -0000 1.205 ++++ rsync.yo 10 Jan 2005 10:16:56 -0000 +@@ -348,6 +348,7 @@ verb( + --max-size=SIZE don't transfer any file larger than SIZE + --partial keep partially transferred files + --partial-dir=DIR put a partially transferred file into DIR ++ --delay-renames renames transferred files into place at end + --force force deletion of dirs even if not empty + --numeric-ids don't map uid/gid values by user/group name + --timeout=TIME set I/O timeout in seconds +@@ -544,9 +545,10 @@ or appended data, and also on systems th + bound. + + The option implies --partial (since an interrupted transfer does not delete +-the file), but conflicts with --partial-dir, --compare-dest, --copy-dest, and +---link-dest (a future rsync version will hopefully update the protocol to +-remove some of these restrictions). ++the file), but conflicts with --partial-dir, --compare-dest, --copy-dest, ++--link-dest, and --delay-renames. ++(A future rsync version will hopefully update the protocol to ++remove some of these restrictions.) + + WARNING: The file's data will be in an inconsistent state during the + transfer (and possibly afterward if the transfer gets interrupted), so you +@@ -967,6 +969,17 @@ environment and then just use the -P opt + does not look for this environment value is when --inplace was also + specified (since --inplace conflicts with --partial-dir). + ++dit(bf(--delay-renames)) This option puts the temporary file from each ++updated file into the file's partial-dir (see above) until the end of the ++transfer, at which time all the files are renamed into place in rapid ++succession. This attempts to make the updating of the files a little more ++atomic. If you don't specify the --partial-dir option, this option will ++cause it to default to ".~tmp~" (RSYNC_PARTIAL_DIR is not consulted for ++this value). Conflicts with --inplace. ++ ++See also the "atomic-rsync" perl script in the "support" subdir for an ++update algorithm that is even more atomic (it uses --link-dest). ++ + dit(bf(--progress)) This option tells rsync to print information + showing the progress of the transfer. This gives a bored user + something to watch. -- 2.34.1