subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1476675 [9/17] - in /subversion/branches/fsfs-format7: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ contrib/server-side/svncutter/ subversion/bindings/cxxhl/include/ subversion/bindings/cxxhl...
Date Sat, 27 Apr 2013 21:30:43 GMT
Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/fs-wrap.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/fs-wrap.c Sat Apr 27 21:30:36 2013
@@ -54,12 +54,17 @@ svn_repos_fs_commit_txn(const char **con
   apr_hash_t *props;
   apr_pool_t *iterpool;
   apr_hash_index_t *hi;
+  apr_hash_t *hooks_env;
 
   *new_rev = SVN_INVALID_REVNUM;
 
+  /* Parse the hooks-env file (if any). */
+  SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
+                                     pool, pool));
+
   /* Run pre-commit hooks. */
   SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
-  SVN_ERR(svn_repos__hooks_pre_commit(repos, txn_name, pool));
+  SVN_ERR(svn_repos__hooks_pre_commit(repos, hooks_env, txn_name, pool));
 
   /* Remove any ephemeral transaction properties. */
   SVN_ERR(svn_fs_txn_proplist(&props, txn, pool));
@@ -78,14 +83,15 @@ svn_repos_fs_commit_txn(const char **con
         }
     }
   svn_pool_destroy(iterpool);
-  
+
   /* Commit. */
   err = svn_fs_commit_txn(conflict_p, new_rev, txn, pool);
   if (! SVN_IS_VALID_REVNUM(*new_rev))
     return err;
 
   /* Run post-commit hooks. */
-  if ((err2 = svn_repos__hooks_post_commit(repos, *new_rev, txn_name, pool)))
+  if ((err2 = svn_repos__hooks_post_commit(repos, hooks_env,
+                                           *new_rev, txn_name, pool)))
     {
       err2 = svn_error_create
                (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err2,
@@ -110,6 +116,11 @@ svn_repos_fs_begin_txn_for_commit2(svn_f
   apr_array_header_t *revprops;
   const char *txn_name;
   svn_string_t *author = svn_hash_gets(revprop_table, SVN_PROP_REVISION_AUTHOR);
+  apr_hash_t *hooks_env;
+
+  /* Parse the hooks-env file (if any). */
+  SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
+                                     pool, pool));
 
   /* Begin the transaction, ask for the fs to do on-the-fly lock checks.
      We fetch its name, too, so the start-commit hook can use it.  */
@@ -124,7 +135,8 @@ svn_repos_fs_begin_txn_for_commit2(svn_f
   SVN_ERR(svn_repos_fs_change_txn_props(*txn_p, revprops, pool));
 
   /* Run start-commit hooks. */
-  SVN_ERR(svn_repos__hooks_start_commit(repos, author ? author->data : NULL,
+  SVN_ERR(svn_repos__hooks_start_commit(repos, hooks_env,
+                                        author ? author->data : NULL,
                                         repos->client_capabilities, txn_name,
                                         pool));
   return SVN_NO_ERROR;
@@ -317,6 +329,7 @@ svn_repos_fs_change_rev_prop4(svn_repos_
     {
       const svn_string_t *old_value;
       char action;
+      apr_hash_t *hooks_env;
 
       SVN_ERR(svn_repos__validate_prop(name, new_value, pool));
 
@@ -343,17 +356,24 @@ svn_repos_fs_change_rev_prop4(svn_repos_
       else
         action = 'M';
 
+      /* Parse the hooks-env file (if any, and if to be used). */
+      if (use_pre_revprop_change_hook || use_post_revprop_change_hook)
+        SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
+                                           pool, pool));
+
       /* ### currently not passing the old_value to hooks */
       if (use_pre_revprop_change_hook)
-        SVN_ERR(svn_repos__hooks_pre_revprop_change(repos, rev, author, name,
-                                                    new_value, action, pool));
+        SVN_ERR(svn_repos__hooks_pre_revprop_change(repos, hooks_env, rev,
+                                                    author, name, new_value,
+                                                    action, pool));
 
       SVN_ERR(svn_fs_change_rev_prop2(repos->fs, rev, name,
                                       &old_value, new_value, pool));
 
       if (use_post_revprop_change_hook)
-        SVN_ERR(svn_repos__hooks_post_revprop_change(repos, rev, author,  name,
-                                                     old_value, action, pool));
+        SVN_ERR(svn_repos__hooks_post_revprop_change(repos, hooks_env, rev,
+                                                     author, name, old_value,
+                                                     action, pool));
     }
   else  /* rev is either unreadable or only partially readable */
     {
@@ -472,6 +492,11 @@ svn_repos_fs_lock(svn_lock_t **lock,
   const char *username = NULL;
   const char *new_token;
   apr_array_header_t *paths;
+  apr_hash_t *hooks_env;
+
+  /* Parse the hooks-env file (if any). */
+  SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
+                                     pool, pool));
 
   /* Setup an array of paths in anticipation of the ra layers handling
      multiple locks in one request (1.3 most likely).  This is only
@@ -490,8 +515,8 @@ svn_repos_fs_lock(svn_lock_t **lock,
 
   /* Run pre-lock hook.  This could throw error, preventing
      svn_fs_lock() from happening. */
-  SVN_ERR(svn_repos__hooks_pre_lock(repos, &new_token, path, username, comment,
-                                    steal_lock, pool));
+  SVN_ERR(svn_repos__hooks_pre_lock(repos, hooks_env, &new_token, path,
+                                    username, comment, steal_lock, pool));
   if (*new_token)
     token = new_token;
 
@@ -500,7 +525,8 @@ svn_repos_fs_lock(svn_lock_t **lock,
                       expiration_date, current_rev, steal_lock, pool));
 
   /* Run post-lock hook. */
-  if ((err = svn_repos__hooks_post_lock(repos, paths, username, pool)))
+  if ((err = svn_repos__hooks_post_lock(repos, hooks_env,
+                                        paths, username, pool)))
     return svn_error_create
       (SVN_ERR_REPOS_POST_LOCK_HOOK_FAILED, err,
        "Lock succeeded, but post-lock hook failed");
@@ -519,10 +545,17 @@ svn_repos_fs_unlock(svn_repos_t *repos,
   svn_error_t *err;
   svn_fs_access_t *access_ctx = NULL;
   const char *username = NULL;
+  apr_array_header_t *paths;
+  apr_hash_t *hooks_env;
+
+  /* Parse the hooks-env file (if any). */
+  SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
+                                     pool, pool));
+
   /* Setup an array of paths in anticipation of the ra layers handling
      multiple locks in one request (1.3 most likely).  This is only
      used by svn_repos__hooks_post_lock. */
-  apr_array_header_t *paths = apr_array_make(pool, 1, sizeof(const char *));
+  paths = apr_array_make(pool, 1, sizeof(const char *));
   APR_ARRAY_PUSH(paths, const char *) = path;
 
   SVN_ERR(svn_fs_get_access(&access_ctx, repos->fs));
@@ -537,14 +570,15 @@ svn_repos_fs_unlock(svn_repos_t *repos,
 
   /* Run pre-unlock hook.  This could throw error, preventing
      svn_fs_unlock() from happening. */
-  SVN_ERR(svn_repos__hooks_pre_unlock(repos, path, username, token,
+  SVN_ERR(svn_repos__hooks_pre_unlock(repos, hooks_env, path, username, token,
                                       break_lock, pool));
 
   /* Unlock. */
   SVN_ERR(svn_fs_unlock(repos->fs, path, token, break_lock, pool));
 
   /* Run post-unlock hook. */
-  if ((err = svn_repos__hooks_post_unlock(repos, paths, username, pool)))
+  if ((err = svn_repos__hooks_post_unlock(repos, hooks_env, paths,
+                                          username, pool)))
     return svn_error_create
       (SVN_ERR_REPOS_POST_UNLOCK_HOOK_FAILED, err,
        _("Unlock succeeded, but post-unlock hook failed"));
@@ -706,7 +740,14 @@ pack_notify_func(void *baton,
   struct pack_notify_baton *pnb = baton;
   svn_repos_notify_t *notify;
 
-  notify = svn_repos_notify_create(pack_action + 3, pool);
+  /* Simple conversion works for these values. */
+  SVN_ERR_ASSERT(pack_action >= svn_fs_pack_notify_start
+                 && pack_action <= svn_fs_pack_notify_end_revprop);
+
+  notify = svn_repos_notify_create(pack_action
+                                   + svn_repos_notify_pack_shard_start
+                                   - svn_fs_pack_notify_start,
+                                   pool);
   notify->shard = shard;
   pnb->notify_func(pnb->notify_baton, notify, pool);
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/hooks.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/hooks.c Sat Apr 27 21:30:36 2013
@@ -27,6 +27,7 @@
 #include <apr_pools.h>
 #include <apr_file_io.h>
 
+#include "svn_config.h"
 #include "svn_hash.h"
 #include "svn_error.h"
 #include "svn_dirent_uri.h"
@@ -245,7 +246,7 @@ run_hook_cmd(svn_string_t **result,
         hook_env = svn_hash_gets(hooks_env,
                                  SVN_REPOS__HOOKS_ENV_DEFAULT_SECTION);
     }
-    
+
   err = svn_io_start_cmd3(&cmd_proc, ".", cmd, args,
                           env_from_env_hash(hook_env, pool, pool),
                           FALSE, FALSE, stdin_handle, result != NULL,
@@ -355,6 +356,86 @@ check_hook_cmd(const char *hook, svn_boo
   return NULL;
 }
 
+/* Baton for parse_hooks_env_option. */
+struct parse_hooks_env_option_baton {
+  /* The name of the section being parsed. If not the default section,
+   * the section name should match the name of a hook to which the
+   * options apply. */
+  const char *section;
+  apr_hash_t *hooks_env;
+} parse_hooks_env_option_baton;
+
+/* An implementation of svn_config_enumerator2_t.
+ * Set environment variable NAME to value VALUE in the environment for
+ * all hooks (in case the current section is the default section),
+ * or the hook with the name corresponding to the current section's name. */
+static svn_boolean_t
+parse_hooks_env_option(const char *name, const char *value,
+                       void *baton, apr_pool_t *pool)
+{
+  struct parse_hooks_env_option_baton *bo = baton;
+  apr_pool_t *result_pool = apr_hash_pool_get(bo->hooks_env);
+  apr_hash_t *hook_env;
+
+  hook_env = svn_hash_gets(bo->hooks_env, bo->section);
+  if (hook_env == NULL)
+    {
+      hook_env = apr_hash_make(result_pool);
+      svn_hash_sets(bo->hooks_env, apr_pstrdup(result_pool, bo->section),
+                    hook_env);
+    }
+  svn_hash_sets(hook_env, apr_pstrdup(result_pool, name),
+                apr_pstrdup(result_pool, value));
+
+  return TRUE;
+}
+
+struct parse_hooks_env_section_baton {
+  svn_config_t *cfg;
+  apr_hash_t *hooks_env;
+} parse_hooks_env_section_baton;
+
+/* An implementation of svn_config_section_enumerator2_t. */
+static svn_boolean_t
+parse_hooks_env_section(const char *name, void *baton, apr_pool_t *pool)
+{
+  struct parse_hooks_env_section_baton *b = baton;
+  struct parse_hooks_env_option_baton bo;
+
+  bo.section = name;
+  bo.hooks_env = b->hooks_env;
+
+  (void)svn_config_enumerate2(b->cfg, name, parse_hooks_env_option, &bo, pool);
+
+  return TRUE;
+}
+
+svn_error_t *
+svn_repos__parse_hooks_env(apr_hash_t **hooks_env_p,
+                           const char *local_abspath,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  svn_config_t *cfg;
+  struct parse_hooks_env_section_baton b;
+
+  if (local_abspath)
+    {
+      SVN_ERR(svn_config_read3(&cfg, local_abspath, FALSE,
+                               TRUE, TRUE, scratch_pool));
+      b.cfg = cfg;
+      b.hooks_env = apr_hash_make(result_pool);
+      (void)svn_config_enumerate_sections2(cfg, parse_hooks_env_section, &b,
+                                           scratch_pool);
+      *hooks_env_p = b.hooks_env;
+    }
+  else
+    {
+      *hooks_env_p = NULL;
+    }
+
+  return SVN_NO_ERROR;
+}
 
 /* Return an error for the failure of HOOK due to a broken symlink. */
 static svn_error_t *
@@ -367,6 +448,7 @@ hook_symlink_error(const char *hook)
 
 svn_error_t *
 svn_repos__hooks_start_commit(svn_repos_t *repos,
+                              apr_hash_t *hooks_env,
                               const char *user,
                               const apr_array_header_t *capabilities,
                               const char *txn_name,
@@ -405,7 +487,7 @@ svn_repos__hooks_start_commit(svn_repos_
       args[5] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_START_COMMIT, hook, args,
-                           repos->hooks_env, NULL, pool));
+                           hooks_env, NULL, pool));
     }
 
   return SVN_NO_ERROR;
@@ -449,6 +531,7 @@ lock_token_content(apr_file_t **handle, 
 
 svn_error_t  *
 svn_repos__hooks_pre_commit(svn_repos_t *repos,
+                            apr_hash_t *hooks_env,
                             const char *txn_name,
                             apr_pool_t *pool)
 {
@@ -484,7 +567,7 @@ svn_repos__hooks_pre_commit(svn_repos_t 
                                  APR_READ, APR_OS_DEFAULT, pool));
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_COMMIT, hook, args,
-                           repos->hooks_env, stdin_handle, pool));
+                           hooks_env, stdin_handle, pool));
     }
 
   return SVN_NO_ERROR;
@@ -493,6 +576,7 @@ svn_repos__hooks_pre_commit(svn_repos_t 
 
 svn_error_t  *
 svn_repos__hooks_post_commit(svn_repos_t *repos,
+                             apr_hash_t *hooks_env,
                              svn_revnum_t rev,
                              const char *txn_name,
                              apr_pool_t *pool)
@@ -515,7 +599,7 @@ svn_repos__hooks_post_commit(svn_repos_t
       args[4] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_COMMIT, hook, args,
-                           repos->hooks_env, NULL, pool));
+                           hooks_env, NULL, pool));
     }
 
   return SVN_NO_ERROR;
@@ -524,6 +608,7 @@ svn_repos__hooks_post_commit(svn_repos_t
 
 svn_error_t  *
 svn_repos__hooks_pre_revprop_change(svn_repos_t *repos,
+                                    apr_hash_t *hooks_env,
                                     svn_revnum_t rev,
                                     const char *author,
                                     const char *name,
@@ -563,7 +648,7 @@ svn_repos__hooks_pre_revprop_change(svn_
       args[6] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_REVPROP_CHANGE, hook,
-                           args, repos->hooks_env, stdin_handle, pool));
+                           args, hooks_env, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }
@@ -586,6 +671,7 @@ svn_repos__hooks_pre_revprop_change(svn_
 
 svn_error_t  *
 svn_repos__hooks_post_revprop_change(svn_repos_t *repos,
+                                     apr_hash_t *hooks_env,
                                      svn_revnum_t rev,
                                      const char *author,
                                      const char *name,
@@ -625,7 +711,7 @@ svn_repos__hooks_post_revprop_change(svn
       args[6] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_REVPROP_CHANGE, hook,
-                           args, repos->hooks_env, stdin_handle, pool));
+                           args, hooks_env, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }
@@ -636,6 +722,7 @@ svn_repos__hooks_post_revprop_change(svn
 
 svn_error_t  *
 svn_repos__hooks_pre_lock(svn_repos_t *repos,
+                          apr_hash_t *hooks_env,
                           const char **token,
                           const char *path,
                           const char *username,
@@ -655,6 +742,7 @@ svn_repos__hooks_pre_lock(svn_repos_t *r
       const char *args[7];
       svn_string_t *buf;
 
+
       args[0] = hook;
       args[1] = svn_dirent_local_style(svn_repos_path(repos, pool), pool);
       args[2] = path;
@@ -664,7 +752,7 @@ svn_repos__hooks_pre_lock(svn_repos_t *r
       args[6] = NULL;
 
       SVN_ERR(run_hook_cmd(&buf, SVN_REPOS__HOOK_PRE_LOCK, hook, args,
-                           repos->hooks_env, NULL, pool));
+                           hooks_env, NULL, pool));
 
       if (token)
         /* No validation here; the FS will take care of that. */
@@ -680,6 +768,7 @@ svn_repos__hooks_pre_lock(svn_repos_t *r
 
 svn_error_t  *
 svn_repos__hooks_post_lock(svn_repos_t *repos,
+                           apr_hash_t *hooks_env,
                            const apr_array_header_t *paths,
                            const char *username,
                            apr_pool_t *pool)
@@ -708,7 +797,7 @@ svn_repos__hooks_post_lock(svn_repos_t *
       args[4] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_LOCK, hook, args,
-                           repos->hooks_env, stdin_handle, pool));
+                           hooks_env, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }
@@ -719,6 +808,7 @@ svn_repos__hooks_post_lock(svn_repos_t *
 
 svn_error_t  *
 svn_repos__hooks_pre_unlock(svn_repos_t *repos,
+                            apr_hash_t *hooks_env,
                             const char *path,
                             const char *username,
                             const char *token,
@@ -745,7 +835,7 @@ svn_repos__hooks_pre_unlock(svn_repos_t 
       args[6] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_UNLOCK, hook, args,
-                           repos->hooks_env, NULL, pool));
+                           hooks_env, NULL, pool));
     }
 
   return SVN_NO_ERROR;
@@ -754,6 +844,7 @@ svn_repos__hooks_pre_unlock(svn_repos_t 
 
 svn_error_t  *
 svn_repos__hooks_post_unlock(svn_repos_t *repos,
+                             apr_hash_t *hooks_env,
                              const apr_array_header_t *paths,
                              const char *username,
                              apr_pool_t *pool)
@@ -782,7 +873,7 @@ svn_repos__hooks_post_unlock(svn_repos_t
       args[4] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_UNLOCK, hook, args,
-                           repos->hooks_env, stdin_handle, pool));
+                           hooks_env, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }

Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/load-fs-vtable.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/load-fs-vtable.c Sat Apr 27 21:30:36 2013
@@ -474,6 +474,18 @@ new_revision_record(void **revision_bato
   svn_revnum_t head_rev;
 
   rb = make_revision_baton(headers, pb, pool);
+
+  /* ### If we're filtering revisions, and this is one we've skipped,
+     ### and we've skipped it because it has a revision number younger
+     ### than the youngest in our acceptable range, then should we
+     ### just bail out here? */
+  /*
+  if (rb->skipped && (rb->rev > pb->end_rev))
+    return svn_error_createf(SVN_ERR_CEASE_INVOCATION, 0,
+                             _("Finished processing acceptable load "
+                               "revision range"));
+  */
+
   SVN_ERR(svn_fs_youngest_rev(&head_rev, pb->fs, pool));
 
   /* FIXME: This is a lame fallback loading multiple segments of dump in
@@ -900,16 +912,20 @@ close_revision(void *baton)
   const char *conflict_msg = NULL;
   svn_revnum_t committed_rev;
   svn_error_t *err;
-  const char *txn_name;
+  const char *txn_name = NULL;
+  apr_hash_t *hooks_env;
 
   /* If we're skipping this revision or it has an invalid revision
      number, we're done here. */
   if (rb->skipped || (rb->rev <= 0))
     return SVN_NO_ERROR;
 
-  /* Get the txn name, if it will be needed. */
+  /* Get the txn name and hooks environment if they will be needed. */
   if (pb->use_pre_commit_hook || pb->use_post_commit_hook)
     {
+      SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, pb->repos->hooks_env_path,
+                                         rb->pool, rb->pool));
+
       err = svn_fs_txn_name(&txn_name, rb->txn, rb->pool);
       if (err)
         {
@@ -921,7 +937,8 @@ close_revision(void *baton)
   /* Run the pre-commit hook, if so commanded. */
   if (pb->use_pre_commit_hook)
     {
-      err = svn_repos__hooks_pre_commit(pb->repos, txn_name, rb->pool);
+      err = svn_repos__hooks_pre_commit(pb->repos, hooks_env,
+                                        txn_name, rb->pool);
       if (err)
         {
           svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
@@ -953,8 +970,9 @@ close_revision(void *baton)
   /* Run post-commit hook, if so commanded.  */
   if (pb->use_post_commit_hook)
     {
-      if ((err = svn_repos__hooks_post_commit(pb->repos, committed_rev,
-                                              txn_name, rb->pool)))
+      if ((err = svn_repos__hooks_post_commit(pb->repos, hooks_env,
+                                              committed_rev, txn_name,
+                                              rb->pool)))
         return svn_error_create
           (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
            _("Commit succeeded, but post-commit hook failed"));

Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/log.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/log.c Sat Apr 27 21:30:36 2013
@@ -599,7 +599,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
      svn:mergeinfo change and is one of our paths of interest, or a
      child or [grand]parent directory thereof. */
   iterpool = svn_pool_create(scratch_pool);
-  for (hi = apr_hash_first(scratch_pool, *prefetched_changes); 
+  for (hi = apr_hash_first(scratch_pool, *prefetched_changes);
        hi;
        hi = apr_hash_next(hi))
     {

Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/repos.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/repos.c Sat Apr 27 21:30:36 2013
@@ -1147,14 +1147,15 @@ create_conf(svn_repos_t *repos, apr_pool
 "### With svnserve, the LANG environment variable of the svnserve process"   NL
 "### must be set to the same value as given here."                           NL
 "[default]"                                                                  NL
-"# LANG = en_US.UTF-8"                                                       NL
+"LANG = en_US.UTF-8"                                                         NL
 ""                                                                           NL
 "### This sets the PATH environment variable for the pre-commit hook."       NL
-"# [pre-commit]"                                                             NL
-"# PATH = /usr/local/bin:/usr/bin:/usr/sbin"                                 NL;
+"[pre-commit]"                                                               NL
+"PATH = /usr/local/bin:/usr/bin:/usr/sbin"                                   NL;
 
     SVN_ERR_W(svn_io_file_create(svn_dirent_join(repos->conf_path,
-                                                 SVN_REPOS__CONF_HOOKS_ENV,
+                                                 SVN_REPOS__CONF_HOOKS_ENV \
+                                                 SVN_REPOS__HOOK_DESC_EXT,
                                                  pool),
                                  hooks_env_contents, pool),
               _("Creating hooks-env file"));
@@ -1163,96 +1164,21 @@ create_conf(svn_repos_t *repos, apr_pool
   return SVN_NO_ERROR;
 }
 
-/* Baton for parse_hooks_env_option. */
-struct parse_hooks_env_option_baton {
-  /* The name of the section being parsed. If not the default section,
-   * the section name should match the name of a hook to which the
-   * options apply. */
-  const char *section;
-  apr_hash_t *hooks_env;
-} parse_hooks_env_option_baton;
-
-/* An implementation of svn_config_enumerator2_t.
- * Set environment variable NAME to value VALUE in the environment for
- * all hooks (in case the current section is the default section),
- * or the hook with the name corresponding to the current section's name. */
-static svn_boolean_t
-parse_hooks_env_option(const char *name, const char *value,
-                       void *baton, apr_pool_t *pool)
-{
-  struct parse_hooks_env_option_baton *bo = baton;
-  apr_pool_t *result_pool = apr_hash_pool_get(bo->hooks_env);
-  apr_hash_t *hook_env;
-  
-  hook_env = svn_hash_gets(bo->hooks_env, bo->section);
-  if (hook_env == NULL)
-    {
-      hook_env = apr_hash_make(result_pool);
-      svn_hash_sets(bo->hooks_env, apr_pstrdup(result_pool, bo->section),
-                    hook_env);
-    }
-  svn_hash_sets(hook_env, apr_pstrdup(result_pool, name),
-                apr_pstrdup(result_pool, value));
-
-  return TRUE;
-}
-
-struct parse_hooks_env_section_baton {
-  svn_config_t *cfg;
-  apr_hash_t *hooks_env;
-} parse_hooks_env_section_baton;
-
-/* An implementation of svn_config_section_enumerator2_t. */
-static svn_boolean_t
-parse_hooks_env_section(const char *name, void *baton, apr_pool_t *pool)
-{
-  struct parse_hooks_env_section_baton *b = baton;
-  struct parse_hooks_env_option_baton bo;
-
-  bo.section = name;
-  bo.hooks_env = b->hooks_env;
-
-  (void)svn_config_enumerate2(b->cfg, name, parse_hooks_env_option, &bo, pool);
-
-  return TRUE;
-}
-
-/* Parse the hooks env file for this repository. */
-static svn_error_t *
-parse_hooks_env(svn_repos_t *repos,
-                const char *local_abspath,
-                apr_pool_t *result_pool,
-                apr_pool_t *scratch_pool)
-{
-  svn_config_t *cfg;
-  int n;
-  struct parse_hooks_env_section_baton b;
-
-  SVN_ERR(svn_config_read2(&cfg, local_abspath, FALSE, TRUE, scratch_pool));
-  b.cfg = cfg;
-  b.hooks_env = apr_hash_make(result_pool);
-  n = svn_config_enumerate_sections2(cfg, parse_hooks_env_section, &b,
-                                     scratch_pool);
-  if (n > 0)
-    repos->hooks_env = b.hooks_env;
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_repos_hooks_setenv(svn_repos_t *repos,
                        const char *hooks_env_path,
-                       apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
   if (hooks_env_path == NULL)
-    hooks_env_path = svn_dirent_join(repos->conf_path,
-                                     SVN_REPOS__CONF_HOOKS_ENV, scratch_pool);
+    repos->hooks_env_path = svn_dirent_join(repos->conf_path,
+                                            SVN_REPOS__CONF_HOOKS_ENV,
+                                            repos->pool);
   else if (!svn_dirent_is_absolute(hooks_env_path))
-    hooks_env_path = svn_dirent_join(repos->conf_path, hooks_env_path,
-                                     scratch_pool);
-
-  SVN_ERR(parse_hooks_env(repos, hooks_env_path, result_pool, scratch_pool));
+    repos->hooks_env_path = svn_dirent_join(repos->conf_path,
+                                            hooks_env_path,
+                                            repos->pool);
+  else
+    repos->hooks_env_path = apr_pstrdup(repos->pool, hooks_env_path);
 
   return SVN_NO_ERROR;
 }
@@ -1272,8 +1198,9 @@ create_svn_repos_t(const char *path, apr
   repos->conf_path = svn_dirent_join(path, SVN_REPOS__CONF_DIR, pool);
   repos->hook_path = svn_dirent_join(path, SVN_REPOS__HOOK_DIR, pool);
   repos->lock_path = svn_dirent_join(path, SVN_REPOS__LOCK_DIR, pool);
+  repos->hooks_env_path = NULL;
   repos->repository_capabilities = apr_hash_make(pool);
-  repos->hooks_env = NULL;
+  repos->pool = pool;
 
   return repos;
 }
@@ -1750,6 +1677,62 @@ svn_repos_has_capability(svn_repos_t *re
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_repos_capabilities(apr_hash_t **capabilities,
+                       svn_repos_t *repos,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  static const char *const queries[] = {
+    SVN_REPOS_CAPABILITY_MERGEINFO,
+    NULL
+  };
+  const char *const *i;
+
+  *capabilities = apr_hash_make(result_pool);
+
+  for (i = queries; *i; i++)
+    {
+      svn_boolean_t has;
+      SVN_ERR(svn_repos_has_capability(repos, &has, *i, scratch_pool));
+      if (has)
+        svn_hash_sets(*capabilities, *i, *i);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_repos_info_format(int *repos_format,
+                      svn_version_t **supports_version,
+                      svn_repos_t *repos,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
+{
+  *repos_format = repos->format;
+  *supports_version = apr_palloc(result_pool, sizeof(svn_version_t));
+
+  (*supports_version)->major = SVN_VER_MAJOR;
+  (*supports_version)->minor = 0;
+  (*supports_version)->patch = 0;
+  (*supports_version)->tag = "";
+
+  switch (repos->format)
+    {
+    case SVN_REPOS__FORMAT_NUMBER_LEGACY:
+      break;
+    case SVN_REPOS__FORMAT_NUMBER_1_4:
+      (*supports_version)->minor = 4;
+      break;
+#ifdef SVN_DEBUG
+# if SVN_REPOS__FORMAT_NUMBER != SVN_REPOS__FORMAT_NUMBER_1_4
+#  error "Need to add a 'case' statement here"
+# endif
+#endif
+    }
+
+  return SVN_NO_ERROR;
+}
 
 svn_fs_t *
 svn_repos_fs(svn_repos_t *repos)
@@ -1828,8 +1811,8 @@ svn_repos_recover4(const char *path,
 struct freeze_baton_t {
   apr_array_header_t *paths;
   int counter;
-  svn_error_t *(*freeze_body)(void *, apr_pool_t *);
-  void *baton;
+  svn_repos_freeze_func_t freeze_func;
+  void *freeze_baton;
 };
 
 static svn_error_t *
@@ -1840,7 +1823,7 @@ multi_freeze(void *baton,
 
   if (fb->counter == fb->paths->nelts)
     {
-      SVN_ERR(fb->freeze_body(fb->baton, pool));
+      SVN_ERR(fb->freeze_func(fb->freeze_baton, pool));
       return SVN_NO_ERROR;
     }
   else
@@ -1889,16 +1872,16 @@ multi_freeze(void *baton,
    while frozen. */
 svn_error_t *
 svn_repos_freeze(apr_array_header_t *paths,
-                 svn_error_t *(*freeze_body)(void *, apr_pool_t *),
-                 void *baton,
+                 svn_repos_freeze_func_t freeze_func,
+                 void *freeze_baton,
                  apr_pool_t *pool)
 {
   struct freeze_baton_t fb;
 
   fb.paths = paths;
   fb.counter = 0;
-  fb.freeze_body = freeze_body;
-  fb.baton = baton;
+  fb.freeze_func = freeze_func;
+  fb.freeze_baton = freeze_baton;
 
   SVN_ERR(multi_freeze(&fb, pool));
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/repos.h?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/repos.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/repos.h Sat Apr 27 21:30:36 2013
@@ -47,7 +47,8 @@ extern "C" {
    formats are accepted by some versions of Subversion which do not
    pay attention to the FS format number.
 */
-#define SVN_REPOS__FORMAT_NUMBER         5
+#define SVN_REPOS__FORMAT_NUMBER         SVN_REPOS__FORMAT_NUMBER_1_4
+#define SVN_REPOS__FORMAT_NUMBER_1_4     5
 #define SVN_REPOS__FORMAT_NUMBER_LEGACY  3
 
 
@@ -126,6 +127,10 @@ struct svn_repos_t
   /* The format number of this repository. */
   int format;
 
+  /* The path to the repository's hooks enviroment file. If NULL, hooks run
+   * in an empty environment. */
+  const char *hooks_env_path;
+
   /* The FS backend in use within this repository. */
   const char *fs_type;
 
@@ -147,25 +152,36 @@ struct svn_repos_t
      those constants' addresses, therefore). */
   apr_hash_t *repository_capabilities;
 
-  /* The environment inherited to hook scripts. If NULL, hooks run
-   * in an empty environment.
-   *
-   * This is a nested hash table.
-   * The entry with name SVN_REPOS__HOOKS_ENV_DEFAULT_SECTION contains the
-   * default environment for all hooks in form of an apr_hash_t with keys
-   * and values describing the names and values of environment variables.
-   * Defaults can be overridden by an entry matching the name of a hook.
-   * E.g. an entry with the name SVN_REPOS__HOOK_PRE_COMMIT provides the
-   * environment specific to the pre-commit hook. */
-  apr_hash_t *hooks_env;
+  /* Pool from which this structure was allocated.  Also used for
+     auxiliary repository-related data that requires a matching
+     lifespan.  (As the svn_repos_t structure tends to be relatively
+     long-lived, please be careful regarding this pool's usage.)  */
+  apr_pool_t *pool;
 };
 
 
 /*** Hook-running Functions ***/
 
+/* Set *HOOKS_ENV_P to the parsed contents of the hooks-env file
+   LOCAL_ABSPATH, allocated in RESULT_POOL.  (This result is suitable
+   for delivery to the various hook wrapper functions which accept a
+   'hooks_env' parameter.)  If LOCAL_ABSPATH is NULL, set *HOOKS_ENV_P
+   to NULL.
+
+   Use SCRATCH_POOL for temporary allocations.  */
+svn_error_t *
+svn_repos__parse_hooks_env(apr_hash_t **hooks_env_p,
+                           const char *local_abspath,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
+
 /* Run the start-commit hook for REPOS.  Use POOL for any temporary
    allocations.  If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    USER is the authenticated name of the user starting the commit.
 
    CAPABILITIES is a list of 'const char *' capability names (using
@@ -177,6 +193,7 @@ struct svn_repos_t
    created. */
 svn_error_t *
 svn_repos__hooks_start_commit(svn_repos_t *repos,
+                              apr_hash_t *hooks_env,
                               const char *user,
                               const apr_array_header_t *capabilities,
                               const char *txn_name,
@@ -185,18 +202,28 @@ svn_repos__hooks_start_commit(svn_repos_
 /* Run the pre-commit hook for REPOS.  Use POOL for any temporary
    allocations.  If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    TXN_NAME is the name of the transaction that is being committed.  */
 svn_error_t *
 svn_repos__hooks_pre_commit(svn_repos_t *repos,
+                            apr_hash_t *hooks_env,
                             const char *txn_name,
                             apr_pool_t *pool);
 
 /* Run the post-commit hook for REPOS.  Use POOL for any temporary
    allocations.  If the hook fails, run SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    REV is the revision that was created as a result of the commit.  */
 svn_error_t *
 svn_repos__hooks_post_commit(svn_repos_t *repos,
+                             apr_hash_t *hooks_env,
                              svn_revnum_t rev,
                              const char *txn_name,
                              apr_pool_t *pool);
@@ -205,6 +232,10 @@ svn_repos__hooks_post_commit(svn_repos_t
    temporary allocations.  If the hook fails, return
    SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    REV is the revision whose property is being changed.
    AUTHOR is the authenticated name of the user changing the prop.
    NAME is the name of the property being changed.
@@ -217,6 +248,7 @@ svn_repos__hooks_post_commit(svn_repos_t
    will be written. */
 svn_error_t *
 svn_repos__hooks_pre_revprop_change(svn_repos_t *repos,
+                                    apr_hash_t *hooks_env,
                                     svn_revnum_t rev,
                                     const char *author,
                                     const char *name,
@@ -228,6 +260,10 @@ svn_repos__hooks_pre_revprop_change(svn_
    temporary allocations.  If the hook fails, return
    SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    REV is the revision whose property was changed.
    AUTHOR is the authenticated name of the user who changed the prop.
    NAME is the name of the property that was changed, and OLD_VALUE is
@@ -239,6 +275,7 @@ svn_repos__hooks_pre_revprop_change(svn_
    the property is being created, no data will be written. */
 svn_error_t *
 svn_repos__hooks_post_revprop_change(svn_repos_t *repos,
+                                     apr_hash_t *hooks_env,
                                      svn_revnum_t rev,
                                      const char *author,
                                      const char *name,
@@ -249,6 +286,10 @@ svn_repos__hooks_post_revprop_change(svn
 /* Run the pre-lock hook for REPOS.  Use POOL for any temporary
    allocations.  If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    PATH is the path being locked, USERNAME is the person doing it,
    COMMENT is the comment of the lock, and is treated as an empty
    string when NULL is given.  STEAL-LOCK is a flag if the user is
@@ -261,6 +302,7 @@ svn_repos__hooks_post_revprop_change(svn
 
 svn_error_t *
 svn_repos__hooks_pre_lock(svn_repos_t *repos,
+                          apr_hash_t *hooks_env,
                           const char **token,
                           const char *path,
                           const char *username,
@@ -271,10 +313,15 @@ svn_repos__hooks_pre_lock(svn_repos_t *r
 /* Run the post-lock hook for REPOS.  Use POOL for any temporary
    allocations.  If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    PATHS is an array of paths being locked, USERNAME is the person
    who did it.  */
 svn_error_t *
 svn_repos__hooks_post_lock(svn_repos_t *repos,
+                           apr_hash_t *hooks_env,
                            const apr_array_header_t *paths,
                            const char *username,
                            apr_pool_t *pool);
@@ -282,11 +329,16 @@ svn_repos__hooks_post_lock(svn_repos_t *
 /* Run the pre-unlock hook for REPOS.  Use POOL for any temporary
    allocations.  If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    PATH is the path being unlocked, USERNAME is the person doing it,
    TOKEN is the lock token to be unlocked which should not be NULL,
    and BREAK-LOCK is a flag if the user is breaking the lock.  */
 svn_error_t *
 svn_repos__hooks_pre_unlock(svn_repos_t *repos,
+                            apr_hash_t *hooks_env,
                             const char *path,
                             const char *username,
                             const char *token,
@@ -296,10 +348,15 @@ svn_repos__hooks_pre_unlock(svn_repos_t 
 /* Run the post-unlock hook for REPOS.  Use POOL for any temporary
    allocations.  If the hook fails, return SVN_ERR_REPOS_HOOK_FAILURE.
 
+   HOOKS_ENV is a hash of hook script environment information returned
+   via svn_repos__parse_hooks_env() (or NULL if no such information is
+   available).
+
    PATHS is an array of paths being unlocked, USERNAME is the person
    who did it.  */
 svn_error_t *
 svn_repos__hooks_post_unlock(svn_repos_t *repos,
+                             apr_hash_t *hooks_env,
                              const apr_array_header_t *paths,
                              const char *username,
                              apr_pool_t *pool);
@@ -310,25 +367,19 @@ svn_repos__hooks_post_unlock(svn_repos_t
 /* Read authz configuration data from PATH into *AUTHZ_P, allocated
    in POOL.  If GROUPS_PATH is set, use the global groups parsed from it.
 
-   PATH and GROUPS_PATH may be a file or a registry path and iff ACCEPT_URLS
-   is set it may also be a repos relative url or an absolute file url.  When
-   ACCEPT_URLS is FALSE REPOS_ROOT can be NULL.
+   PATH and GROUPS_PATH may be a dirent or a registry path and iff ACCEPT_URLS
+   is set it may also be an absolute file url.
 
-   If PATH or GROUPS_PATH is not a valid authz rule file, then return 
+   If PATH or GROUPS_PATH is not a valid authz rule file, then return
    SVN_AUTHZ_INVALID_CONFIG.  The contents of *AUTHZ_P is then
    undefined.  If MUST_EXIST is TRUE, a missing authz or global groups file
-   is also an error.
-
-   If PATH is a repos relative URL then REPOS_ROOT must be set to
-   the root of the repository the authz configuration will be used with.
-   The same applies to GROUPS_PATH if it is being used. */
+   is also an error. */
 svn_error_t *
 svn_repos__authz_read(svn_authz_t **authz_p,
                       const char *path,
                       const char *groups_path,
                       svn_boolean_t must_exist,
                       svn_boolean_t accept_urls,
-                      const char *repos_root,
                       apr_pool_t *pool);
 
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/rev_hunt.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/rev_hunt.c Sat Apr 27 21:30:36 2013
@@ -1491,7 +1491,7 @@ get_file_revs_backwards(svn_repos_t *rep
   SVN_ERR(svn_fs_revision_root(&root, repos->fs, end, scratch_pool));
   SVN_ERR(svn_fs_check_path(&kind, root, path, scratch_pool));
   if (kind != svn_node_file)
-    return svn_error_createf(SVN_ERR_FS_NOT_FILE, 
+    return svn_error_createf(SVN_ERR_FS_NOT_FILE,
                              NULL, _("'%s' is not a file in revision %ld"),
                              path, end);
 

Propchange: subversion/branches/fsfs-format7/subversion/libsvn_subr/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat Apr 27 21:30:36 2013
@@ -9,3 +9,4 @@ Debug
 .*~
 libsvn_subr.def
 internal_statements.h
+errorcode.inc

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/auth.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/auth.c Sat Apr 27 21:30:36 2013
@@ -35,6 +35,7 @@
 #include "svn_private_config.h"
 #include "svn_dso.h"
 #include "svn_version.h"
+#include "private/svn_dep_compat.h"
 
 #include "auth.h"
 
@@ -186,6 +187,15 @@ svn_auth_get_parameter(svn_auth_baton_t 
 }
 
 
+/* Return the key used to address the in-memory cache of auth
+   credentials of type CRED_KIND and associated with REALMSTRING. */
+static const char *
+make_cache_key(const char *cred_kind,
+               const char *realmstring,
+               apr_pool_t *pool)
+{
+  return apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
+}
 
 svn_error_t *
 svn_auth_first_credentials(void **credentials,
@@ -212,7 +222,7 @@ svn_auth_first_credentials(void **creden
                              cred_kind);
 
   /* First, see if we have cached creds in the auth_baton. */
-  cache_key = apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
+  cache_key = make_cache_key(cred_kind, realmstring, pool);
   creds = svn_hash_gets(auth_baton->creds_cache, cache_key);
   if (creds)
     {
@@ -381,6 +391,32 @@ svn_auth_save_credentials(svn_auth_iters
   return SVN_NO_ERROR;
 }
 
+
+svn_error_t *
+svn_auth_forget_credentials(svn_auth_baton_t *auth_baton,
+                            const char *cred_kind,
+                            const char *realmstring,
+                            apr_pool_t *scratch_pool)
+{
+  SVN_ERR_ASSERT((cred_kind && realmstring) || (!cred_kind && !realmstring));
+
+  /* If we have a CRED_KIND and REALMSTRING, we clear out just the
+     cached item (if any).  Otherwise, empty the whole hash. */
+  if (cred_kind)
+    {
+      svn_hash_sets(auth_baton->creds_cache,
+                    make_cache_key(cred_kind, realmstring, scratch_pool),
+                    NULL);
+    }
+  else
+    {
+      apr_hash_clear(auth_baton->creds_cache);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
 svn_auth_ssl_server_cert_info_t *
 svn_auth_ssl_server_cert_info_dup
   (const svn_auth_ssl_server_cert_info_t *info, apr_pool_t *pool)
@@ -614,20 +650,3 @@ svn_auth_get_platform_specific_client_pr
 
   return SVN_NO_ERROR;
 }
-
-svn_error_t *
-svn_auth_cleanup_walk(svn_auth_baton_t *baton,
-                      svn_auth_cleanup_callback cleanup,
-                      void *cleanup_baton,
-                      apr_pool_t *scratch_pool)
-{
-
-  if (svn_hash_gets(baton->tables, SVN_AUTH_CRED_SIMPLE))
-    {
-      SVN_ERR(svn_auth__simple_cleanup_walk(baton, cleanup, cleanup_baton,
-                                            baton->creds_cache, scratch_pool));
-    }
-  /* ### Maybe add support for other providers? */
-
-  return SVN_NO_ERROR;
-}

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/auth.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/auth.h?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/auth.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/auth.h Sat Apr 27 21:30:36 2013
@@ -21,8 +21,12 @@
  * ====================================================================
  */
 
-#ifndef SVN_SUBR_AUTH_H
-#define SVN_SUBR_AUTH_H
+#ifndef SVN_LIBSVN_SUBR_AUTH_H
+#define SVN_LIBSVN_SUBR_AUTH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
 
 #include "svn_auth.h"
 
@@ -37,13 +41,9 @@ svn_auth__file_path(const char **path,
                     const char *config_dir,
                     apr_pool_t *pool);
 
-/* Implementation of svn_auth_cleanup_walk() for the "simple" provider */
-svn_error_t *
-svn_auth__simple_cleanup_walk(svn_auth_baton_t *baton,
-                              svn_auth_cleanup_callback cleanup,
-                              void *cleanup_baton,
-                              apr_hash_t *creds_cache,
-                              apr_pool_t *scratch_pool);
 
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
 
-#endif
+#endif /* SVN_LIBSVN_SUBR_AUTH_H */

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-inprocess.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-inprocess.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-inprocess.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-inprocess.c Sat Apr 27 21:30:36 2013
@@ -214,7 +214,7 @@ inprocess_cache_get(void **value_p,
 {
   inprocess_cache_t *cache = cache_void;
   char* buffer = NULL;
-  apr_size_t size;
+  apr_size_t size = 0;
 
   if (key)
     SVN_MUTEX__WITH_LOCK(cache->mutex,
@@ -674,6 +674,7 @@ svn_cache__create_inprocess(svn_cache__t
 
   wrapper->vtable = &inprocess_cache_vtable;
   wrapper->cache_internal = cache;
+  wrapper->pretend_empty = !!getenv("SVN_X_DOES_NOT_MARK_THE_SPOT");
 
   *cache_p = wrapper;
   return SVN_NO_ERROR;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-membuffer.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-membuffer.c Sat Apr 27 21:30:36 2013
@@ -45,6 +45,8 @@
  *
  * 1. A linear data buffer containing cached items in a serialized
  *    representation. There may be arbitrary gaps between entries.
+ *    This buffer is sub-devided into (currently two) cache levels.
+ *
  * 2. A directory of cache entries. This is organized similar to CPU
  *    data caches: for every possible key, there is exactly one group
  *    of entries that may contain the header info for an item with
@@ -56,23 +58,30 @@
  * between different processes and / or to persist them on disk. These
  * out-of-process features have not been implemented, yet.
  *
+ * Superficially, cache levels are being used as usual: insertion happens
+ * into L1 and evictions will promote items to L2.  But their whole point
+ * is a different one.  L1 uses a circular buffer, i.e. we have perfect
+ * caching for the last N bytes where N is the size of L1.  L2 uses a more
+ * elaborate scheme based on priorities and hit counts as described below.
+ *
  * The data buffer usage information is implicitly given by the directory
  * entries. Every USED entry has a reference to the previous and the next
  * used dictionary entry and this double-linked list is ordered by the
  * offsets of their item data within the data buffer. So removing data,
  * for instance, is done simply by unlinking it from the chain, implicitly
  * marking the entry as well as the data buffer section previously
- * associated to it as unused.
+ * associated to it as unused.  First and last element of that chain are
+ * being referenced from the respective cache level.
  *
- * Insertion can occur at only one, sliding position. It is marked by its
- * offset in the data buffer plus the index of the first used entry at or
- * behind that position. If this gap is too small to accommodate the new
- * item, the insertion window is extended as described below. The new entry
- * will always be inserted at the bottom end of the window and since the
- * next used entry is known, properly sorted insertion is possible.
+ * Insertion can occur at only one, sliding position per cache level.  It is
+ * marked by its offset in the data buffer and the index of the first used
+ * entry at or behind that position.  If this gap is too small to accommodate
+ * the new item, the insertion window is extended as described below. The new
+ * entry will always be inserted at the bottom end of the window and since
+ * the next used entry is known, properly sorted insertion is possible.
  *
  * To make the cache perform robustly in a wide range of usage scenarios,
- * a randomized variant of LFU is used (see ensure_data_insertable for
+ * L2 uses a randomized variant of LFU (see ensure_data_insertable_l2 for
  * details). Every item holds a read hit counter and there is a global read
  * hit counter. The more hits an entry has in relation to the average, the
  * more it is likely to be kept using a rand()-based condition. The test is
@@ -86,7 +95,7 @@
  * they get not used for a while. Also, even a cache thrashing situation
  * about 50% of the content survives every 50% of the cache being re-written
  * with new entries. For details on the fine-tuning involved, see the
- * comments in ensure_data_insertable().
+ * comments in ensure_data_insertable_l2().
  *
  * To limit the entry size and management overhead, not the actual item keys
  * but only their MD5 checksums will not be stored. This is reasonably safe
@@ -313,7 +322,7 @@ static svn_error_t* assert_equal_tags(co
 /* A single dictionary entry. Since all entries will be allocated once
  * during cache creation, those entries might be either used or unused.
  * An entry is used if and only if it is contained in the doubly-linked
- * list of used entries.
+ * list of used entries per cache level.
  */
 typedef struct entry_t
 {
@@ -321,7 +330,8 @@ typedef struct entry_t
    */
   entry_key_t key;
 
-  /* The offset of the cached item's serialized data within the data buffer.
+  /* The offset of the cached item's serialized data within the caches
+   * DATA buffer.
    */
   apr_uint64_t offset;
 
@@ -337,15 +347,15 @@ typedef struct entry_t
 
   /* Reference to the next used entry in the order defined by offset.
    * NO_INDEX indicates the end of the list; this entry must be referenced
-   * by the caches membuffer_cache_t.last member. NO_INDEX also implies
-   * that the data buffer is not used beyond offset+size.
+   * by the caches cache_level_t.last member.  NO_INDEX also implies that
+   * the data buffer is not used beyond offset+size.
    * Only valid for used entries.
    */
   apr_uint32_t next;
 
   /* Reference to the previous used entry in the order defined by offset.
    * NO_INDEX indicates the end of the list; this entry must be referenced
-   * by the caches membuffer_cache_t.first member.
+   * by the caches cache_level_t.first member.
    * Only valid for used entries.
    */
   apr_uint32_t previous;
@@ -372,28 +382,12 @@ typedef struct entry_group_t
   entry_t entries[GROUP_SIZE];
 } entry_group_t;
 
-/* The cache header structure.
+/* Per-cache level header structure.  Instances of this are members of
+ * svn_membuffer_t and will use non-overlapping sections of its DATA buffer.
+ * All offset values are global / absolute to that whole buffer.
  */
-struct svn_membuffer_t
+typedef struct cache_level_t
 {
-  /* Number of cache segments. Must be a power of 2.
-     Please note that this structure represents only one such segment
-     and that all segments must / will report the same values here. */
-  apr_uint32_t segment_count;
-
-  /* The dictionary, GROUP_SIZE * group_count entries long. Never NULL.
-   */
-  entry_group_t *directory;
-
-  /* Flag array with group_count / GROUP_INIT_GRANULARITY _bit_ elements.
-   * Allows for efficiently marking groups as "not initialized".
-   */
-  unsigned char *group_initialized;
-
-  /* Size of dictionary in groups. Must be > 0.
-   */
-  apr_uint32_t group_count;
-
   /* Reference to the first (defined by the order content in the data
    * buffer) dictionary entry used by any data item.
    * NO_INDEX for an empty cache.
@@ -414,18 +408,46 @@ struct svn_membuffer_t
   apr_uint32_t next;
 
 
-  /* Pointer to the data buffer, data_size bytes long. Never NULL.
+  /* First offset in the caches DATA buffer that belongs to this level.
    */
-  unsigned char *data;
+  apr_uint64_t start_offset;
 
-  /* Size of data buffer in bytes. Must be > 0.
+  /* Size of data buffer allocated to this level in bytes. Must be > 0.
    */
-  apr_uint64_t data_size;
+  apr_uint64_t size;
 
   /* Offset in the data buffer where the next insertion shall occur.
    */
   apr_uint64_t current_data;
 
+} cache_level_t;
+
+/* The cache header structure.
+ */
+struct svn_membuffer_t
+{
+  /* Number of cache segments. Must be a power of 2.
+     Please note that this structure represents only one such segment
+     and that all segments must / will report the same values here. */
+  apr_uint32_t segment_count;
+
+  /* The dictionary, GROUP_SIZE * group_count entries long. Never NULL.
+   */
+  entry_group_t *directory;
+
+  /* Flag array with group_count / GROUP_INIT_GRANULARITY _bit_ elements.
+   * Allows for efficiently marking groups as "not initialized".
+   */
+  unsigned char *group_initialized;
+
+  /* Size of dictionary in groups. Must be > 0.
+   */
+  apr_uint32_t group_count;
+
+  /* Pointer to the data buffer, data_size bytes long. Never NULL.
+   */
+  unsigned char *data;
+
   /* Total number of data buffer bytes in use. This is for statistics only.
    */
   apr_uint64_t data_used;
@@ -435,6 +457,24 @@ struct svn_membuffer_t
    */
   apr_uint64_t max_entry_size;
 
+  /* The cache levels, organized as sub-buffers.  Since entries in the
+   * DIRECTORY use offsets in DATA for addressing, a cache lookup does
+   * not need to know the cache level of a specific item.  Cache levels
+   * are only used to implement a hybrid insertion / eviction strategy.
+   */
+
+  /* First cache level, i.e. most insertions happen here.  Very large
+   * items might get inserted directly into L2.  L1 is a strict FIFO
+   * ring buffer that does not care about item priorities.  All evicted
+   * items get a chance to be promoted to L2.
+   */
+  cache_level_t l1;
+
+  /* Second cache level, i.e. data evicted from L1 will be added here
+   * if the item is "important" enough or the L2 insertion window is large
+   * enough.
+   */
+  cache_level_t l2;
 
   /* Number of used dictionary entries, i.e. number of cached items.
    * In conjunction with hit_count, this is used calculate the average
@@ -525,7 +565,7 @@ write_lock_cache(svn_membuffer_t *cache,
               status = APR_SUCCESS;
             }
         }
-    
+
       if (status)
         return svn_error_wrap_apr(status,
                                   _("Can't write-lock cache mutex"));
@@ -625,6 +665,96 @@ get_index(svn_membuffer_t *cache, entry_
        + (apr_uint32_t)(entry - cache->directory[group_index].entries);
 }
 
+/* Return the cache level of ENTRY in CACHE.
+ */
+static cache_level_t *
+get_cache_level(svn_membuffer_t *cache, entry_t *entry)
+{
+  return entry->offset < cache->l1.size ? &cache->l1
+                                        : &cache->l2;
+}
+
+/* Insert ENTRY to the chain of items that belong to LEVEL in CACHE.  IDX
+ * is ENTRY's item index and is only given for efficiency.  The insertion
+ * takes place just before LEVEL->NEXT.  *CACHE will not be modified.
+ */
+static void
+chain_entry(svn_membuffer_t *cache,
+            cache_level_t *level,
+            entry_t *entry,
+            apr_uint32_t idx)
+{
+  /* insert ENTRY before this item */
+  entry_t *next = level->next == NO_INDEX
+                ? NULL
+                : get_entry(cache, level->next);
+  assert(idx == get_index(cache, entry));
+
+  /* update entry chain
+   */
+  entry->next = level->next;
+  if (level->first == NO_INDEX)
+    {
+      /* insert as the first entry and only in the chain
+       */
+      entry->previous = NO_INDEX;
+      level->last = idx;
+      level->first = idx;
+    }
+  else if (next == NULL)
+    {
+      /* insert as the last entry in the chain.
+       * Note that it cannot also be at the beginning of the chain.
+       */
+      entry->previous = level->last;
+      get_entry(cache, level->last)->next = idx;
+      level->last = idx;
+    }
+  else
+    {
+      /* insert either at the start of a non-empty list or
+       * somewhere in the middle
+       */
+      entry->previous = next->previous;
+      next->previous = idx;
+
+      if (entry->previous != NO_INDEX)
+        get_entry(cache, entry->previous)->next = idx;
+      else
+        level->first = idx;
+    }
+}
+
+/* Remove ENTRY from the chain of items that belong to LEVEL in CACHE. IDX
+ * is ENTRY's item index and is only given for efficiency.  Please note
+ * that neither *CACHE nor *ENTRY will not be modified.
+ */
+static void
+unchain_entry(svn_membuffer_t *cache,
+              cache_level_t *level,
+              entry_t *entry,
+              apr_uint32_t idx)
+{
+  assert(idx == get_index(cache, entry));
+
+  /* update 
+   */
+  if (level->next == idx)
+    level->next = entry->next;
+  
+  /* unlink it from the chain of used entries
+   */
+  if (entry->previous == NO_INDEX)
+    level->first = entry->next;
+  else
+    get_entry(cache, entry->previous)->next = entry->next;
+
+  if (entry->next == NO_INDEX)
+    level->last = entry->previous;
+  else
+    get_entry(cache, entry->next)->previous = entry->previous;
+}
+
 /* Remove the used ENTRY from the CACHE, i.e. make it "unused".
  * In contrast to insertion, removal is possible for any entry.
  */
@@ -637,6 +767,7 @@ drop_entry(svn_membuffer_t *cache, entry
   apr_uint32_t group_index = idx / GROUP_SIZE;
   entry_group_t *group = &cache->directory[group_index];
   apr_uint32_t last_in_group = group_index * GROUP_SIZE + group->used - 1;
+  cache_level_t *level = get_cache_level(cache, entry);
 
   /* Only valid to be called for used entries.
    */
@@ -650,39 +781,31 @@ drop_entry(svn_membuffer_t *cache, entry
 
   /* extend the insertion window, if the entry happens to border it
    */
-  if (idx == cache->next)
-    cache->next = entry->next;
+  if (idx == level->next)
+    level->next = entry->next;
   else
-    if (entry->next == cache->next)
+    if (entry->next == level->next)
       {
         /* insertion window starts right behind the entry to remove
          */
         if (entry->previous == NO_INDEX)
           {
             /* remove the first entry -> insertion may start at pos 0, now */
-            cache->current_data = 0;
+            level->current_data = level->start_offset;
           }
         else
           {
             /* insertion may start right behind the previous entry */
             entry_t *previous = get_entry(cache, entry->previous);
-            cache->current_data = ALIGN_VALUE(  previous->offset
+            level->current_data = ALIGN_VALUE(  previous->offset
                                               + previous->size);
           }
       }
 
   /* unlink it from the chain of used entries
    */
-  if (entry->previous == NO_INDEX)
-    cache->first = entry->next;
-  else
-    get_entry(cache, entry->previous)->next = entry->next;
-
-  if (entry->next == NO_INDEX)
-    cache->last = entry->previous;
-  else
-    get_entry(cache, entry->next)->previous = entry->previous;
-
+  unchain_entry(cache, level, entry, idx);
+  
   /* Move last entry into hole (if the removed one is not the last used).
    * We need to do this since all used entries are at the beginning of
    * the group's entries array.
@@ -693,18 +816,22 @@ drop_entry(svn_membuffer_t *cache, entry
        */
       *entry = group->entries[group->used-1];
 
+      /* this ENTRY may belong to a different cache level than the entry
+       * we have just removed */
+      level = get_cache_level(cache, entry);
+
       /* update foreign links to new index
        */
-      if (last_in_group == cache->next)
-        cache->next = idx;
+      if (last_in_group == level->next)
+        level->next = idx;
 
       if (entry->previous == NO_INDEX)
-        cache->first = idx;
+        level->first = idx;
       else
         get_entry(cache, entry->previous)->next = idx;
-      
+
       if (entry->next == NO_INDEX)
-        cache->last = idx;
+        level->last = idx;
       else
         get_entry(cache, entry->next)->previous = idx;
     }
@@ -726,16 +853,14 @@ insert_entry(svn_membuffer_t *cache, ent
   apr_uint32_t idx = get_index(cache, entry);
   apr_uint32_t group_index = idx / GROUP_SIZE;
   entry_group_t *group = &cache->directory[group_index];
-  entry_t *next = cache->next == NO_INDEX
-                ? NULL
-                : get_entry(cache, cache->next);
+  cache_level_t *level = get_cache_level(cache, entry);
 
   /* The entry must start at the beginning of the insertion window.
    * It must also be the first unused entry in the group.
    */
-  assert(entry->offset == cache->current_data);
+  assert(entry->offset == level->current_data);
   assert(idx == group_index * GROUP_SIZE + group->used);
-  cache->current_data = ALIGN_VALUE(entry->offset + entry->size);
+  level->current_data = ALIGN_VALUE(entry->offset + entry->size);
 
   /* update usage counters
    */
@@ -746,42 +871,12 @@ insert_entry(svn_membuffer_t *cache, ent
 
   /* update entry chain
    */
-  entry->next = cache->next;
-  if (cache->first == NO_INDEX)
-    {
-      /* insert as the first entry and only in the chain
-       */
-      entry->previous = NO_INDEX;
-      cache->last = idx;
-      cache->first = idx;
-    }
-  else if (next == NULL)
-    {
-      /* insert as the last entry in the chain.
-       * Note that it cannot also be at the beginning of the chain.
-       */
-      entry->previous = cache->last;
-      get_entry(cache, cache->last)->next = idx;
-      cache->last = idx;
-    }
-  else
-    {
-      /* insert either at the start of a non-empty list or
-       * somewhere in the middle
-       */
-      entry->previous = next->previous;
-      next->previous = idx;
-
-      if (entry->previous != NO_INDEX)
-        get_entry(cache, entry->previous)->next = idx;
-      else
-        cache->first = idx;
-    }
+  chain_entry(cache, level, entry, idx);
 
   /* The current insertion position must never point outside our
    * data buffer.
    */
-  assert(cache->current_data <= cache->data_size);
+  assert(level->current_data <= level->start_offset + level->size);
 }
 
 /* Map a KEY of 16 bytes to the CACHE and group that shall contain the
@@ -792,7 +887,7 @@ get_group_index(svn_membuffer_t **cache,
                 entry_key_t key)
 {
   svn_membuffer_t *segment0 = *cache;
-  
+
   /* select the cache segment to use. they have all the same group_count */
   *cache = &segment0[key[0] & (segment0->segment_count -1)];
   return key[1] % segment0->group_count;
@@ -955,6 +1050,7 @@ static void
 move_entry(svn_membuffer_t *cache, entry_t *entry)
 {
   apr_size_t size = ALIGN_VALUE(entry->size);
+  cache_level_t *level = get_cache_level(cache, entry);
 
   /* This entry survived this cleansing run. Reset half of its
    * hit count so that its removal gets more likely in the next
@@ -968,36 +1064,66 @@ move_entry(svn_membuffer_t *cache, entry
    * Size-aligned moves tend to be faster than non-aligned ones
    * because no "odd" bytes at the end need to special treatment.
    */
-  if (entry->offset != cache->current_data)
+  if (entry->offset != level->current_data)
     {
-      memmove(cache->data + cache->current_data,
+      memmove(cache->data + level->current_data,
               cache->data + entry->offset,
               size);
-      entry->offset = cache->current_data;
+      entry->offset = level->current_data;
     }
 
   /* The insertion position is now directly behind this entry.
    */
-  cache->current_data = entry->offset + size;
-  cache->next = entry->next;
+  level->current_data = entry->offset + size;
+  level->next = entry->next;
 
   /* The current insertion position must never point outside our
    * data buffer.
    */
-  assert(cache->current_data <= cache->data_size);
+  assert(level->current_data <= level->start_offset + level->size);
 }
 
-/* If necessary, enlarge the insertion window until it is at least
- * SIZE bytes long.  SIZE must not exceed the data buffer size.  The
- * new item will be of the given PRIORITY class.
- *
- * Return TRUE if enough room could be found or made. A FALSE result
+/* Move ENTRY in CACHE from L1 to L2.
+ */
+static void
+promote_entry(svn_membuffer_t *cache, entry_t *entry)
+{
+  apr_uint32_t idx = get_index(cache, entry);
+  apr_size_t size = ALIGN_VALUE(entry->size);
+  assert(get_cache_level(cache, entry) == &cache->l1);
+
+  /* copy item from the current location in L1 to the start of L2's
+   * insertion window */
+  memmove(cache->data + cache->l2.current_data,
+          cache->data + entry->offset,
+          size);
+  entry->offset = cache->l2.current_data;
+
+  /* The insertion position is now directly behind this entry.
+   */
+  cache->l2.current_data += size;
+
+  /* remove ENTRY from chain of L1 entries and put it into L2
+   */
+  unchain_entry(cache, &cache->l1, entry, idx);
+  chain_entry(cache, &cache->l2, entry, idx);
+}
+
+/* This function implements the cache insertion / eviction strategy for L2.
+ * 
+ * If necessary, enlarge the insertion window of CACHE->L2 until it is at
+ * least TO_FIT_IN->SIZE bytes long. TO_FIT_IN->SIZE must not exceed the
+ * data buffer size allocated to CACHE->L2.  IDX is the item index of
+ * TO_FIT_IN and is given for performance reasons.
+ * 
+ * Return TRUE if enough room could be found or made.  A FALSE result
+>>>>>>> .merge-right.r1476664
  * indicates that the respective item shall not be added.
  */
 static svn_boolean_t
-ensure_data_insertable(svn_membuffer_t *cache,
-                       apr_uint32_t priority,
-                       apr_size_t size)
+ensure_data_insertable_l2(svn_membuffer_t *cache,
+                          entry_t *to_fit_in,
+                          apr_uint32_t idx)
 {
   entry_t *entry;
   apr_uint64_t average_hit_value;
@@ -1008,6 +1134,12 @@ ensure_data_insertable(svn_membuffer_t *
    */
   apr_size_t moved_size = 0;
 
+  /* accumulated "worth" of items dropped so far */
+  apr_size_t drop_hits = 0;
+
+  /* verify parameters */
+  assert(idx == get_index(cache, to_fit_in));
+
   /* This loop will eventually terminate because every cache entry
    * would get dropped eventually:
    * - hit counts become 0 after the got kept for 32 full scans
@@ -1024,38 +1156,44 @@ ensure_data_insertable(svn_membuffer_t *
     {
       /* first offset behind the insertion window
        */
-      apr_uint64_t end = cache->next == NO_INDEX
-                       ? cache->data_size
-                       : get_entry(cache, cache->next)->offset;
+      apr_uint64_t end = cache->l2.next == NO_INDEX
+                       ? cache->l2.start_offset + cache->l2.size
+                       : get_entry(cache, cache->l2.next)->offset;
 
       /* leave function as soon as the insertion window is large enough
        */
-      if (end >= size + cache->current_data)
+      if (end >= to_fit_in->size + cache->l2.current_data)
         return TRUE;
 
       /* Don't be too eager to cache data.  If a lot of data has been 
        * moved around, the current item has probably a relatively low
        * priority.  So, give up after some time.
        */
-      if (moved_size > 16 * size)
+      if (moved_size > 16 * to_fit_in->size)
+        return FALSE;
+
+      /* if the net worth (in hits) of items removed is already larger
+       * than what we want to insert, reject TO_FIT_IN because it still
+       * does not fit in.
+      if (drop_hits > to_fit_in->hit_count)
         return FALSE;
 
       /* try to enlarge the insertion window
        */
-      if (cache->next == NO_INDEX)
+      if (cache->l2.next == NO_INDEX)
         {
           /* We reached the end of the data buffer; restart at the beginning.
            * Due to the randomized nature of our LFU implementation, very
            * large data items may require multiple passes. Therefore, SIZE
            * should be restricted to significantly less than data_size.
            */
-          cache->current_data = 0;
-          cache->next = cache->first;
+          cache->l2.current_data = cache->l2.start_offset;
+          cache->l2.next = cache->l2.first;
         }
       else
         {
           svn_boolean_t keep;
-          entry = get_entry(cache, cache->next);
+          entry = get_entry(cache, cache->l2.next);
 
           /* Keep entries that are very small. Those are likely to be data
            * headers or similar management structures. So, they are probably
@@ -1067,10 +1205,20 @@ ensure_data_insertable(svn_membuffer_t *
             {
               keep = TRUE;
             }
-          else if (priority != entry->priority)
+          else if (cache->l2.next / GROUP_SIZE == idx / GROUP_SIZE)
+            {
+              /* Special case: we cannot drop entries that are in the same
+               * group as TO_FIT_IN because that might the latter to become
+               * invalidated it it happens to be the highest used entry in
+               * the group.  So, we must keep ENTRY unconditionally.
+               * (this is a very rare condition)
+               */
+              keep = TRUE;
+            }
+          else if (to_fit_in->priority != entry->priority)
             {
               /* strictly let the higher priority win */
-              keep = entry->priority > priority;
+              keep = entry->priority > to_fit_in->priority;
             }
           else if (cache->hit_count > cache->used_entries)
             {
@@ -1103,6 +1251,7 @@ ensure_data_insertable(svn_membuffer_t *
                * has been hit less than the threshold. Otherwise, keep it and
                * move the insertion window one entry further.
                */
+              drop_hits += entry->hit_count;
               drop_entry(cache, entry);
             }
         }
@@ -1112,6 +1261,72 @@ ensure_data_insertable(svn_membuffer_t *
    * right answer. */
 }
 
+/* This function implements the cache insertion / eviction strategy for L1.
+ *
+ * If necessary, enlarge the insertion window of CACHE->L1 by promoting
+ * entries to L2 until it is at least SIZE bytes long.
+ *
+ * Return TRUE if enough room could be found or made. A FALSE result
+ *
+ * Return TRUE if enough room could be found or made.  A FALSE result
+ * indicates that the respective item shall not be added because it is
+ * too large.
+ */
+static svn_boolean_t
+ensure_data_insertable_l1(svn_membuffer_t *cache, apr_size_t size)
+{
+  entry_t *entry;
+
+  /* Guarantees that the while loop will terminate. */
+  if (size > cache->l1.size)
+    return FALSE;
+
+  /* This loop will eventually terminate because every cache entry
+   * would get dropped eventually.
+   */
+  while (1)
+    {
+      /* first offset behind the insertion window
+       */
+      apr_uint64_t end = cache->l1.next == NO_INDEX
+                       ? cache->l1.start_offset + cache->l1.size
+                       : get_entry(cache, cache->l1.next)->offset;
+
+      /* leave function as soon as the insertion window is large enough
+       */
+      if (end >= size + cache->l1.current_data)
+        return TRUE;
+
+      /* Enlarge the insertion window
+       */
+      if (cache->l1.next == NO_INDEX)
+        {
+          /* We reached the end of the data buffer; restart at the beginning.
+           * Due to the randomized nature of our LFU implementation, very
+           * large data items may require multiple passes. Therefore, SIZE
+           * should be restricted to significantly less than data_size.
+           */
+          cache->l1.current_data = cache->l1.start_offset;
+          cache->l1.next = cache->l1.first;
+        }
+      else
+        {
+          /* Remove the entry from the end of insertion window and promote
+           * it to L2, if it is important enough.
+           */
+          entry = get_entry(cache, cache->l1.next);
+
+          if (ensure_data_insertable_l2(cache, entry, cache->l1.next))
+            promote_entry(cache, entry);
+          else
+            drop_entry(cache, entry);
+        }
+    }
+
+  /* This will never be reached. But if it was, "can't insert" was the
+   * right answer. */
+}
+
 /* Mimic apr_pcalloc in APR_POOL_DEBUG mode, i.e. handle failed allocations
  * (e.g. OOM) properly: Allocate at least SIZE bytes from POOL and zero
  * the content of the allocated memory if ZERO has been set. Return NULL
@@ -1164,7 +1379,7 @@ svn_cache__membuffer_cache_create(svn_me
     segment_count = MAX_SEGMENT_COUNT;
   if (segment_count * MIN_SEGMENT_SIZE > total_size)
     segment_count = total_size / MIN_SEGMENT_SIZE;
-    
+
   /* The segment count must be a power of two. Round it down as necessary.
    */
   while ((segment_count & (segment_count-1)) != 0)
@@ -1231,13 +1446,13 @@ svn_cache__membuffer_cache_create(svn_me
    */
   data_size = ALIGN_VALUE(total_size - directory_size + 1) - ITEM_ALIGNMENT;
 
-  /* For cache sizes > 4TB, individual cache segments will be larger
-   * than 16GB allowing for >4GB entries.  But caching chunks larger
-   * than 4GB is simply not supported.
+  /* For cache sizes > 16TB, individual cache segments will be larger
+   * than 32GB allowing for >4GB entries.  But caching chunks larger
+   * than 4GB are simply not supported.
    */
-  max_entry_size = data_size / 4 > MAX_ITEM_SIZE
+  max_entry_size = data_size / 8 > MAX_ITEM_SIZE
                  ? MAX_ITEM_SIZE
-                 : data_size / 4;
+                 : data_size / 8;
 
   /* to keep the entries small, we use 32 bit indexes only
    * -> we need to ensure that no more then 4G entries exist.
@@ -1265,13 +1480,25 @@ svn_cache__membuffer_cache_create(svn_me
          hence "unused" */
       c[seg].group_initialized = apr_pcalloc(pool, group_init_size);
 
-      c[seg].first = NO_INDEX;
-      c[seg].last = NO_INDEX;
-      c[seg].next = NO_INDEX;
+      /* Allocate 1/4th of the data buffer to L1
+       */
+      c[seg].l1.first = NO_INDEX;
+      c[seg].l1.last = NO_INDEX;
+      c[seg].l1.next = NO_INDEX;
+      c[seg].l1.start_offset = 0;
+      c[seg].l1.size = ALIGN_VALUE(data_size / 4);
+      c[seg].l1.current_data = 0;
+
+      /* The remaining 3/4th will be used as L2
+       */
+      c[seg].l2.first = NO_INDEX;
+      c[seg].l2.last = NO_INDEX;
+      c[seg].l2.next = NO_INDEX;
+      c[seg].l2.start_offset = c[seg].l1.size;
+      c[seg].l2.size = data_size - c[seg].l1.size;
+      c[seg].l2.current_data = c[seg].l2.start_offset;
 
-      c[seg].data_size = data_size;
       c[seg].data = secure_aligned_alloc(pool, (apr_size_t)data_size, FALSE);
-      c[seg].current_data = 0;
       c[seg].data_used = 0;
       c[seg].max_entry_size = max_entry_size;
 
@@ -1405,7 +1632,7 @@ membuffer_cache_set_internal(svn_membuff
    */
   if (   buffer != NULL
       && cache->max_entry_size >= size
-      && ensure_data_insertable(cache, priority, size))
+      && ensure_data_insertable_l1(cache, size))
     {
       /* Remove old data for this key, if that exists.
        * Get an unused entry for the key and and initialize it with
@@ -1413,7 +1640,7 @@ membuffer_cache_set_internal(svn_membuff
        */
       entry = find_entry(cache, group_index, to_find, TRUE);
       entry->size = size;
-      entry->offset = cache->current_data;
+      entry->offset = cache->l1.current_data;
       entry->priority = priority;
 
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER
@@ -1807,13 +2034,13 @@ membuffer_cache_set_partial_internal(svn
               apr_uint32_t priority = entry->priority;
               drop_entry(cache, entry);
               if (   (cache->max_entry_size >= size)
-                  && ensure_data_insertable(cache, priority, size))
+                  && ensure_data_insertable_l1(cache, size))
                 {
                   /* Write the new entry.
                    */
                   entry = find_entry(cache, group_index, to_find, TRUE);
                   entry->size = size;
-                  entry->offset = cache->current_data;
+                  entry->offset = cache->l1.current_data;
                   if (size)
                     memcpy(cache->data + entry->offset, data, size);
 
@@ -2198,9 +2425,9 @@ static svn_error_t *
 svn_membuffer_get_segment_info(svn_membuffer_t *segment,
                                svn_cache__info_t *info)
 {
-  info->data_size += segment->data_size;
+  info->data_size += segment->l1.size + segment->l2.size;
   info->used_size += segment->data_used;
-  info->total_size += segment->data_size +
+  info->total_size += segment->l1.size + segment->l2.size +
       segment->group_count * GROUP_SIZE * sizeof(entry_t);
 
   info->used_entries += segment->used_entries;
@@ -2470,6 +2697,7 @@ svn_cache__create_membuffer_cache(svn_ca
   wrapper->cache_internal = cache;
   wrapper->error_handler = 0;
   wrapper->error_baton = 0;
+  wrapper->pretend_empty = !!getenv("SVN_X_DOES_NOT_MARK_THE_SPOT");
 
   *cache_p = wrapper;
   return SVN_NO_ERROR;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-memcache.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-memcache.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-memcache.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-memcache.c Sat Apr 27 21:30:36 2013
@@ -428,6 +428,7 @@ svn_cache__create_memcache(svn_cache__t 
   wrapper->cache_internal = cache;
   wrapper->error_handler = 0;
   wrapper->error_baton = 0;
+  wrapper->pretend_empty = !!getenv("SVN_X_DOES_NOT_MARK_THE_SPOT");
 
   *cache_p = wrapper;
   return SVN_NO_ERROR;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/cache.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/cache.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/cache.c Sat Apr 27 21:30:36 2013
@@ -76,7 +76,7 @@ svn_cache__get(void **value_p,
      out with FOUND set to false. */
   *found = FALSE;
 #ifdef SVN_DEBUG
-  if (getenv("SVN_X_DOES_NOT_MARK_THE_SPOT"))
+  if (cache->pretend_empty)
     return SVN_NO_ERROR;
 #endif
 
@@ -134,7 +134,7 @@ svn_cache__iter(svn_boolean_t *completed
                 apr_pool_t *scratch_pool)
 {
 #ifdef SVN_DEBUG
-  if (getenv("SVN_X_DOES_NOT_MARK_THE_SPOT"))
+  if (cache->pretend_empty)
     /* Pretend CACHE is empty. */
     return SVN_NO_ERROR;
 #endif
@@ -161,7 +161,7 @@ svn_cache__get_partial(void **value,
   out with FOUND set to false. */
   *found = FALSE;
 #ifdef SVN_DEBUG
-  if (getenv("SVN_X_DOES_NOT_MARK_THE_SPOT"))
+  if (cache->pretend_empty)
     return SVN_NO_ERROR;
 #endif
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/cache.h?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/cache.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/cache.h Sat Apr 27 21:30:36 2013
@@ -105,6 +105,10 @@ struct svn_cache__t {
 
   /* Total number of function calls that returned an error. */
   apr_uint64_t failures;
+
+  /* Cause all getters to act as though the cache contains no data.
+     (Currently this never becomes set except in maintainer builds.) */
+  svn_boolean_t pretend_empty;
 };
 
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/cmdline.c?rev=1476675&r1=1476674&r2=1476675&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/cmdline.c Sat Apr 27 21:30:36 2013
@@ -946,7 +946,7 @@ svn_cmdline__be_interactive(svn_boolean_
       return (isatty(STDIN_FILENO) != 0);
 #endif
     }
-  else if (force_interactive) 
+  else if (force_interactive)
     return TRUE;
 
   return !non_interactive;



Mime
View raw message