Author: stefan2
Date: Sun Apr  8 10:03:03 2012
New Revision: 1310967

URL: http://svn.apache.org/viewvc?rev=1310967&view=rev
Log:
On the reprop-cache branch: Introduce namespaces to simplify writing test code
and fix a number of issues found during testing.

* subversion/include/private/svn_named_atomic.h
  (svn_atomic_namespace__t): declare new type
  (SVN_NAMED_ATOMIC__MAX_NAME_LENGTH): add docstring
  (svn_atomic_namespace__create): declare new function
  (svn_named_atomic__get): add namespace as optional parameter
* subversion/libsvn_subr/svn_named_atomic.c
   update / fix commentary
  (DEFAULT_NAMESPACE_NAME): new constant
  (MUTEX_NAME): shorten
  (SHM_NAME): drop
  (SHM_NAME_SUFFIX): replaces SHM_NAME
  (synched_write): fix GCC intrinsics code
  (svn_atomic_namespace__t): define new type
  (default_namespace): new global variable
  (mutex, mutex_initialized, init_mutex): global mutex is now truely global
  (lock, unlock, SYNCHRONIZE): adapt to having a global mutex
  (initialize): adapt to init any namespace
  (validate): only very basic checks are still possible
  (svn_atomic_namespace__create): implement new API function
  (svn_named_atomic__get): adapt to API change
* subversion/libsvn_fs_fs/fs_fs.c
  (ensure_revprop_generation, ensure_revprop_timeout): adapt API callers

Modified:
    
subversion/branches/revprop-cache/subversion/include/private/svn_named_atomic.h
    subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c
    subversion/branches/revprop-cache/subversion/libsvn_subr/svn_named_atomic.c

Modified: 
subversion/branches/revprop-cache/subversion/include/private/svn_named_atomic.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/revprop-cache/subversion/include/private/svn_named_atomic.h?rev=1310967&r1=1310966&r2=1310967&view=diff
==============================================================================
--- 
subversion/branches/revprop-cache/subversion/include/private/svn_named_atomic.h 
(original)
+++ 
subversion/branches/revprop-cache/subversion/include/private/svn_named_atomic.h 
Sun Apr  8 10:03:03 2012
@@ -21,7 +21,12 @@
  * @endcopyright
  *
  * @file svn_named_atomics.h
- * @brief Strutures and functions for machine-wide named atomics
+ * @brief Structures and functions for machine-wide named atomics.
+ *        These atomics store 64 bit signed integer values and provide
+ *        a number of basic operations on them. Instead of an address,
+ *        these atomics are identified by strings / names.  We also support
+ *        namespaces - mainly to separate debug from production data.
+ *        SVN-internal functionality uses the default namespace (see below).
  */
 
 #ifndef SVN_NAMED_ATOMICS_H
@@ -33,30 +38,57 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/** An opaque structure that represents a namespace, i.e. a container
+ * for named atomics.
+ */
+typedef struct svn_atomic_namespace__t svn_atomic_namespace__t;
+
 /** An opaque structure that represents a named, system-wide visible
  * 64 bit integer with atomic access routines.
  */
 typedef struct svn_named_atomic__t svn_named_atomic__t;
 
+/** Maximum length of the name of any atomic (excluding the terminal NUL).
+ */
 #define SVN_NAMED_ATOMIC__MAX_NAME_LENGTH 30
 
-/** Find the atomic with the specified @a name and return it in @a *atomic.
- * If no object with that name can be found, the behavior depends on 
- * @a auto_create. If it is @c FALSE, @a *atomic will be set to @c NULL.
- * Otherwise, a new atomic will be created, its value set to 0 and the
- * access structure be returned in @a *atomic.
+/** Create a namespace (i.e. access object) with the given @a name and
+ * return it in @a *anamespace.  If @a name is @c NULL, return the name
+ * of the default namespace will be used.
+ *
+ * Multiple access objects with the same name may be created.  They access
+ * the same shared memory region but have independent lifetimes.
+ *
+ * The access object will be allocated in @a pool and atomics gotten
+ * from this object will become invalid when the pool is being cleaned.
+ */
+svn_error_t *
+svn_atomic_namespace__create(svn_atomic_namespace__t **anamespace,
+                             const char *name,
+                             apr_pool_t *pool);
+
+/** Find the atomic with the specified @a name in @a anamespace and return
+ * it in @a *atomic.  If @a namespace is @c NULL, the default namespace
+ * will be used.  If no object with that name can be found, the behavior
+ * depends on @a auto_create.  If it is @c FALSE, @a *atomic will be set
+ * to @c NULL. Otherwise, a new atomic will be created, its value set to 0
+ * and the access structure be returned in @a *atomic.
  * 
- * Note that @a name must be short and should not exceeed 
- * @ref SVN_NAMED_ATOMIC__MAX_NAME_LENGTH characters. The actual limit is
- * implementation-dependent and may change in the future. This function
- * will return an error if the specified name is longer than supported.
+ * Note that @a name must not exceed @ref SVN_NAMED_ATOMIC__MAX_NAME_LENGTH
+ * characters and an error will be returned if the specified name is longer
+ * than supported.
+ *
+ * If necessary, this function will automatically initialize the default
+ * shared memory region. Therefore, this may fail with a variety of errors.
  *
- * This function will automatically initialize the shared memory region,
- * if that hadn't been attempted before. Therefore, this may fail with
- * a variety of errors.
+ * Please note that the lifetime of the atomic is bound to the lifetime
+ * of the @a anamespace object, i.e. the pool the latter was created in.
+ * The default namespace (for @c anamespace=NULL) remains valid until APR
+ * gets cleaned up.
  */
 svn_error_t *
 svn_named_atomic__get(svn_named_atomic__t **atomic,
+                      svn_atomic_namespace__t *anamespace,
                       const char *name,
                       svn_boolean_t auto_create);
 

Modified: subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c?rev=1310967&r1=1310966&r2=1310967&view=diff
==============================================================================
--- subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c Sun Apr  
8 10:03:03 2012
@@ -2719,6 +2719,7 @@ ensure_revprop_generation(svn_fs_t *fs)
   
   return ffd->revprop_generation == NULL
     ? svn_named_atomic__get(&ffd->revprop_generation,
+                            NULL,
                             ATOMIC_REVPROP_GENERATION,
                             TRUE)
     : SVN_NO_ERROR;
@@ -2732,6 +2733,7 @@ ensure_revprop_timeout(svn_fs_t *fs)
   
   return ffd->revprop_timeout == NULL
     ? svn_named_atomic__get(&ffd->revprop_timeout,
+                            NULL,
                             ATOMIC_REVPROP_TIMEOUT,
                             TRUE)
     : SVN_NO_ERROR;

Modified: 
subversion/branches/revprop-cache/subversion/libsvn_subr/svn_named_atomic.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/revprop-cache/subversion/libsvn_subr/svn_named_atomic.c?rev=1310967&r1=1310966&r2=1310967&view=diff
==============================================================================
--- subversion/branches/revprop-cache/subversion/libsvn_subr/svn_named_atomic.c 
(original)
+++ subversion/branches/revprop-cache/subversion/libsvn_subr/svn_named_atomic.c 
Sun Apr  8 10:03:03 2012
@@ -39,7 +39,7 @@
  * an short header followed by a fixed-capacity array of named atomics. The
  * number of entries currently in use is stored in the header part.
  * 
- * Finding / creating the SHM object as well as additing new array entries
+ * Finding / creating the SHM object as well as adding new array entries
  * is being guarded by an APR global mutex.
  * 
  * The array is append-only.  Once a process mapped the block into its
@@ -66,18 +66,26 @@
  */
 #define CACHE_LINE_LENGTH 64
 
-/* We need 8 bytes for the actual value and the remainer is used to
+/* We need 8 bytes for the actual value and the remainder is used to
  * store the NUL-terminated name.
+ *
+ * Must not be smaller than SVN_NAMED_ATOMIC__MAX_NAME_LENGTH.
  */
 #define MAX_NAME_LENGTH (CACHE_LINE_LENGTH - sizeof(apr_int64_t) - 1)
 
-/* Name of the global mutex that we will use.
+/* Name of the default namespace.
  */
-#define MUTEX_NAME "SvnNamedAtomicsMutex"
+#define DEFAULT_NAMESPACE_NAME "SvnNamedAtomics"
 
-/* Name of the shared memory file that we will use.
+/* Name of the mutex used for global serialization - where global
+ * serialization is necessary.
  */
-#define SHM_NAME "SvnNamedAtomicsShm"
+#define MUTEX_NAME "SvnAtomicsMutex"
+
+/* Particle that will be appended to the namespace name to form the
+ * name of the shared memory file that backs that namespace.
+ */
+#define SHM_NAME_SUFFIX "Shm"
 
 /* Platform-dependent implementations of our basic atomic operations.
  * SYNCHRONIZE(op) will ensure that the OP gets executed atomically.
@@ -104,7 +112,7 @@
 /* GCC provides atomic intrinsics for most common CPU types
  */
 #define synched_read(value) value
-#define synched_write(mem, value) (*mem = value)
+#define synched_write(mem, value) __sync_lock_test_and_set(mem, value)
 #define synched_add(mem, delta) __sync_add_and_fetch(mem, delta)
 #define synched_cmpxchg(mem, value, comperand) \
   __sync_val_compare_and_swap(mem, comperand, value)
@@ -149,9 +157,9 @@ synched_cmpxchg(volatile apr_int64_t *me
 }
 
 #define SYNCHRONIZE(op)\
-  SVN_ERR(lock(&access));\
+  SVN_ERR(lock());\
   op;\
-  SVN_ERR(unlock(&access, SVN_NO_ERROR));
+  SVN_ERR(unlock(SVN_NO_ERROR));
 
 #endif
 
@@ -166,7 +174,7 @@ struct svn_named_atomic__t
 /* Content of our shared memory buffer.  COUNT is the number
  * of used entries in ATOMICS.  Insertion is append-only.
  * PADDING is used to align the header information with the
- * atomics to create a favourable data alignment.
+ * atomics to create a favorable data alignment.
  */
 struct shared_data_t
 {
@@ -180,40 +188,63 @@ struct shared_data_t
  * information necessary to initialize and access the shared
  * memory.
  */
-struct shared_mem_access_t
+struct svn_atomic_namespace__t
 {
   /* Init flag used by svn_atomic__init_once */
   svn_atomic_t initialized;
 
+  /* Name of the namespace.
+   * Will only be used to during creation. */
+  const char *name;
+
   /* Pointer to the shared data mapped into our process */
   struct shared_data_t *data;
 
-  /* Named mutex to control access to the shared mem */
-  apr_global_mutex_t *mutex;
-
   /* Named APR shared memory object */
   apr_shm_t *shared_mem;
 
   /* Last time we checked, this was the number of used
    * (i.e. fully initialized) items.  I.e. we can read
-   * their names without futher sync. */
+   * their names without further sync. */
   volatile svn_atomic_t min_used;
 
   /* Pool for APR objects */
   apr_pool_t *pool;
 };
 
-/* Global / singleton instance to access our shared memory.
+/* Global / singleton instance to access our default shared memory.
  */
-static struct shared_mem_access_t access = {FALSE};
+static struct svn_atomic_namespace__t default_namespace = {FALSE, NULL};
 
-/* Utility that aquires a lock for ACCESS->MUTEX and converts
- * error types when necessary.
+/* Named global mutex to control access to the shared memory structures.
+ */
+static apr_global_mutex_t *mutex = NULL;
+
+/* Initialization flag for the above used by svn_atomic__init_once.
+ */
+static volatile svn_atomic_t mutex_initialized = FALSE;
+
+/* Mutex initialization called via svn_atomic__init_once.
  */
 static svn_error_t *
-lock(struct shared_mem_access_t *access)
+init_mutex(void *baton, apr_pool_t *_pool)
 {
-  apr_status_t apr_err = apr_global_mutex_lock(access->mutex);
+  apr_pool_t *pool = svn_pool_create(NULL);
+  apr_status_t apr_err = apr_global_mutex_create(&mutex,
+                                                 MUTEX_NAME,
+                                                 APR_LOCK_DEFAULT,
+                                                 pool);
+  return apr_err
+    ? svn_error_wrap_apr(apr_err, _("Can't create mutex for named atomics"))
+    : SVN_NO_ERROR;
+}
+
+/* Utility that acquires our global mutex and converts error types.
+ */
+static svn_error_t *
+lock()
+{
+  apr_status_t apr_err = apr_global_mutex_lock(mutex);
   if (apr_err)
     return svn_error_wrap_apr(apr_err,
               _("Can't lock mutex for named atomics"));
@@ -221,15 +252,14 @@ lock(struct shared_mem_access_t *access)
   return SVN_NO_ERROR;
 }
 
-/* Utility that releases a lock for ACCESS->MUTEX and converts
- * error types when necessary.  If the unlock succeeds, OUTER_ERR
- * will be returned.  If it fails, the unlock error will only be
- * returned if the OUTER_ERR is NULL and ignored, otherwise.
+/* Utility that releases the lock previously acquired via lock().  If the
+ * unlock succeeds and OUTER_ERR is not NULL, OUTER_ERR will be returned.
+ * Otherwise, return the result of the unlock operation.
  */
 static svn_error_t *
-unlock(struct shared_mem_access_t *access, svn_error_t * outer_err)
+unlock(svn_error_t * outer_err)
 {
-  apr_status_t apr_err = apr_global_mutex_unlock(access->mutex);
+  apr_status_t apr_err = apr_global_mutex_unlock(mutex);
   if (apr_err && !outer_err)
     return svn_error_wrap_apr(apr_err,
               _("Can't unlock mutex for named atomics"));
@@ -237,71 +267,82 @@ unlock(struct shared_mem_access_t *acces
   return outer_err;
 }
 
-/* Initialize the shared_mem_access_t given as BATON.  POOL is unused.
+/* Initialize the shared_mem_access_t given as BATON.
+ * POOL will be used by the namespace for allocations and may be NULL
+ * (in which case a new root pool will be created).
  */
 static svn_error_t *
 initialize(void *baton, apr_pool_t *pool)
 {
   apr_status_t apr_err;
   const char *temp_dir, *shm_name;
-  struct shared_mem_access_t *access = baton;
+  struct svn_atomic_namespace__t *anamespace = baton;
 
-  /* Since this function will be called through svn_atomic__init_once,
-   * providing a new root pool each time this is called, is not feasible.
-   * -> Create our own root pool here.
+  SVN_ERR(svn_atomic__init_once(&mutex_initialized,
+                                init_mutex,
+                                NULL,
+                                NULL));
+
+  /* The namespace will use its own (sub-)pool for all allocations.
    */
-  access->pool = svn_pool_create(NULL);
+  anamespace->pool = svn_pool_create(pool);
 
-  /* construct the name of the SHM file */
-  SVN_ERR(svn_io_temp_dir(&temp_dir, access->pool));
-  shm_name = svn_dirent_join(temp_dir, SHM_NAME, access->pool);
+  /* Use the default namespace if none has been given.
+   * All namespaces sharing the same name are equivalent and see
+   * the same data, even within the same process.
+   */
+  if (anamespace->name == NULL)
+    anamespace->name = DEFAULT_NAMESPACE_NAME;
 
-  /* Next, we must ensure that no-one else tries to initialize the shared
-   * memory while we are about to do the same.
+  /* Construct the name of the SHM file.  If the namespace is not
+   * absolute, we put it into the temp dir.
    */
-  apr_err = apr_global_mutex_create(&access->mutex,
-                                    MUTEX_NAME,
-                                    APR_LOCK_DEFAULT,
-                                    access->pool);
-  if (apr_err)
-    return svn_error_wrap_apr(apr_err,
-              _("Can't create global mutex for named atomics"));
+  shm_name = anamespace->name;
+  if (!svn_dirent_is_absolute(shm_name))
+    {
+      SVN_ERR(svn_io_temp_dir(&temp_dir, anamespace->pool));
+      shm_name = svn_dirent_join(temp_dir, shm_name, anamespace->pool);
+    }
+
+  shm_name = apr_pstrcat(anamespace->pool, shm_name, SHM_NAME_SUFFIX, NULL);
 
-  SVN_ERR(lock(access));
+  /* Prevent concurrent initialization.
+   */
+  SVN_ERR(lock());
 
   /* First, look for an existing shared memory object.  If it doesn't
    * exist, create one.
    */
-  apr_err = apr_shm_attach(&access->shared_mem, shm_name, access->pool);
+  apr_err = apr_shm_attach(&anamespace->shared_mem, shm_name, 
anamespace->pool);
   if (apr_err)
     {
-      apr_err = apr_shm_create(&access->shared_mem,
-                               sizeof(*access->data),
+      apr_err = apr_shm_create(&anamespace->shared_mem,
+                               sizeof(*anamespace->data),
                                shm_name,
-                               access->pool);
+                               anamespace->pool);
       if (apr_err)
-        return unlock(access, svn_error_wrap_apr(apr_err,
+        return unlock(svn_error_wrap_apr(apr_err,
                   _("Can't get shared memory for named atomics")));
 
-      access->data = apr_shm_baseaddr_get(access->shared_mem);
+      anamespace->data = apr_shm_baseaddr_get(anamespace->shared_mem);
 
       /* Zero all counters, values and names.
        */
-      memset(access->data, 0, sizeof(*access->data));
+      memset(anamespace->data, 0, sizeof(*anamespace->data));
     }
   else
-    access->data = apr_shm_baseaddr_get(access->shared_mem);
+    anamespace->data = apr_shm_baseaddr_get(anamespace->shared_mem);
 
   /* Cache the number of existing, complete entries.  There can't be incomplete
-   * onces from other processe because we hold the mutex.  Our process may also
+   * onces from other processes because we hold the mutex.  Our process may 
also
    * not access this information since we are being called from within
    * svn_atomic__init_once.
    */
-  access->min_used = access->data->count;
+  anamespace->min_used = anamespace->data->count;
 
   /* Unlock to allow other processes may access the shared memory as well.
    */
-  return unlock(access, SVN_NO_ERROR);
+  return unlock(SVN_NO_ERROR);
 }
 
 /* Validate the ATOMIC parameter, i.e it's address.
@@ -310,8 +351,6 @@ static svn_error_t *
 validate(svn_named_atomic__t *atomic)
 {
   return atomic 
-      && atomic >= &access.data->atomics[0]
-      && atomic < &access.data->atomics[access.data->count]
     ? SVN_NO_ERROR
     : svn_error_create(SVN_ERR_BAD_ATOMIC, 0, _("Not a valid atomic"));
 }
@@ -319,7 +358,24 @@ validate(svn_named_atomic__t *atomic)
 /* Implement API */
 
 svn_error_t *
+svn_atomic_namespace__create(svn_atomic_namespace__t **anamespace,
+                             const char *name,
+                             apr_pool_t *pool)
+{
+  svn_atomic_namespace__t *new_namespace
+      = apr_pcalloc(pool, sizeof(*new_namespace));
+
+  new_namespace->name = apr_pstrdup(pool, name);
+  SVN_ERR(initialize(new_namespace, pool));
+
+  *anamespace = new_namespace;
+  
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_named_atomic__get(svn_named_atomic__t **atomic,
+                      svn_atomic_namespace__t *anamespace,
                       const char *name,
                       svn_boolean_t auto_create)
 {
@@ -331,58 +387,64 @@ svn_named_atomic__get(svn_named_atomic__
    * in case of failure.
    */
   *atomic = NULL;
-  if (len > MAX_NAME_LENGTH)
+  if (len > SVN_NAMED_ATOMIC__MAX_NAME_LENGTH)
     return svn_error_create(SVN_ERR_BAD_ATOMIC, 0,
-                            _("Atomic name too long."));
+                            _("Atomic's name is too long."));
 
   /* Auto-initialize our access to the shared memory
    */
-  SVN_ERR(svn_atomic__init_once(&access.initialized,
-                                initialize,
-                                &access,
-                                NULL));
+  if (anamespace == NULL)
+    {
+      SVN_ERR(svn_atomic__init_once(&default_namespace.initialized,
+                                    initialize,
+                                    &default_namespace,
+                                    NULL));
+      anamespace = &default_namespace;
+    }
 
   /* Optimistic lookup.
    * Because we never change the name of existing atomics and may only
    * append new ones, we can safely compare the name of existing ones
    * with the name that we are looking for.
    */
-  for (i = 0, count = svn_atomic_read(&access.min_used); i < count; ++i)
-    if (strncmp(access.data->atomics[i].name, name, len + 1) == 0)
+  for (i = 0, count = svn_atomic_read(&anamespace->min_used); i < count; ++i)
+    if (strncmp(anamespace->data->atomics[i].name, name, len + 1) == 0)
       {
-        *atomic = &access.data->atomics[i];
+        *atomic = &anamespace->data->atomics[i];
         return SVN_NO_ERROR;
       }
 
   /* Try harder:
    * Serialize all lookup and insert the item, if necessary and allowed.
    */
-  SVN_ERR(lock(&access));
+  SVN_ERR(lock(anamespace));
 
   /* We only need to check for new entries.
    */
-  for (i = count; i < access.data->count; ++i)
-    if (strcmp(access.data->atomics[i].name, name))
+  for (i = count; i < anamespace->data->count; ++i)
+    if (strcmp(anamespace->data->atomics[i].name, name) == 0)
       {
-        *atomic = &access.data->atomics[i];
+        *atomic = &anamespace->data->atomics[i];
         
         /* Update our cached number of complete entries. */
-        svn_atomic_set(&access.min_used, access.data->count);
+        svn_atomic_set(&anamespace->min_used, anamespace->data->count);
 
-        return unlock(&access, error);
+        return unlock(error);
       }
 
   /* Not found.  Append a new entry, if allowed & possible.
    */
   if (auto_create)
     {
-      if (access.data->count < MAX_ATOMIC_COUNT)
+      if (anamespace->data->count < MAX_ATOMIC_COUNT)
         {
-          access.data->atomics[access.data->count].value = 0;
-          memcpy(access.data->atomics[access.data->count].name, name, len+1);
+          anamespace->data->atomics[anamespace->data->count].value = 0;
+          memcpy(anamespace->data->atomics[anamespace->data->count].name,
+                 name,
+                 len+1);
           
-          *atomic = &access.data->atomics[access.data->count];
-          ++access.data->count;
+          *atomic = &anamespace->data->atomics[anamespace->data->count];
+          ++anamespace->data->count;
         }
         else
           error = svn_error_create(SVN_ERR_BAD_ATOMIC, 0,
@@ -391,12 +453,12 @@ svn_named_atomic__get(svn_named_atomic__
 
   /* We are mainly done here.  Let others continue their work.
    */
-  SVN_ERR(unlock(&access, error));
+  SVN_ERR(unlock(error));
 
   /* Only now can we be sure that a full memory barrier has been set
    * and that the new entry has been written to memory in full.
    */
-  svn_atomic_set(&access.min_used, access.data->count);
+  svn_atomic_set(&anamespace->min_used, anamespace->data->count);
 
   return SVN_NO_ERROR;
 }


Reply via email to