[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: Measured: btrfs COW and sqlite exclusive locking

From: Mattias Engdegård <mattiase_at_bredband.net>
Date: Mon, 9 Jul 2012 09:40:48 +0200

8 jul 2012 kl. 19.26 skrev Daniel Shahaf:

> Yes, please specify what the client used COW for. Was it for
> populating the working tree files from the pristine store? Was it for
> something else?

It was only intended for that, but it's possible that the copying code
is used for other purposes as well. The changes look bigger than they
really are, because I had to reorganise some code (in workqueue.c) in
order to expose a plain file copy that was hiding inside.

Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c (revision 1357273)
+++ subversion/libsvn_subr/io.c (working copy)
@@ -29,6 +29,8 @@
  #include <unistd.h>
  #endif

+#include <sys/ioctl.h>
+
  #ifndef APR_STATUS_IS_EPERM
  #include <errno.h>
  #ifdef EPERM
@@ -706,7 +708,14 @@
    return SVN_NO_ERROR;
  }

+#define BTRFS_IOCTL_MAGIC 0x94
+#define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int)

+static int
+cow_copy_file(int dest_fd, int src_fd)
+{
+ return ioctl(dest_fd, BTRFS_IOC_CLONE, src_fd);
+}

  /*** Creating, copying and appending files. ***/
@@ -768,6 +777,13 @@
    const char *dst_tmp;
    svn_error_t *err;

+ typedef enum { No, Unknown, Yes } maybe_t;
+
+ static maybe_t want_cow_copy = Unknown;
+ static maybe_t cow_copy_available = Unknown;
+ svn_boolean_t did_cow_copy;
+
+
    /* ### NOTE: sometimes src == dst. In this case, because we copy
to a
       ### temporary file, and then rename over the top of the
destination,
       ### the net result is resetting the permissions on src/dst.
@@ -796,8 +812,42 @@
                                     svn_dirent_dirname(dst, pool),
                                     svn_io_file_del_none, pool, pool));

- apr_err = copy_contents(from_file, to_file, pool);
+ if (want_cow_copy == Unknown)
+ want_cow_copy = getenv("SVN_COW_COPY") ? Yes : No;
+ did_cow_copy = FALSE;
+ if (want_cow_copy == Yes && cow_copy_available != No)
+ {
+ apr_os_file_t from_fd;
+ apr_os_file_t to_fd;
+ apr_os_file_get(&from_fd, from_file);
+ apr_os_file_get(&to_fd, to_file);
+ int r = cow_copy_file(to_fd, from_fd);
+ if (r == 0)
+ {
+ did_cow_copy = TRUE;
+ if (cow_copy_available == Unknown)
+ fprintf(stderr, "svn: using cow copy\n");
+ cow_copy_available = Yes;
+ apr_err = 0;
+ }
+ else
+ {
+ if (errno == ENOTTY)
+ {
+ cow_copy_available = No;
+ fprintf(stderr, "svn: cow copy not available here (%s)
\n", src);
+ }
+ else
+ {
+ apr_err = apr_get_os_error();
+ SVN_ERR_ASSERT(apr_err);
+ }
+ }
+ }

+ if (!did_cow_copy)
+ apr_err = copy_contents(from_file, to_file, pool);
+
    if (apr_err)
      {
        err = svn_error_wrap_apr(apr_err, _("Can't copy '%s' to '%s'"),
Index: subversion/libsvn_wc/workqueue.c
===================================================================
--- subversion/libsvn_wc/workqueue.c (revision 1357273)
+++ subversion/libsvn_wc/workqueue.c (working copy)
@@ -692,9 +692,6 @@
                                                    scratch_pool,
scratch_pool));
      }

- SVN_ERR(svn_stream_open_readonly(&src_stream, source_abspath,
- scratch_pool, scratch_pool));
-
    /* Fetch all the translation bits. */
    SVN_ERR(svn_wc__get_translate_info(&style, &eol,
                                       &keywords,
@@ -708,6 +705,9 @@
        SVN_ERR(svn_subst_create_specialfile(&dst_stream, local_abspath,
                                             scratch_pool,
scratch_pool));

+ SVN_ERR(svn_stream_open_readonly(&src_stream, source_abspath,
+ scratch_pool, scratch_pool));
+
        /* Copy the "repository normal" form of the special file into
the
           special stream. */
        SVN_ERR(svn_stream_copy3(src_stream, dst_stream,
@@ -718,68 +718,55 @@
        return SVN_NO_ERROR;
      }

+ /* Where is the Right Place to put a temp file in this working
copy? */
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath,
+ db, wcroot_abspath,
+ scratch_pool, scratch_pool));
+
    if (svn_subst_translation_required(style, eol, keywords,
                                       FALSE /* special */,
                                       TRUE /* force_eol_check */))
      {
+ SVN_ERR(svn_stream_open_readonly(&src_stream, source_abspath,
+ scratch_pool, scratch_pool));
+
        /* Wrap it in a translating (expanding) stream. */
        src_stream = svn_subst_stream_translated(src_stream, eol,
                                                 TRUE /* repair */,
                                                 keywords,
                                                 TRUE /* expand */,
                                                 scratch_pool);
- }

- /* Where is the Right Place to put a temp file in this working
copy? */
- SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath,
- db, wcroot_abspath,
- scratch_pool, scratch_pool));
+ /* Translate to a temporary file. We don't want the user seeing
a partial
+ file, nor let them muck with it while we translate. We may
also need to
+ get its TRANSLATED_SIZE before the user can monkey it. */
+ SVN_ERR(svn_stream_open_unique(&dst_stream, &dst_abspath,
+ temp_dir_abspath,
+ svn_io_file_del_none,
+ scratch_pool, scratch_pool));
+
+ /* Copy from the source to the dest, translating as we go. This
will also
+ close both streams. */
+ SVN_ERR(svn_stream_copy3(src_stream, dst_stream,
+ cancel_func, cancel_baton,
+ scratch_pool));

- /* Translate to a temporary file. We don't want the user seeing a
partial
- file, nor let them muck with it while we translate. We may also
need to
- get its TRANSLATED_SIZE before the user can monkey it. */
- SVN_ERR(svn_stream_open_unique(&dst_stream, &dst_abspath,
- temp_dir_abspath,
- svn_io_file_del_none,
- scratch_pool, scratch_pool));
+ /* All done. Move the file into place. */
+ SVN_ERR(svn_io_file_rename(dst_abspath, local_abspath,
scratch_pool));
+ }
+ else
+ {
+ /* No translation required - do a fast file-to-file copy. */

- /* Copy from the source to the dest, translating as we go. This
will also
- close both streams. */
- SVN_ERR(svn_stream_copy3(src_stream, dst_stream,
- cancel_func, cancel_baton,
- scratch_pool));
+ SVN_ERR(svn_io_copy_file(source_abspath, local_abspath,
+ FALSE, scratch_pool));
+ }

- /* All done. Move the file into place. */
+ /* FIXME: The old "tolerant" code that would make missing
directories if
+ the rename failed has been ditched. If we want to keep it, it
could be
+ done prior to the copy instead. (It never worked for "special"
files
+ anyway.) */

- {
- svn_error_t *err;
-
- err = svn_io_file_rename(dst_abspath, local_abspath, scratch_pool);
-
- /* With a single db we might want to install files in a missing
directory.
- Simply trying this scenario on error won't do any harm and at
least
- one user reported this problem on IRC. */
- if (err && APR_STATUS_IS_ENOENT(err->apr_err))
- {
- svn_error_t *err2;
-
- err2 =
svn_io_make_dir_recursively(svn_dirent_dirname(local_abspath,
-
scratch_pool),
- scratch_pool);
-
- if (err2)
- /* Creating directory didn't work: Return all errors */
- return svn_error_trace(svn_error_compose_create(err, err2));
- else
- /* We could create a directory: retry install */
- svn_error_clear(err);
-
- SVN_ERR(svn_io_file_rename(dst_abspath, local_abspath,
scratch_pool));
- }
- else
- SVN_ERR(err);
- }
-
    /* Tweak the on-disk file according to its properties. */
    if (props
        && (apr_hash_get(props, SVN_PROP_NEEDS_LOCK,
APR_HASH_KEY_STRING)
Received on 2012-07-09 09:53:06 CEST

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.