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

Re: thread safe

From: Branko Čibej <brane_at_wandisco.com>
Date: Wed, 05 Sep 2012 01:14:33 +0200

On 04.09.2012 22:24, Stefan Küng wrote:
> Attached is my first draft of the new svn_config_dup() API.
>
> * it does not return an svn_error_t but the duplicate hash directly.
> The only API call that could return an error is svn_config_create()
> but that API also returns SVN_NO_ERROR unconditionally (for now at
> least).
> * no error checking is done for now, will add some checks for failed
> memory allocations later.
> * hash keys are duplicated as well (allocated in the passed pool)
>
> Please have a look at this. I think it's correct, at least my first
> tests show that it works and solves my problem in TSVN with multiple
> threads as well.
>
> be back tomorrow...

Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h (revision 1380737)
+++ subversion/include/svn_config.h (working copy)
@@ -626,6 +626,16 @@
                                 const char *fname,
                                 apr_pool_t *pool);
 
+/** Return a deep copy of the config hash.
+ * @note use this function instead of repeated calls
+ * to svn_config_get_config to avoid reading the config file
+ * over and over.
+ *
+ * @since New in 1.8.
+ */
+apr_hash_t *
+svn_config_dup(apr_hash_t * config, apr_pool_t * pool);

As I said, the return value must be a svn_config_t*.
More comments below (I'll ignore coding style).

 
Index: subversion/libsvn_subr/config.c
===================================================================
--- subversion/libsvn_subr/config.c (revision 1380737)
+++ subversion/libsvn_subr/config.c (working copy)
@@ -1011,3 +1011,88 @@
   sec = apr_hash_get(cfg->sections, cfg->tmp_key->data, APR_HASH_KEY_STRING);
   return sec != NULL;
 }
+
+
+apr_hash_t *
+svn_config_dup(apr_hash_t * config, apr_pool_t * pool)
+{
+ apr_hash_t * rethash;
+ apr_hash_index_t * cidx;
+ apr_hash_index_t * sectidx;
+ apr_hash_index_t * optidx;
+
+ rethash = apr_hash_make(pool);
+ for (cidx = apr_hash_first(pool, config);
+ cidx != NULL;
+ cidx = apr_hash_next(cidx))
+ {
+ const void *ckey = NULL;
+ void *cval = NULL;
+ apr_ssize_t ckeyLength = 0;
+ svn_config_t * c;
+ svn_config_t * newconfig = NULL;
+
+ svn_config_create(&newconfig, FALSE, pool);

Um, what? You return a hash of svn_config_t? None of the
svn_config_* APIs use such a structure.

+
+ apr_hash_this(cidx, &ckey, &ckeyLength, &cval);
+ c = cval;
+
+ newconfig->sections = apr_hash_make(pool);
+ newconfig->pool = pool;
+ newconfig->x_pool = svn_pool_create(pool);
+ newconfig->x_values = c->x_values;
+ newconfig->tmp_key = svn_stringbuf_dup(c->tmp_key, pool);
+ newconfig->tmp_value = svn_stringbuf_dup(c->tmp_value, pool);
+ newconfig->section_names_case_sensitive = c->section_names_case_sensitive;

svn_config_create already creates the hash table, populates
pool and x_pool, and creates the TEMPORARY stringbufs.
In other words, all you have to do is copy x_values and
section_names_case_sensitive, everything else is already done.

+
+ for (sectidx = apr_hash_first(pool, c->sections);
+ sectidx != NULL;
+ sectidx = apr_hash_next(sectidx))
+ {
+ const void *sectkey = NULL;
+ void *sectval = NULL;
+ apr_ssize_t sectkeyLength = 0;
+ cfg_section_t * sect;
+ cfg_section_t * newsec;
+
+ apr_hash_this(sectidx, &sectkey, &sectkeyLength, &sectval);
+ sect = sectval;
+
+ newsec = apr_palloc(pool, sizeof(*newsec));
+ newsec->name = apr_pstrdup(pool, sect->name);
+ newsec->hash_key = apr_pstrdup(pool, sect->hash_key);
+ newsec->options = apr_hash_make(pool);

Suggest you factor this part out of svn_config_set instead
of duplicating the logic here.

+ for (optidx = apr_hash_first(pool, sect->options);
+ optidx != NULL;
+ optidx = apr_hash_next(optidx))
+ {
+ const void *optkey = NULL;
+ void *optval = NULL;
+ apr_ssize_t optkeyLength = 0;
+ cfg_option_t * opt;
+ cfg_option_t * newopt;
+
+ apr_hash_this(optidx, &optkey, &optkeyLength, &optval);
+ opt = optval;
+
+ newopt = apr_palloc(pool, sizeof(*newopt));
+ newopt->name = apr_pstrdup(pool, opt->name);
+ newopt->hash_key = apr_pstrdup(pool, opt->hash_key);
+ newopt->value = apr_pstrdup(pool, opt->value);
+ newopt->x_value = apr_pstrdup(pool, opt->x_value);
+ newopt->expanded = opt->expanded;
+ apr_hash_set(newsec->options,
+ apr_pstrdup(pool, (const char*)optkey),
+ optkeyLength, newopt);

And here; svn_config_set already has code to create option
and section records, it only needs to be factored out.

+ }
+ apr_hash_set(newconfig->sections,
+ apr_pstrdup(pool, (const char*)sectkey),
+ sectkeyLength, newsec);
+ }
+ apr_hash_set(rethash,
+ apr_pstrdup(pool, (const char*)ckey),
+ ckeyLength, newconfig);
+ }
+
+ return rethash;
+}

So except for the rethash which I frankly don't understand at all, the
rest looks like a good start. Basically just strip away the outer loop
and rely on (refactored) existing code instead of copying it around, and
you're done.

-- Brane

-- 
Certified & Supported Apache Subversion Downloads:
http://www.wandisco.com/subversion/download
Received on 2012-09-05 01:15:10 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.