You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2011/05/06 18:44:08 UTC

svn commit: r1100276 - /subversion/trunk/subversion/libsvn_ra_neon/commit.c

Author: cmpilato
Date: Fri May  6 16:44:08 2011
New Revision: 1100276

URL: http://svn.apache.org/viewvc?rev=1100276&view=rev
Log:
Delay activity/transaction creation in ra_neon until open_root(), as
ra_serf does.

* subversion/libsvn_ra_neon/commit.c
  (commit_ctx_t): Add 'revprop_table' and 'pool' members.
  (delete_activity): Only try to DELETE the activity if we have an
    activity URL to DELETE.
  (create_activity): Dup the activity URL into the commit context pool.
  (apply_revprops): Move this function higher up in the source file.
  (commit_open_root): Create the commit transaction/activity and apply
    the revprop changes here now...
  (svn_ra_neon__get_commit_editor): ...instead of here.  This means we
    no longer have to manually call the abort_edit() implementation if
    these steps go wrong, as our driver will be expected to manage
    those scenarios as part of good editor driver etiquette.

Modified:
    subversion/trunk/subversion/libsvn_ra_neon/commit.c

Modified: subversion/trunk/subversion/libsvn_ra_neon/commit.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_neon/commit.c?rev=1100276&r1=1100275&r2=1100276&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_neon/commit.c (original)
+++ subversion/trunk/subversion/libsvn_ra_neon/commit.c Fri May  6 16:44:08 2011
@@ -79,6 +79,10 @@ typedef struct commit_ctx_t
   svn_ra_neon__session_t *ras;
   const char *activity_url;
 
+  /* A hash of revision properties (log messages, etc.) we need to set
+     on the commit transaction. */
+  apr_hash_t *revprop_table; 
+
   apr_hash_t *valid_targets;
 
   svn_ra_get_wc_prop_func_t get_func;
@@ -100,6 +104,9 @@ typedef struct commit_ctx_t
   /* Whether or not to keep the locks after commit is done. */
   svn_boolean_t keep_locks;
 
+  /* Pool for the whole of the commit context. */
+  apr_pool_t *pool;
+
 } commit_ctx_t;
 
 typedef struct put_baton_t
@@ -158,10 +165,16 @@ static svn_error_t * delete_activity(voi
                                      apr_pool_t *pool)
 {
   commit_ctx_t *cc = edit_baton;
-  return svn_ra_neon__simple_request(NULL, cc->ras, "DELETE",
-                                     cc->activity_url, NULL, NULL,
-                                     204 /* No Content */,
-                                     404 /* Not Found */, pool);
+
+  /* If we started an activity, we need to (try to) delete it.  (If it
+     doesn't exist, that's okay, too.) */
+  if (cc->activity_url)
+    SVN_ERR(svn_ra_neon__simple_request(NULL, cc->ras, "DELETE",
+                                        cc->activity_url, NULL, NULL,
+                                        204 /* No Content */,
+                                        404 /* Not Found */, pool));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -342,7 +355,7 @@ static svn_error_t * create_activity(com
                                           201, 0, pool));
     }
 
-  cc->activity_url = url;
+  cc->activity_url = apr_pstrdup(cc->pool, url);
 
   return SVN_NO_ERROR;
 }
@@ -665,6 +678,59 @@ add_valid_target(commit_ctx_t *cc,
 }
 
 
+/* PROPPATCH the appropriate resource in order to set the properties
+   in REVPROP_TABLE on the commit transaction.  Use POOL for
+   temporary allocations.  */
+static svn_error_t *
+apply_revprops(commit_ctx_t *cc,
+               apr_hash_t *revprop_table,
+               apr_pool_t *pool)
+{
+  const char *vcc;
+  version_rsrc_t vcc_rsrc = { SVN_INVALID_REVNUM };
+  svn_error_t *err = NULL;
+  int retry_count = 5;
+
+  /* ### this whole sequence can/should be replaced with an expand-property
+     ### REPORT when that is available on the server. */
+
+  /* fetch the DAV:version-controlled-configuration from the session's URL */
+  SVN_ERR(svn_ra_neon__get_vcc(&vcc, cc->ras, cc->ras->root.path, pool));
+
+
+  do {
+
+    svn_error_clear(err);
+
+    vcc_rsrc.pool = pool;
+    vcc_rsrc.vsn_url = vcc;
+
+    /* To set the revision properties, we must checkout the latest baseline
+       and get back a mutable "working" baseline.  */
+    err = checkout_resource(cc, &vcc_rsrc, FALSE, NULL, TRUE, pool);
+
+    /* There's a small chance of a race condition here, if apache is
+       experiencing heavy commit concurrency or if the network has
+       long latency.  It's possible that the value of HEAD changed
+       between the time we fetched the latest baseline and the time we
+       checkout that baseline.  If that happens, apache will throw us
+       a BAD_BASELINE error (deltaV says you can only checkout the
+       latest baseline).  We just ignore that specific error and
+       retry a few times, asking for the latest baseline again. */
+    if (err && err->apr_err != SVN_ERR_APMOD_BAD_BASELINE)
+      return err;
+
+  } while (err && (--retry_count > 0));
+
+  /* Yikes, if we couldn't hold onto HEAD after a few retries, throw a
+     real error.*/
+  if (err)
+    return err;
+
+  return svn_ra_neon__do_proppatch(cc->ras, vcc_rsrc.wr_url, revprop_table,
+                                   NULL, NULL, NULL, pool);
+}
+
 
 static svn_error_t * commit_open_root(void *edit_baton,
                                       svn_revnum_t base_revision,
@@ -675,11 +741,19 @@ static svn_error_t * commit_open_root(vo
   resource_baton_t *root;
   version_rsrc_t *rsrc;
 
-  /* create the root resource. no wr_url (yet). */
+  /* Create a server-side activity which corresponds directly to an FS
+     transaction.  We will check out all further resources within the
+     context of this activity.  */
+  SVN_ERR(create_activity(cc, dir_pool));
+
+  /* Find the latest baseline resource, check it out, and then apply
+     the log message onto the thing. */
+  SVN_ERR(apply_revprops(cc, cc->revprop_table, dir_pool));
+
+  /* Create the root resource.  (We don't yet know the wr_url.) */
   rsrc = apr_pcalloc(dir_pool, sizeof(*rsrc));
   rsrc->pool = dir_pool;
   rsrc->revision = base_revision;
-
   rsrc->url = cc->ras->root.path;
   rsrc->local_path = "";
 
@@ -1346,55 +1420,6 @@ static svn_error_t * commit_abort_edit(v
 }
 
 
-static svn_error_t * apply_revprops(commit_ctx_t *cc,
-                                    apr_hash_t *revprop_table,
-                                    apr_pool_t *pool)
-{
-  const char *vcc;
-  version_rsrc_t vcc_rsrc = { SVN_INVALID_REVNUM };
-  svn_error_t *err = NULL;
-  int retry_count = 5;
-
-  /* ### this whole sequence can/should be replaced with an expand-property
-     ### REPORT when that is available on the server. */
-
-  /* fetch the DAV:version-controlled-configuration from the session's URL */
-  SVN_ERR(svn_ra_neon__get_vcc(&vcc, cc->ras, cc->ras->root.path, pool));
-
-
-  do {
-
-    svn_error_clear(err);
-
-    vcc_rsrc.pool = pool;
-    vcc_rsrc.vsn_url = vcc;
-
-    /* To set the revision properties, we must checkout the latest baseline
-       and get back a mutable "working" baseline.  */
-    err = checkout_resource(cc, &vcc_rsrc, FALSE, NULL, TRUE, pool);
-
-    /* There's a small chance of a race condition here, if apache is
-       experiencing heavy commit concurrency or if the network has
-       long latency.  It's possible that the value of HEAD changed
-       between the time we fetched the latest baseline and the time we
-       checkout that baseline.  If that happens, apache will throw us
-       a BAD_BASELINE error (deltaV says you can only checkout the
-       latest baseline).  We just ignore that specific error and
-       retry a few times, asking for the latest baseline again. */
-    if (err && err->apr_err != SVN_ERR_APMOD_BAD_BASELINE)
-      return err;
-
-  } while (err && (--retry_count > 0));
-
-  /* Yikes, if we couldn't hold onto HEAD after a few retries, throw a
-     real error.*/
-  if (err)
-    return err;
-
-  return svn_ra_neon__do_proppatch(cc->ras, vcc_rsrc.wr_url, revprop_table,
-                                   NULL, NULL, NULL, pool);
-}
-
 svn_error_t * svn_ra_neon__get_commit_editor(svn_ra_session_t *session,
                                              const svn_delta_editor_t **editor,
                                              void **edit_baton,
@@ -1408,10 +1433,11 @@ svn_error_t * svn_ra_neon__get_commit_ed
   svn_ra_neon__session_t *ras = session->priv;
   svn_delta_editor_t *commit_editor;
   commit_ctx_t *cc;
-  svn_error_t *err;
+  apr_hash_index_t *hi;
 
   /* Build the main commit editor's baton. */
   cc = apr_pcalloc(pool, sizeof(*cc));
+  cc->pool = pool;
   cc->ras = ras;
   cc->valid_targets = apr_hash_make(pool);
   cc->get_func = ras->callbacks->get_wc_prop;
@@ -1422,42 +1448,26 @@ svn_error_t * svn_ra_neon__get_commit_ed
   cc->tokens = lock_tokens;
   cc->keep_locks = keep_locks;
 
+  /* Dup the revprops into POOL, in case the caller clears the pool
+     they're in before driving the editor that this function returns. */
+  cc->revprop_table = apr_hash_make(pool);
+  for (hi = apr_hash_first(pool, revprop_table); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      apr_ssize_t klen;
+      void *val;
+
+      apr_hash_this(hi, &key, &klen, &val);
+      apr_hash_set(cc->revprop_table, apr_pstrdup(pool, key), klen,
+                   svn_string_dup(val, pool));
+    }
+
   /* If the caller didn't give us any way of storing wcprops, then
-     there's no point in getting back a MERGE response full of VR's. */
+     there's no point in getting back a MERGE response full of VR's.  */
   if (ras->callbacks->push_wc_prop == NULL)
     cc->disable_merge_response = TRUE;
 
-  /* ### should we perform an OPTIONS to validate the server we're about
-     ### to talk to? */
-
-  /*
-  ** Create an Activity. This corresponds directly to an FS transaction.
-  ** We will check out all further resources within the context of this
-  ** activity.
-  */
-  SVN_ERR(create_activity(cc, pool));
-
-  /*
-  ** Find the latest baseline resource, check it out, and then apply the
-  ** log message onto the thing.
-  */
-  err = apply_revprops(cc, revprop_table, pool);
-  /* If the caller gets an error during the editor drive, we rely on them
-     to call abort_edit() so that we can clear up the activity.  But if we
-     got an error here, we need to clear up the activity ourselves. */
-  if (err)
-    {
-      svn_error_clear(commit_abort_edit(cc, pool));
-      return err;
-    }
-
-  /*
-  ** Set up the editor.
-  **
-  ** This structure is used during the commit process. An external caller
-  ** uses these callbacks to describe all the changes in the working copy
-  ** that must be committed to the server.
-  */
+  /* Set up the editor. */
   commit_editor = svn_delta_default_editor(pool);
   commit_editor->open_root = commit_open_root;
   commit_editor->delete_entry = commit_delete_entry;