Delay the renaming of all the temp files until the end of the transfer.
authorWayne Davison <wayned@samba.org>
Mon, 10 Jan 2005 10:26:21 +0000 (10:26 +0000)
committerWayne Davison <wayned@samba.org>
Mon, 10 Jan 2005 10:26:21 +0000 (10:26 +0000)
delay-renames.diff [new file with mode: 0644]

diff --git a/delay-renames.diff b/delay-renames.diff
new file mode 100644 (file)
index 0000000..dca4cd1
--- /dev/null
@@ -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.