Blair Zajac wrote on Wed, Dec 22, 2010 at 22:26:15 -0800: > On 12/22/10 4:38 PM, Daniel Shahaf wrote: >> Blair Zajac wrote on Wed, Dec 22, 2010 at 13:22:11 -0800: >>> On 12/22/10 10:56 AM, Daniel Shahaf wrote: >>>> Blair Zajac wrote on Wed, Dec 22, 2010 at 10:45:12 -0800: >>>>> It seems the best thing is to have svn_error_purge_tracing() return a >>>>> brand new chain that shares no links with the original chain, and then >>>>> both need to be freed. >>>>> >>>> >>>> That makes sense; if we'll work with complete chains, there's a smaller >>>> chance of more edge-case bugs. >>> >>> Thinking on this a little more, since most people won't use debugging, >>> it'll be wasteful to have svn_error_purge_tracing() make a duplicate >>> chain that will have no tracing errors in it. >>> >> >> IOW, duplicating in maintainer mode forces duplicating in non-maintainer >> mode too, making the common case costlier. True. >> >> However, we could have a macro that causes the dup() operation to only >> be done in maintainer mode: >> >> void svn_error_purge_tracing_shell(svn_error_t **err_p) >> { >> #ifdef SVN_ERR__TRACING >> svn_error_t *err = svn_error_purge_tracing(*err_p); >> svn_error_clear(*err_p); >> *err_p = err; >> #endif /* SVN_ERR__TRACING */ >> } >> >>> So maybe we should have svn_error_purge_tracing() be related to the input >>> chain and share what it can, but not be an error chain one should use >>> svn_error_clear() on. >>> >> >> IOW, change its promise such that it's the passed-in error, not the >> returned one, which should be cleared? And have it leave the passed-in >> chain untouched? >> >> It makes sense on a first scan, but at 3am it's too late for a full +1. > > I've attached a patch to review. It fixes both svn_error_purge_tracing() > and the the behavior of svn_repos__post_commit_error_str(). >
Review below. >>>>>> For example, shouldn't the following code trigger err_abort() on the >>>>>> outer (wrapper) link? >>>>>> >>>>>> svn_error_t *in = svn_error_create(...); >>>>>> svn_error_t *original = svn_error_quick_wrap(in, >>>>>> SVN_ERR__TRACED); >>>>>> svn_error_t *purged = svn_error_purge_tracing(original); >>>>>> svn_error_clear(purged); >>>>>> exit(0); >>>>>> >>>>>> Am I making sense? >>>>> >>>>> I don't think so, because if SVN_DEBUG is defined, then it finds the >>>>> error at the end of the chain, which in this example is a non-tracing >>>>> error, and it'll properly remove the err_abort. >>>>> >>>> >>>> You're right, I'll modify my example to this: >>>> >>>> SVN_ERR__TRACED /* start of chain */ >>>> SVN_ERR__TRACED >>>> "non-tracing link" /* end of chain */ >>>> >>>> In this case, the middle link would be lost. Right? >>> >>> Both SVN_ERR__TRACED would be lost by svn_error_purge_tracing(), right? >>> >> >> Won't the inner while() loop would skip over them? > > Yes, I think it would. We should probably write a unit test for > svn_error_purge_tracing(). > > Blair I've made a quick sketch --- looks good? (I'll fix the "###" comment before committing.) [[[ Index: subversion/tests/libsvn_subr/error-test.c =================================================================== --- subversion/tests/libsvn_subr/error-test.c (revision 1052215) +++ subversion/tests/libsvn_subr/error-test.c (working copy) @@ -78,6 +78,34 @@ test_error_root_cause(apr_pool_t *pool) return SVN_NO_ERROR; } +/* ### just make ../../libsvn_subr/error.c:is_tracing_link() semi-public */ +#ifdef SVN_ERR__TRACING +#define is_tracing_link(err) \ + ((err) && (err)->message && !strcmp((err)->message, SVN_ERR__TRACED)) +#else +#define is_tracing_link(err) FALSE +#endif + +static svn_error_t * +test_error_purge_tracing(apr_pool_t *pool) +{ + svn_error_t *err, *err2, *child; + + err = svn_error_quick_wrap(svn_error_create(SVN_ERR_BASE, NULL, "root error"), + "wrapped"); + err = svn_error_quick_wrap(svn_error_create(SVN_ERR_BASE, err, "other error"), + "re-wrapped"); + + err2 = svn_error_purge_tracing(err); + for (child = err2; child; child = child->child) + if (is_tracing_link(child)) + return svn_error_create(SVN_ERR_TEST_FAILED, err, + "Tracing link found after purging the following chain:"); + + svn_error_clear(err); + return SVN_NO_ERROR; +} + /* The test table. */ @@ -86,5 +114,7 @@ struct svn_test_descriptor_t test_funcs[] = SVN_TEST_NULL, SVN_TEST_PASS2(test_error_root_cause, "test svn_error_root_cause"), + SVN_TEST_PASS2(test_error_purge_tracing, + "test svn_error_purge_tracing"), SVN_TEST_NULL }; ]]] > Index: subversion/libsvn_subr/error.c > =================================================================== > --- subversion/libsvn_subr/error.c (revision 1052167) > +++ subversion/libsvn_subr/error.c (working copy) > @@ -349,39 +349,47 @@ > svn_error_purge_tracing(svn_error_t *err) > { > #ifdef SVN_ERR__TRACING ... > return new_err; > #else /* SVN_ERR__TRACING */ > return err; +1 > Index: subversion/mod_dav_svn/deadprops.c > =================================================================== > --- subversion/mod_dav_svn/deadprops.c (revision 1052167) > +++ subversion/mod_dav_svn/deadprops.c (working copy) > @@ -222,18 +222,22 @@ > + purged_serr->message = apr_xml_quote_string > + (purged_serr->pool, Our current policy is to have the '(' on the same line as the function name. > Index: subversion/mod_dav_svn/version.c > =================================================================== > --- subversion/mod_dav_svn/version.c (revision 1052167) > +++ subversion/mod_dav_svn/version.c (working copy) > @@ -922,16 +922,16 @@ > { > if (serr) > { > - const char *post_commit_err; > - apr_err = serr->apr_err; > - post_commit_err = svn_repos__post_commit_error_str > - (serr, resource->pool); > - serr = SVN_NO_ERROR; > - ap_log_perror(APLOG_MARK, APLOG_ERR, apr_err, resource->pool, > + const char *post_commit_err = svn_repos__post_commit_error_str > + (serr, resource->pool); > + ap_log_perror(APLOG_MARK, APLOG_ERR, serr->apr_err, > + resource->pool, The rest looks good. (I am assuming --- didn't check --- that you updated all callers.)