You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ph...@apache.org on 2015/05/27 13:38:55 UTC

svn commit: r1681990 - /subversion/trunk/subversion/libsvn_fs_x/lock.c

Author: philip
Date: Wed May 27 11:38:54 2015
New Revision: 1681990

URL: http://svn.apache.org/r1681990
Log:
Apply FSFS lock change r1659212 to FSX.

* subversion/subversion/libsvn_fs_x/lock.c:
  (schedule_index_update): New helper function.
  (struct lock_info_t,
   struct unlock_info_t): Drop the unused fields.
  (lock_body,
   unlock_body): Rework the algorithm.

Modified:
    subversion/trunk/subversion/libsvn_fs_x/lock.c

Modified: subversion/trunk/subversion/libsvn_fs_x/lock.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/lock.c?rev=1681990&r1=1681989&r2=1681990&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/lock.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/lock.c Wed May 27 11:38:54 2015
@@ -737,6 +737,35 @@ svn_fs_x__allow_locked_operation(const c
   return SVN_NO_ERROR;
 }
 
+/* Helper function called from the lock and unlock code.
+   UPDATES is a map from "const char *" parent paths to "apr_array_header_t *"
+   arrays of child paths.  For all of the parent paths of PATH this function
+   adds PATH to the corresponding array of child paths. */
+static void
+schedule_index_update(apr_hash_t *updates,
+                      const char *path,
+                      apr_pool_t *scratch_pool)
+{
+  apr_pool_t *hashpool = apr_hash_pool_get(updates);
+  const char *parent_path = path;
+
+  while (! svn_fspath__is_root(parent_path, strlen(parent_path)))
+    {
+      apr_array_header_t *children;
+
+      parent_path = svn_fspath__dirname(parent_path, scratch_pool);
+      children = svn_hash_gets(updates, parent_path);
+
+      if (! children)
+        {
+          children = apr_array_make(hashpool, 8, sizeof(const char *));
+          svn_hash_sets(updates, apr_pstrdup(hashpool, parent_path), children);
+        }
+
+      APR_ARRAY_PUSH(children, const char *) = path;
+    }
+}
+
 /* The effective arguments for lock_body() below. */
 typedef struct lock_baton_t {
   svn_fs_t *fs;
@@ -859,7 +888,6 @@ check_lock(svn_error_t **fs_err,
 
 typedef struct lock_info_t {
   const char *path;
-  const char *component;
   svn_lock_t *lock;
   svn_error_t *fs_err;
 } lock_info_t;
@@ -882,7 +910,9 @@ lock_body(void *baton, apr_pool_t *pool)
   svn_fs_root_t *root;
   svn_revnum_t youngest;
   const char *rev_0_path;
-  int i, outstanding = 0;
+  int i;
+  apr_hash_t *index_updates = apr_hash_make(pool);
+  apr_hash_index_t *hi;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
   /* Until we implement directory locks someday, we only allow locks
@@ -896,35 +926,28 @@ lock_body(void *baton, apr_pool_t *pool)
     {
       const svn_sort__item_t *item = &APR_ARRAY_IDX(lb->targets, i,
                                                     svn_sort__item_t);
-      const svn_fs_lock_target_t *target = item->value;
       lock_info_t info;
 
       svn_pool_clear(iterpool);
 
       info.path = item->key;
-      SVN_ERR(check_lock(&info.fs_err, info.path, target, lb, root,
-                         youngest, iterpool));
       info.lock = NULL;
-      info.component = NULL;
-      APR_ARRAY_PUSH(lb->infos, lock_info_t) = info;
+      info.fs_err = SVN_NO_ERROR;
+
+      SVN_ERR(check_lock(&info.fs_err, info.path, item->value, lb, root,
+                         youngest, iterpool));
+
+      /* If no error occurred while pre-checking, schedule the index updates for
+         this path. */
       if (!info.fs_err)
-        ++outstanding;
+        schedule_index_update(index_updates, info.path, iterpool);
+
+      APR_ARRAY_PUSH(lb->infos, lock_info_t) = info;
     }
 
   rev_0_path = svn_fs_x__path_rev_absolute(lb->fs, 0, pool);
 
-  /* Given the paths:
-
-       /foo/bar/f
-       /foo/bar/g
-       /zig/x
-
-     we loop through repeatedly.  The first pass sees '/' on all paths
-     and writes the '/' index.  The second pass sees '/foo' twice and
-     writes that index followed by '/zig' and that index. The third
-     pass sees '/foo/bar' twice and writes that index, and then writes
-     the lock for '/zig/x'.  The fourth pass writes the locks for
-     '/foo/bar/f' and '/foo/bar/g'.
+  /* We apply the scheduled index updates before writing the actual locks.
 
      Writing indices before locks is correct: if interrupted it leaves
      indices without locks rather than locks without indices.  An
@@ -933,88 +956,46 @@ lock_body(void *baton, apr_pool_t *pool)
      index is inconsistent, svn_fs_x__allow_locked_operation will
      show locked on the file but unlocked on the parent. */
 
+  for (hi = apr_hash_first(pool, index_updates); hi; hi = apr_hash_next(hi))
+    {
+      const char *path = apr_hash_this_key(hi);
+      apr_array_header_t *children = apr_hash_this_val(hi);
+
+      svn_pool_clear(iterpool);
+      SVN_ERR(add_to_digest(lb->fs->path, children, path, rev_0_path,
+                            iterpool));
+    }
 
-  while (outstanding)
+  for (i = 0; i < lb->infos->nelts; ++i)
     {
-      const char *last_path = NULL;
-      apr_array_header_t *paths;
+      struct lock_info_t *info = &APR_ARRAY_IDX(lb->infos, i,
+                                                struct lock_info_t);
+      svn_sort__item_t *item = &APR_ARRAY_IDX(lb->targets, i, svn_sort__item_t);
+      svn_fs_lock_target_t *target = item->value;
 
       svn_pool_clear(iterpool);
-      paths = apr_array_make(iterpool, 1, sizeof(const char *));
 
-      for (i = 0; i < lb->infos->nelts; ++i)
+      if (! info->fs_err)
         {
-          lock_info_t *info = &APR_ARRAY_IDX(lb->infos, i, lock_info_t);
-          const svn_sort__item_t *item = &APR_ARRAY_IDX(lb->targets, i,
-                                                        svn_sort__item_t);
-          const svn_fs_lock_target_t *target = item->value;
-
-          if (!info->fs_err && !info->lock)
-            {
-              if (!info->component)
-                {
-                  info->component = info->path;
-                  APR_ARRAY_PUSH(paths, const char *) = info->path;
-                  last_path = "/";
-                }
-              else
-                {
-                  info->component = strchr(info->component + 1, '/');
-                  if (!info->component)
-                    {
-                      /* The component is a path to lock, this cannot
-                         match a previous path that need to be indexed. */
-                      if (paths->nelts)
-                        {
-                          SVN_ERR(add_to_digest(lb->fs->path, paths, last_path,
-                                                rev_0_path, iterpool));
-                          apr_array_clear(paths);
-                          last_path = NULL;
-                        }
-
-                      info->lock = svn_lock_create(lb->result_pool);
-                      if (target->token)
-                        info->lock->token = target->token;
-                      else
-                        SVN_ERR(svn_fs_x__generate_lock_token(
-                                  &(info->lock->token), lb->fs,
-                                  lb->result_pool));
-                      info->lock->path = info->path;
-                      info->lock->owner = lb->fs->access_ctx->username;
-                      info->lock->comment = lb->comment;
-                      info->lock->is_dav_comment = lb->is_dav_comment;
-                      info->lock->creation_date = apr_time_now();
-                      info->lock->expiration_date = lb->expiration_date;
-
-                      info->fs_err = set_lock(lb->fs->path, info->lock,
-                                              rev_0_path, iterpool);
-                      --outstanding;
-                    }
-                  else
-                    {
-                      /* The component is a path to an index. */
-                      apr_size_t len = info->component - info->path;
-
-                      if (last_path
-                          && (strncmp(last_path, info->path, len)
-                              || strlen(last_path) != len))
-                        {
-                          /* No match to the previous paths to index. */
-                          SVN_ERR(add_to_digest(lb->fs->path, paths, last_path,
-                                                rev_0_path, iterpool));
-                          apr_array_clear(paths);
-                          last_path = NULL;
-                        }
-                      APR_ARRAY_PUSH(paths, const char *) = info->path;
-                      if (!last_path)
-                        last_path = apr_pstrndup(iterpool, info->path, len);
-                    }
-                }
-            }
-
-          if (last_path && i == lb->infos->nelts - 1)
-            SVN_ERR(add_to_digest(lb->fs->path, paths, last_path,
-                                  rev_0_path, iterpool));
+          info->lock = svn_lock_create(lb->result_pool);
+          if (target->token)
+            info->lock->token = apr_pstrdup(lb->result_pool, target->token);
+          else
+            SVN_ERR(svn_fs_x__generate_lock_token(&(info->lock->token), lb->fs,
+                                                  lb->result_pool));
+
+          /* The INFO->PATH is already allocated in LB->RESULT_POOL as a result
+             of svn_fspath__canonicalize() (see svn_fs_fs__lock()). */
+          info->lock->path = info->path;
+          info->lock->owner = apr_pstrdup(lb->result_pool,
+                                          lb->fs->access_ctx->username);
+          info->lock->comment = apr_pstrdup(lb->result_pool, lb->comment);
+          info->lock->is_dav_comment = lb->is_dav_comment;
+          info->lock->creation_date = apr_time_now();
+          info->lock->expiration_date = lb->expiration_date;
+
+          info->fs_err = set_lock(lb->fs->path, info->lock, rev_0_path,
+                                  iterpool);
         }
     }
 
@@ -1058,10 +1039,8 @@ check_unlock(svn_error_t **fs_err,
 
 typedef struct unlock_info_t {
   const char *path;
-  const char *component;
   svn_error_t *fs_err;
   svn_boolean_t done;
-  int components;
 } unlock_info_t;
 
 /* The body of svn_fs_x__unlock(), which see.
@@ -1082,7 +1061,9 @@ unlock_body(void *baton, apr_pool_t *poo
   svn_fs_root_t *root;
   svn_revnum_t youngest;
   const char *rev_0_path;
-  int i, max_components = 0, outstanding = 0;
+  int i;
+  apr_hash_t *indices_updates = apr_hash_make(pool);
+  apr_hash_index_t *hi;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
   SVN_ERR(ub->fs->vtable->youngest_rev(&youngest, ub->fs, pool));
@@ -1093,95 +1074,56 @@ unlock_body(void *baton, apr_pool_t *poo
       const svn_sort__item_t *item = &APR_ARRAY_IDX(ub->targets, i,
                                                     svn_sort__item_t);
       const char *token = item->value;
-      unlock_info_t info = { 0 };
+      unlock_info_t info;
 
       svn_pool_clear(iterpool);
 
       info.path = item->key;
+      info.fs_err = SVN_NO_ERROR;
+      info.done = FALSE;
+
       if (!ub->skip_check)
         SVN_ERR(check_unlock(&info.fs_err, info.path, token, ub, root,
                              iterpool));
-      if (!info.fs_err)
-        {
-          const char *s;
 
-          info.components = 1;
-          info.component = info.path;
-          while((s = strchr(info.component + 1, '/')))
-            {
-              info.component = s;
-              ++info.components;
-            }
-
-          if (info.components > max_components)
-            max_components = info.components;
+      /* If no error occurred while pre-checking, schedule the index updates for
+         this path. */
+      if (!info.fs_err)
+        schedule_index_update(indices_updates, info.path, iterpool);
 
-          ++outstanding;
-        }
       APR_ARRAY_PUSH(ub->infos, unlock_info_t) = info;
     }
 
   rev_0_path = svn_fs_x__path_rev_absolute(ub->fs, 0, pool);
 
-  for (i = max_components; i >= 0; --i)
+  /* Unlike the lock_body(), we need to delete locks *before* we start to
+     update indices. */
+
+  for (i = 0; i < ub->infos->nelts; ++i)
     {
-      const char *last_path = NULL;
-      apr_array_header_t *paths;
-      int j;
+      struct unlock_info_t *info = &APR_ARRAY_IDX(ub->infos, i,
+                                                  struct unlock_info_t);
 
       svn_pool_clear(iterpool);
-      paths = apr_array_make(pool, 1, sizeof(const char *));
 
-      for (j = 0; j < ub->infos->nelts; ++j)
+      if (! info->fs_err)
         {
-          unlock_info_t *info = &APR_ARRAY_IDX(ub->infos, j, unlock_info_t);
+          SVN_ERR(delete_lock(ub->fs->path, info->path, iterpool));
+          info->done = TRUE;
+        }
+    }
 
-          if (!info->fs_err && info->path)
-            {
+  for (hi = apr_hash_first(pool, indices_updates); hi; hi = apr_hash_next(hi))
+    {
+      const char *path = apr_hash_this_key(hi);
+      apr_array_header_t *children = apr_hash_this_val(hi);
 
-              if (info->components == i)
-                {
-                  SVN_ERR(delete_lock(ub->fs->path, info->path, iterpool));
-                  info->done = TRUE;
-                }
-              else if (info->components > i)
-                {
-                  apr_size_t len = info->component - info->path;
-
-                  if (last_path
-                      && strcmp(last_path, "/")
-                      && (strncmp(last_path, info->path, len)
-                          || strlen(last_path) != len))
-                    {
-                      SVN_ERR(delete_from_digest(ub->fs->path, paths, last_path,
-                                                 rev_0_path, iterpool));
-                      apr_array_clear(paths);
-                      last_path = NULL;
-                    }
-                  APR_ARRAY_PUSH(paths, const char *) = info->path;
-                  if (!last_path)
-                    {
-                      if (info->component > info->path)
-                        last_path = apr_pstrndup(pool, info->path, len);
-                      else
-                        last_path = "/";
-                    }
-
-                  if (info->component > info->path)
-                    {
-                      --info->component;
-                      while(info->component[0] != '/')
-                        --info->component;
-                    }
-                }
-            }
-
-          if (last_path && j == ub->infos->nelts - 1)
-            SVN_ERR(delete_from_digest(ub->fs->path, paths, last_path,
-                                       rev_0_path, iterpool));
-        }
+      svn_pool_clear(iterpool);
+      SVN_ERR(delete_from_digest(ub->fs->path, children, path, rev_0_path,
+                                 iterpool));
     }
 
+  svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }