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;
}