danie...@apache.org wrote on Sat, Aug 07, 2010 at 17:45:39 -0000:
> Author: danielsh
> Date: Sat Aug  7 17:45:38 2010
> New Revision: 983269
> 
> URL: http://svn.apache.org/viewvc?rev=983269&view=rev
> Log:
> On the 'atomic-revprop' branch:
> 
> Implement the API over ra_dav.
> 

I'll appreciate some extra eyes on this revision.

Thanks.

Daniel
(reasons for this request: at the end)

> 
> First, some general infrastructure:
> 
> * notes/http-and-webdav/webdav-protocol
>   (PROPPATCH):  Document the protocol extension.
> 
> * subversion/include/private/svn_dav_protocol.h
>   (SVN_DAV__OLD_VALUE, SVN_DAV__OLD_VALUE__ABSENT):  New macros.
>   (svn_dav__two_props_t):  New helper typedef.
> 
> 
> Then, mod_dav_svn support:
> 
> * subversion/mod_dav_svn/deadprops.c
>   (save_value):
>     Grow and use an OLD_VALUE_P parameter, passing it
>     to svn_repos_fs_change_rev_prop4().
>   (decode_property_value):
>     Grow an ABSENT out parameter, and parse the (new) 'V:absent' attribute.
>   (db_store):
>     Parse <V:old-value/> and 'V:absent' and pass OLD_VALUE_P to save_value().
> 
> 
> ra_serf support:
> 
> * subversion/libsvn_ra_serf/ra_serf.h
>   (svn_ra_serf__walk_all_props, svn_ra_serf__set_ver_prop):
>     Remove "not implemented" markers from docstrings.
> 
> * subversion/libsvn_ra_serf/property.c
>   (svn_ra_serf__set_ver_prop):
>     Store an svn_dav__two_props_t in the hash if an OLD_VALUE_P was provided.
>   (svn_ra_serf__walk_all_props):
>     Support the VALUES_ARE_PROPPAIRS parameter when calling the walker.
> 
> * subversion/libsvn_ra_serf/commit.c
>   (proppatch_context_t):  Add 'atomic_props' member.
>   (get_encoding_and_cdata):
>     Refactor to return a string rather than a bucket,
>     and to support a NULL value.
>   (proppatch_walker):
>     Track get_encoding_and_cdata() signature change.
>     Set 'V:absent' and <V:old-value/> as appropriate.
>   (create_proppatch_body):
>     Walk/Iterate CTX->ATOMIC_PROPS too.
>   (svn_ra_serf__change_rev_prop):
>     Remove 'not implemented' sentinel.  Initialize CTX->ATOMIC_PROPS.
>     Pass OLD_VALUE_P to svn_ra_serf__set_prop() (which passes it
>     to svn_ra_serf__set_ver_prop()).
> 
> 
> ra_neon support:
> 
> * subversion/libsvn_ra_neon/ra_neon.h
>   (svn_ra_neon__do_proppatch):
>     Add PROP_OLD_VALUES parameter.
> 
> * subversion/libsvn_ra_neon/fetch.c
>   (svn_ra_neon__change_rev_prop):
>     Remove 'not implemented' sentinel.
>     Pass OLD_VALUE_P to svn_ra_neon__do_proppatch() via PROP_OLD_VALUES.
> 
> * subversion/libsvn_ra_neon/props.c
>   (append_setprop):
>     Grow OLD_VALUE_P parameter.  Use it to 
>     generate 'V:absent' and <V:old-value/> as appropriate.
>   (svn_ra_neon__do_proppatch):
>     Grow PROP_OLD_VALUES parameter, and use it.
>   
> 
> * subversion/libsvn_ra_neon/commit.c
>   (do_proppatch, apply_revprops):
>     Track signature change of svn_ra_neon__do_proppatch().
> 
> 
> Finally:
> 
> * BRANCH-README:  Mark this as done.
> 
> Modified:
>     subversion/branches/atomic-revprop/BRANCH-README
>     subversion/branches/atomic-revprop/notes/http-and-webdav/webdav-protocol
>     
> subversion/branches/atomic-revprop/subversion/include/private/svn_dav_protocol.h
>     subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/commit.c
>     subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/fetch.c
>     subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/props.c
>     subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/ra_neon.h
>     subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/commit.c
>     subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/property.c
>     subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/ra_serf.h
>     subversion/branches/atomic-revprop/subversion/mod_dav_svn/deadprops.c
> 
> Modified: subversion/branches/atomic-revprop/BRANCH-README
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/BRANCH-README?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/BRANCH-README (original)
> +++ subversion/branches/atomic-revprop/BRANCH-README Sat Aug  7 17:45:38 2010
> @@ -21,11 +21,7 @@ Planned work
>        achieved with older servers, and because of planned protocol 
> extensions)
>    - [DONE] ra_local: Trivial.
>    - [DONE] ra_svn: Add a 'change-rev-prop2' verb.
> -  - ra_dav
> -      Extend PROPPATCH syntax to provide the old value: add a <S:oldvalue/>
> -      tag inside the <${propname}> tag.
> -        Q: where to document this protocol extension?
> -        A: notes/http-and-webdav/webdav-protocol
> +  - [DONE] ra_dav: Extend PROPPATCH: see 
> notes/http-and-webdav/webdav-protocol
>    - [DONE] unit test
>        prop_tests.py 34: atomic_over_ra()
>    - TODO: extend it to test props set to the empty string and unset props
> 
> Modified: 
> subversion/branches/atomic-revprop/notes/http-and-webdav/webdav-protocol
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/notes/http-and-webdav/webdav-protocol?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/notes/http-and-webdav/webdav-protocol 
> (original)
> +++ subversion/branches/atomic-revprop/notes/http-and-webdav/webdav-protocol 
> Sat Aug  7 17:45:38 2010
> @@ -177,6 +177,30 @@ Response:
>    
>    ...svn-svndiff stream that can be passed to svn_txdelta_parse_svndiff...
>  
> +PROPPATCH
> +=========
> +
> +We extend PROPPATCH as follows.  To pass OLD_VALUE_P (as in
> +svn_ra_change_rev_prop2()), any propchange which is accompanied by a non-NULL
> +OLD_VALUE_P goes within the <D:set><D:prop> tag (and never within the
> +<D:remove><D:prop> tag --- even if it is a propdel).  Consequently, in
> +mod_dav_svn it would land in db_store() and not db_remove().
> +
> +The property tag (in the C: or S: namespace) always contains the propval in 
> its
> +cdata (potentially base64-encoded).  The extension is as follows:
> +
> +* The property tag grows a V:absent attribute, to represent that the property
> +  is being removed (i.e., a propdel routed to <D:set><D:prop>).
> +
> +* A <V:old-value> tag may be nested within the property tag.  The nested tag
> +  supports the same V:absent and V:encoding attributed as the parent 
> (property)
> +  tag.
> +
> +Historical note: we route propdels via <D:set>/db_store() because the mod_dav
> +API for db_remove() was insufficient.  See this thread:
> +http://mid.gmane.org/4c531cfb.2010...@collab.net
> +
> +
>  Custom REPORTs
>  ==============
>  
> 
> Modified: 
> subversion/branches/atomic-revprop/subversion/include/private/svn_dav_protocol.h
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/include/private/svn_dav_protocol.h?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- 
> subversion/branches/atomic-revprop/subversion/include/private/svn_dav_protocol.h
>  (original)
> +++ 
> subversion/branches/atomic-revprop/subversion/include/private/svn_dav_protocol.h
>  Sat Aug  7 17:45:38 2010
> @@ -46,6 +46,17 @@ extern "C" {
>  #define SVN_DAV__INCLUDE_DESCENDANTS "include-descendants"
>  #define SVN_DAV__VERSION_NAME "version-name"
>  
> +/** Names of XML elements attributes and tags for svn_ra_change_rev_prop2()'s
> +    extension of PROPPATCH.  */
> +#define SVN_DAV__OLD_VALUE "old-value"
> +#define SVN_DAV__OLD_VALUE__ABSENT "absent"
> +
> +/** Helper typedef for svn_ra_change_rev_prop2() implementation. */
> +typedef struct svn_dav__two_props_t {
> +  const svn_string_t *const *old_value_p;
> +  const svn_string_t *new_value;
> +} svn_dav__two_props_t;
> +
>  #ifdef __cplusplus
>  }
>  #endif /* __cplusplus */
> 
> Modified: 
> subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/commit.c
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/commit.c?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/commit.c 
> (original)
> +++ subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/commit.c Sat 
> Aug  7 17:45:38 2010
> @@ -616,7 +616,8 @@ static svn_error_t * do_proppatch(svn_ra
>      }
>  
>    return svn_ra_neon__do_proppatch(ras, url, rb->prop_changes,
> -                                   rb->prop_deletes, extra_headers, pool);
> +                                   rb->prop_deletes, NULL, extra_headers,
> +                                   pool);
>  }
>  
>  
> @@ -1417,7 +1418,7 @@ static svn_error_t * apply_revprops(comm
>      return err;
>  
>    return svn_ra_neon__do_proppatch(cc->ras, vcc_rsrc.wr_url, revprop_table,
> -                                   NULL, NULL, pool);
> +                                   NULL, NULL, NULL, pool);
>  }
>  
>  svn_error_t * svn_ra_neon__get_commit_editor(svn_ra_session_t *session,
> 
> Modified: subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/fetch.c
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/fetch.c?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/fetch.c 
> (original)
> +++ subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/fetch.c Sat 
> Aug  7 17:45:38 2010
> @@ -1131,6 +1131,7 @@ svn_error_t *svn_ra_neon__change_rev_pro
>    svn_error_t *err;
>    apr_hash_t *prop_changes = NULL;
>    apr_array_header_t *prop_deletes = NULL;
> +  apr_hash_t *prop_old_values = NULL;
>    static const ne_propname wanted_props[] =
>      {
>        { "DAV:", "auto-version" },
> @@ -1146,9 +1147,6 @@ svn_error_t *svn_ra_neon__change_rev_pro
>  
>        /* How did you get past the same check in svn_ra_change_rev_prop2()? */
>        SVN_ERR_ASSERT(capable);
> -
> -      /* ### server-side support hasn't been implemented yet */
> -      SVN__NOT_IMPLEMENTED();
>      }
>  
>    /* Main objective: do a PROPPATCH (allprops) on a baseline object */
> @@ -1180,19 +1178,33 @@ svn_error_t *svn_ra_neon__change_rev_pro
>           to attempt the PROPPATCH if the deltaV server is going to do
>           auto-versioning and create a new baseline! */
>  
> -  if (value)
> +  if (old_value_p)
>      {
> -      prop_changes = apr_hash_make(pool);
> -      apr_hash_set(prop_changes, name, APR_HASH_KEY_STRING, value);
> +      svn_dav__two_props_t *both_values;
> +
> +      both_values = apr_palloc(pool, sizeof(*both_values));
> +      both_values->old_value_p = old_value_p;
> +      both_values->new_value = value;
> +
> +      prop_old_values = apr_hash_make(pool);
> +      apr_hash_set(prop_old_values, name, APR_HASH_KEY_STRING, both_values);
>      }
>    else
>      {
> -      prop_deletes = apr_array_make(pool, 1, sizeof(const char *));
> -      APR_ARRAY_PUSH(prop_deletes, const char *) = name;
> +      if (value)
> +        {
> +          prop_changes = apr_hash_make(pool);
> +          apr_hash_set(prop_changes, name, APR_HASH_KEY_STRING, value);
> +        }
> +      else
> +        {
> +          prop_deletes = apr_array_make(pool, 1, sizeof(const char *));
> +          APR_ARRAY_PUSH(prop_deletes, const char *) = name;
> +        }
>      }
>  
>    err = svn_ra_neon__do_proppatch(ras, baseline->url, prop_changes,
> -                                  prop_deletes, NULL, pool);
> +                                  prop_deletes, prop_old_values, NULL, pool);
>    if (err)
>      return
>        svn_error_create
> 
> Modified: subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/props.c
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/props.c?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/props.c 
> (original)
> +++ subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/props.c Sat 
> Aug  7 17:45:38 2010
> @@ -1075,12 +1075,14 @@ get_encoding_and_cdata(const char **enco
>  static svn_error_t *
>  append_setprop(svn_stringbuf_t *body,
>                 const char *name,
> +               const svn_string_t *const *old_value_p,
>                 const svn_string_t *value,
>                 apr_pool_t *pool)
>  {
>    const char *encoding;
>    const char *xml_safe;
>    const char *xml_tag_name;
> +  const char *old_value_tag;
>  
>    /* Map property names to namespaces */
>  #define NSLEN (sizeof(SVN_PROP_PREFIX) - 1)
> @@ -1094,11 +1096,45 @@ append_setprop(svn_stringbuf_t *body,
>        xml_tag_name = apr_pstrcat(pool, "C:", name, NULL);
>      }
>  
> -  SVN_ERR(get_encoding_and_cdata(&encoding, &xml_safe, value, pool));
> +  if (old_value_p)
> +    {
> +      if (*old_value_p)
> +        {
> +          const char *encoding2;
> +          const char *xml_safe2;
> +          SVN_ERR(get_encoding_and_cdata(&encoding2, &xml_safe2,
> +                                         *old_value_p, pool));
> +          old_value_tag = apr_psprintf(pool, "<%s %s>%s</%s>",
> +                                       "V:" SVN_DAV__OLD_VALUE, encoding2,
> +                                       xml_safe2, "V:" SVN_DAV__OLD_VALUE);
> +        }
> +      else
> +        {
> +#define OLD_VALUE_ABSENT_TAG \
> +          "<" "V:" SVN_DAV__OLD_VALUE \
> +              " V:" SVN_DAV__OLD_VALUE__ABSENT "=\"1\" " \
> +          "/>"
> +          old_value_tag = OLD_VALUE_ABSENT_TAG;
> +        }
> +    }
> +  else
> +    {
> +      old_value_tag = "";
> +    }
> +
> +  if (old_value_p && !value)
> +    {
> +      encoding = "V:" SVN_DAV__OLD_VALUE__ABSENT "=\"1\"" ;
> +      xml_safe = "";
> +    }
> +  else
> +    {
> +      SVN_ERR(get_encoding_and_cdata(&encoding, &xml_safe, value, pool));
> +    }
>  
>    svn_stringbuf_appendcstr(body,
> -                           apr_psprintf(pool,"<%s %s>%s</%s>",
> -                                        xml_tag_name, encoding,
> +                           apr_psprintf(pool,"<%s %s>%s%s</%s>",
> +                                        xml_tag_name, encoding, 
> old_value_tag,
>                                          xml_safe, xml_tag_name));
>    return SVN_NO_ERROR;
>  }
> @@ -1109,6 +1145,7 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
>                            const char *url,
>                            apr_hash_t *prop_changes,
>                            const apr_array_header_t *prop_deletes,
> +                          apr_hash_t *prop_old_values,
>                            apr_hash_t *extra_headers,
>                            apr_pool_t *pool)
>  {
> @@ -1118,7 +1155,8 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
>  
>    /* just punt if there are no changes to make. */
>    if ((prop_changes == NULL || (! apr_hash_count(prop_changes)))
> -      && (prop_deletes == NULL || prop_deletes->nelts == 0))
> +      && (prop_deletes == NULL || prop_deletes->nelts == 0)
> +      && (prop_old_values == NULL || (! apr_hash_count(prop_old_values))))
>      return SVN_NO_ERROR;
>  
>    /* easier to roll our own PROPPATCH here than use ne_proppatch(), which
> @@ -1130,6 +1168,22 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
>       SVN_DAV_PROP_NS_CUSTOM "\" xmlns:S=\""
>       SVN_DAV_PROP_NS_SVN "\">" DEBUG_CR, pool);
>  
> +  /* Handle property changes/deletions with expected old values. */
> +  if (prop_old_values)
> +    {
> +      apr_hash_index_t *hi;
> +      svn_stringbuf_appendcstr(body, "<D:set><D:prop>");
> +      for (hi = apr_hash_first(pool, prop_old_values); hi; hi = 
> apr_hash_next(hi))
> +        {
> +          const char *name = svn__apr_hash_index_key(hi);
> +          svn_dav__two_props_t *both_values = svn__apr_hash_index_val(hi);
> +          svn_pool_clear(subpool);
> +          SVN_ERR(append_setprop(body, name, both_values->old_value_p,
> +                                 both_values->new_value, subpool));
> +        }
> +      svn_stringbuf_appendcstr(body, "</D:prop></D:set>");
> +    }
> +
>    /* Handle property changes. */
>    if (prop_changes)
>      {
> @@ -1141,7 +1195,7 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
>            void *val;
>            svn_pool_clear(subpool);
>            apr_hash_this(hi, &key, NULL, &val);
> -          SVN_ERR(append_setprop(body, key, val, subpool));
> +          SVN_ERR(append_setprop(body, key, NULL, val, subpool));
>          }
>        svn_stringbuf_appendcstr(body, "</D:prop></D:set>");
>      }
> @@ -1155,7 +1209,7 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
>          {
>            const char *name = APR_ARRAY_IDX(prop_deletes, n, const char *);
>            svn_pool_clear(subpool);
> -          SVN_ERR(append_setprop(body, name, NULL, subpool));
> +          SVN_ERR(append_setprop(body, name, NULL, NULL, subpool));
>          }
>        svn_stringbuf_appendcstr(body, "</D:prop></D:remove>");
>      }
> 
> Modified: 
> subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/ra_neon.h
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/ra_neon.h?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/ra_neon.h 
> (original)
> +++ subversion/branches/atomic-revprop/subversion/libsvn_ra_neon/ra_neon.h 
> Sat Aug  7 17:45:38 2010
> @@ -573,12 +573,15 @@ svn_error_t *svn_ra_neon__get_vcc(const 
>  /* Issue a PROPPATCH request on URL, transmitting PROP_CHANGES (a hash
>     of const svn_string_t * values keyed on Subversion user-visible
>     property names) and PROP_DELETES (an array of property names to
> -   delete).  Send any extra request headers in EXTRA_HEADERS. Use POOL
> -   for all allocations.  */
> +   delete). PROP_OLD_VALUES is a hash of Subversion user-visible property
> +   names mapped to svn_dav__two_props_t * values. Send any extra
> +   request headers in EXTRA_HEADERS. Use POOL for all allocations.
> + */
>  svn_error_t *svn_ra_neon__do_proppatch(svn_ra_neon__session_t *ras,
>                                         const char *url,
>                                         apr_hash_t *prop_changes,
>                                         const apr_array_header_t 
> *prop_deletes,
> +                                       apr_hash_t *prop_old_values,
>                                         apr_hash_t *extra_headers,
>                                         apr_pool_t *pool);
>  
> 
> Modified: 
> subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/commit.c
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/commit.c?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/commit.c 
> (original)
> +++ subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/commit.c Sat 
> Aug  7 17:45:38 2010
> @@ -108,6 +108,7 @@ typedef struct {
>    /* Changed and removed properties. */
>    apr_hash_t *changed_props;
>    apr_hash_t *removed_props;
> +  apr_hash_t *atomic_props;
>  
>    /* In HTTP v2, this is the file/directory version we think we're changing. 
> */
>    svn_revnum_t base_revision;
> @@ -639,16 +640,17 @@ checkout_file(file_context_t *file)
>  /* Helper function for proppatch_walker() below. */
>  static svn_error_t *
>  get_encoding_and_cdata(const char **encoding_p,
> -                       serf_bucket_t **cdata_bkt_p,
> +                       const svn_string_t **encoded_value_p,
>                         serf_bucket_alloc_t *alloc,
>                         const svn_string_t *value,
>                         apr_pool_t *pool)
>  {
> -  const char *encoding;
> -  const char *cdata;
> -  apr_size_t len; /* of cdata */
> -
> -  SVN_ERR_ASSERT(value);
> +  if (value == NULL)
> +    {
> +      *encoding_p = NULL;
> +      *encoded_value_p = NULL;
> +      return SVN_NO_ERROR;
> +    }
>  
>    /* If a property is XML-safe, XML-encode it.  Else, base64-encode
>       it. */
> @@ -656,23 +658,15 @@ get_encoding_and_cdata(const char **enco
>      {
>        svn_stringbuf_t *xml_esc = NULL;
>        svn_xml_escape_cdata_string(&xml_esc, value, pool);
> -      encoding = NULL;
> -      cdata = xml_esc->data;
> -      len = xml_esc->len;
> +      *encoding_p = NULL;
> +      *encoded_value_p = svn_string_create_from_buf(xml_esc, pool);
>      }
>    else
>      {
> -      const svn_string_t *base64ed = svn_base64_encode_string2(value, TRUE,
> -                                                               pool);
> -      encoding = "base64";
> -      cdata = base64ed->data;
> -      len = base64ed->len;
> +      *encoding_p = "base64";
> +      *encoded_value_p = svn_base64_encode_string2(value, TRUE, pool);
>      }
>  
> -  /* ENCODING, CDATA, and LEN are now set. */
> -
> -  *encoding_p = encoding;
> -  *cdata_bkt_p = SERF_BUCKET_SIMPLE_STRING_LEN(cdata, len, alloc);
>    return SVN_NO_ERROR;
>  }
>  
> @@ -680,13 +674,14 @@ static svn_error_t *
>  proppatch_walker(void *baton,
>                   const char *ns, apr_ssize_t ns_len,
>                   const char *name, apr_ssize_t name_len,
> -                 const svn_string_t *const *old_val_p, /* ### */
> +                 const svn_string_t *const *old_val_p,
>                   const svn_string_t *val,
>                   apr_pool_t *pool)
>  {
>    serf_bucket_t *body_bkt = baton;
>    serf_bucket_t *cdata_bkt;
>    serf_bucket_alloc_t *alloc;
> +  const svn_string_t *encoded_value;
>    const char *encoding;
>    char *prop_name;
>  
> @@ -700,12 +695,66 @@ proppatch_walker(void *baton,
>  
>    alloc = body_bkt->allocator;
>  
> -  SVN_ERR(get_encoding_and_cdata(&encoding, &cdata_bkt, alloc, val, pool));
> +  SVN_ERR(get_encoding_and_cdata(&encoding, &encoded_value, alloc, val, 
> pool));
> +  if (encoded_value)
> +    {
> +      cdata_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(encoded_value->data,
> +                                                encoded_value->len,
> +                                                alloc);
> +    }
> +  else
> +    {
> +      cdata_bkt = NULL;
> +    }
> +
> +  if (cdata_bkt)
> +    svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
> +                                      "V:encoding", encoding,
> +                                      NULL);
> +  else
> +    svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
> +                                      "V:" SVN_DAV__OLD_VALUE__ABSENT, "1",
> +                                      NULL);
>  
> -  svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
> -                                    "V:encoding", encoding,
> -                                    NULL);
> -  serf_bucket_aggregate_append(body_bkt, cdata_bkt);
> +  if (old_val_p)
> +    {
> +      const char *encoding2;
> +      const svn_string_t *encoded_value2;
> +      serf_bucket_t *cdata_bkt2;
> +
> +      SVN_ERR(get_encoding_and_cdata(&encoding2, &encoded_value2,
> +                                     alloc, *old_val_p, pool));
> +
> +      if (encoded_value2)
> +        {
> +          cdata_bkt2 = SERF_BUCKET_SIMPLE_STRING_LEN(encoded_value2->data,
> +                                                     encoded_value2->len,
> +                                                     alloc);
> +        }
> +      else
> +        {
> +          cdata_bkt2 = NULL;
> +        }
> +
> +      if (cdata_bkt2)
> +        svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
> +                                          SVN_DAV__OLD_VALUE,
> +                                          "V:encoding", encoding2,
> +                                          NULL);
> +      else
> +        svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
> +                                          SVN_DAV__OLD_VALUE,
> +                                          "V:" SVN_DAV__OLD_VALUE__ABSENT, 
> "1",
> +                                          NULL);
> +
> +      if (cdata_bkt2)
> +        serf_bucket_aggregate_append(body_bkt, cdata_bkt2);
> +
> +      svn_ra_serf__add_close_tag_buckets(body_bkt, alloc,
> +                                         SVN_DAV__OLD_VALUE);
> +    }
> +  if (cdata_bkt)
> +    serf_bucket_aggregate_append(body_bkt, cdata_bkt);
>    svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, prop_name);
>  
>    return SVN_NO_ERROR;
> @@ -766,6 +815,19 @@ create_proppatch_body(serf_bucket_t **bk
>                                      "xmlns:S", SVN_DAV_PROP_NS_SVN,
>                                      NULL);
>  
> +  if (ctx->atomic_props && apr_hash_count(ctx->atomic_props) > 0)
> +    {
> +      svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:set", NULL);
> +      svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:prop", NULL);
> +
> +      svn_ra_serf__walk_all_props(ctx->atomic_props, ctx->path,
> +                                  SVN_INVALID_REVNUM, TRUE,
> +                                  proppatch_walker, body_bkt, pool);
> +
> +      svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:prop");
> +      svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:set");
> +    }
> +
>    if (apr_hash_count(ctx->changed_props) > 0)
>      {
>        svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:set", NULL);
> @@ -2216,9 +2278,6 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
>  
>        /* How did you get past the same check in svn_ra_change_rev_prop2()? */
>        SVN_ERR_ASSERT(capable);
> -
> -      /* ### server-side support hasn't been implemented yet */
> -      SVN__NOT_IMPLEMENTED();
>      }
>  
>    commit = apr_pcalloc(pool, sizeof(*commit));
> @@ -2267,19 +2326,25 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
>    proppatch_ctx->path = proppatch_target;
>    proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
>    proppatch_ctx->removed_props = apr_hash_make(proppatch_ctx->pool);
> +  proppatch_ctx->atomic_props = apr_hash_make(proppatch_ctx->pool);
>    proppatch_ctx->base_revision = SVN_INVALID_REVNUM;
>  
> -  if (value)
> +  if (old_value_p)
> +    {
> +      svn_ra_serf__set_prop(proppatch_ctx->atomic_props, proppatch_ctx->path,
> +                            ns, name, old_value_p, value, 
> proppatch_ctx->pool);
> +    }
> +  else if (value)
>      {
>        svn_ra_serf__set_prop(proppatch_ctx->changed_props, 
> proppatch_ctx->path,
> -                            ns, name, NULL, value, proppatch_ctx->pool);
> +                            ns, name, old_value_p, value, 
> proppatch_ctx->pool);
>      }
>    else
>      {
>        value = svn_string_create("", proppatch_ctx->pool);
>  
>        svn_ra_serf__set_prop(proppatch_ctx->removed_props, 
> proppatch_ctx->path,
> -                            ns, name, NULL, value, proppatch_ctx->pool);
> +                            ns, name, old_value_p, value, 
> proppatch_ctx->pool);
>      }
>  
>    err = proppatch_resource(proppatch_ctx, commit, proppatch_ctx->pool);
> 
> Modified: 
> subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/property.c
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/property.c?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/property.c 
> (original)
> +++ subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/property.c 
> Sat Aug  7 17:45:38 2010
> @@ -209,7 +209,19 @@ svn_ra_serf__set_ver_prop(apr_hash_t *pr
>        apr_hash_set(path_props, ns, APR_HASH_KEY_STRING, ns_props);
>      }
>  
> -  apr_hash_set(ns_props, name, APR_HASH_KEY_STRING, val);
> +  if (old_value_p)
> +    {
> +      /* This must be PROPPATCH_CTX->ATOMIC_PROPS. */
> +      svn_dav__two_props_t *both_values;
> +      both_values = apr_palloc(pool, sizeof(*both_values));
> +      both_values->old_value_p = old_value_p;
> +      both_values->new_value = val;
> +      apr_hash_set(ns_props, name, APR_HASH_KEY_STRING, both_values);
> +    }
> +  else
> +    {
> +      apr_hash_set(ns_props, name, APR_HASH_KEY_STRING, val);
> +    }
>  }
>  
>  void
> @@ -784,8 +796,18 @@ svn_ra_serf__walk_all_props(apr_hash_t *
>  
>            apr_hash_this(name_hi, &prop_name, &prop_len, &prop_val);
>            /* use a subpool? */
> -          SVN_ERR(walker(baton, ns_name, ns_len, prop_name, prop_len,
> -                         NULL /* ### */, prop_val, pool));
> +          if (values_are_proppairs)
> +            {
> +              svn_dav__two_props_t *both_values = prop_val;
> +              SVN_ERR(walker(baton, ns_name, ns_len, prop_name, prop_len,
> +                             both_values->old_value_p, 
> both_values->new_value,
> +                             pool));
> +            }
> +          else
> +            {
> +              SVN_ERR(walker(baton, ns_name, ns_len, prop_name, prop_len,
> +                             NULL, prop_val, pool));
> +            }
>          }
>      }
>  
> 
> Modified: 
> subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/ra_serf.h
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/ra_serf.h?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/ra_serf.h 
> (original)
> +++ subversion/branches/atomic-revprop/subversion/libsvn_ra_serf/ra_serf.h 
> Sat Aug  7 17:45:38 2010
> @@ -961,8 +961,8 @@ svn_ra_serf__retrieve_props(apr_hash_t *
>  
>  /* Set PROPS for PATH at REV revision with a NS:NAME VAL.
>   * 
> - * ### If OLD_VALUE_P is not NULL, it must equal the current value of the
> - * ### revprop.
> + * If OLD_VALUE_P is not NULL, it must equal the current value of the
> + * revprop.
>   *
>   * The POOL governs allocation.
>   */
> @@ -984,7 +984,6 @@ typedef svn_error_t *
>                                   const svn_string_t *val,
>                                   apr_pool_t *pool);
>  
> -/* ### VALUES_ARE_PROPPAIRS is not implemented */
>  svn_error_t *
>  svn_ra_serf__walk_all_props(apr_hash_t *props,
>                              const char *name,
> 
> Modified: 
> subversion/branches/atomic-revprop/subversion/mod_dav_svn/deadprops.c
> URL: 
> http://svn.apache.org/viewvc/subversion/branches/atomic-revprop/subversion/mod_dav_svn/deadprops.c?rev=983269&r1=983268&r2=983269&view=diff
> ==============================================================================
> --- subversion/branches/atomic-revprop/subversion/mod_dav_svn/deadprops.c 
> (original)
> +++ subversion/branches/atomic-revprop/subversion/mod_dav_svn/deadprops.c Sat 
> Aug  7 17:45:38 2010
> @@ -161,7 +161,9 @@ get_value(dav_db *db, const dav_prop_nam
>  
>  
>  static dav_error *
> -save_value(dav_db *db, const dav_prop_name *name, const svn_string_t *value)
> +save_value(dav_db *db, const dav_prop_name *name,
> +           const svn_string_t *const *old_value_p,
> +           const svn_string_t *value)
>  {
>    const char *propname;
>    svn_error_t *serr;
> @@ -210,10 +212,11 @@ save_value(dav_db *db, const dav_prop_na
>          }
>        else
>          {
> -          serr = svn_repos_fs_change_rev_prop3(resource->info->repos->repos,
> +          serr = svn_repos_fs_change_rev_prop4(resource->info->repos->repos,
>                                                 resource->info->root.rev,
>                                                 
> resource->info->repos->username,
> -                                               propname, value, TRUE, TRUE,
> +                                               propname, old_value_p, value,
> +                                               TRUE, TRUE,
>                                                 db->authz_read_func,
>                                                 db->authz_read_baton,
>                                                 resource->pool);
> @@ -425,6 +428,7 @@ db_map_namespaces(dav_db *db,
>  
>  static dav_error *
>  decode_property_value(const svn_string_t **out_propval_p,
> +                      svn_boolean_t *absent,
>                        const svn_string_t *maybe_encoded_propval,
>                        const apr_xml_elem *elem,
>                        apr_pool_t *pool)
> @@ -432,6 +436,7 @@ decode_property_value(const svn_string_t
>    apr_xml_attr *attr = elem->attr;
>  
>    /* Default: no "encoding" attribute. */
> +  *absent = FALSE;
>    *out_propval_p = maybe_encoded_propval;
>  
>    /* Check for special encodings of the property value. */
> @@ -443,12 +448,21 @@ decode_property_value(const svn_string_t
>  
>            /* Handle known encodings here. */
>            if (enc_type && (strcmp(enc_type, "base64") == 0))
> -            *out_propval_p = svn_base64_decode_string(maybe_encoded_propval, 
> pool);
> +            *out_propval_p = svn_base64_decode_string(maybe_encoded_propval,
> +                                                      pool);
>            else
>              return dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0,
>                                   "Unknown property encoding");
>            break;
>          }
> +
> +      if (strcmp(attr->name, SVN_DAV__OLD_VALUE__ABSENT) == 0)
> +        {
> +          /* ### parse attr->value */
> +          *absent = TRUE;
> +          *out_propval_p = NULL;
> +        }
> +
>        /* Next attribute, please. */
>        attr = attr->next;
>      }
> @@ -462,7 +476,10 @@ db_store(dav_db *db,
>           const apr_xml_elem *elem,
>           dav_namespace_map *mapping)
>  {
> +  const svn_string_t *const *old_propval_p;
> +  const svn_string_t *old_propval;
>    const svn_string_t *propval;
> +  svn_boolean_t absent;
>    apr_pool_t *pool = db->p;
>    dav_error *derr;
>  
> @@ -475,11 +492,41 @@ db_store(dav_db *db,
>    propval = svn_string_create
>      (dav_xml_get_cdata(elem, pool, 0 /* strip_white */), pool);
>  
> -  derr = decode_property_value(&propval, propval, elem, pool);
> +  derr = decode_property_value(&propval, &absent, propval, elem, pool);
>    if (derr)
>      return derr;
>  
> -  return save_value(db, name, propval);
> +  if (absent && ! elem->first_child)
> +    /* ### better error check */
> +    return dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0,
> +                         apr_psprintf(pool, 
> +                                      "'%s' cannot be specified on the value 
> "
> +                                      "without specifying an expectation",
> +                                      SVN_DAV__OLD_VALUE__ABSENT));
> +
> +  /* ### namespace check? */
> +  if (elem->first_child && !strcmp(elem->first_child->name, 
> SVN_DAV__OLD_VALUE))
> +    {
> +      const char *propname;
> +
> +      get_repos_propname(db, name, &propname);
> +
> +      /* Parse OLD_PROPVAL. */
> +      old_propval = svn_string_create(dav_xml_get_cdata(elem->first_child, 
> pool,
> +                                                        0 /* strip_white */),
> +                                      pool);
> +      derr = decode_property_value(&old_propval, &absent,
> +                                   old_propval, elem->first_child, pool);
> +      if (derr)
> +        return derr;
> +
> +      old_propval_p = (const svn_string_t *const *) &old_propval;
> +    }
> +  else
> +    old_propval_p = NULL;
> +
> +
> +  return save_value(db, name, old_propval_p, propval);
>  }
>  
>  
> 
> 

(Why?  It's the RA layer I'm least familiar with, it required the least
straightforward implementation (both client- and server- side), and after
spending quite some time inside a 700-line patch I no longer have the
perspective or patience to review all the small details carefully again.)

Reply via email to