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 2012/08/22 22:47:10 UTC

svn commit: r1376228 - in /subversion/trunk/subversion: include/ libsvn_fs/ libsvn_fs_base/ libsvn_fs_fs/ libsvn_repos/ svnadmin/

Author: philip
Date: Wed Aug 22 20:47:09 2012
New Revision: 1376228

URL: http://svn.apache.org/viewvc?rev=1376228&view=rev
Log:
Implement 'svnadmin freeze REPOS_PATH PROGRAM [ARG...]'.

* subversion/include/svn_repos.h
  (svn_repos_freeze): New.

* subversion/libsvn_repos/repos.c
  (svn_repos_freeze): New.

* subversion/include/svn_fs.h
  (svn_fs_freeze): New.

* subversion/libsvn_fs/fs-loader.h
  (struct fs_vtable_t): Add freeze.

* subversion/libsvn_fs/fs-loader.c
  (svn_fs_freeze): New.

* subversion/libsvn_fs_base/fs.c
  (base_bdb_freeze): New.
  (fs_vtable): Add base_bdb_freeze.

* subversion/libsvn_fs_fs/fs.c
  (struct fs_freeze_baton_t, fs_freeze_body, fs_freeze): New.
  (fs_vtable): Add fs_freeze.

* subversion/libsvn_fs_fs/rep-cache.h
  (svn_fs_fs__lock_rep_cache): New.

* subversion/libsvn_fs_fs/rep-cache.c
  (svn_fs_fs__lock_rep_cache): New.

* subversion/libsvn_fs_fs/rep-cache-db.sql
  (STMT_LOCK_REP): New.

* subversion/svnadmin/main.c
  (cmd_table): Add freeze command.
  (freeze_body, subcommand_freeze): New.

Modified:
    subversion/trunk/subversion/include/svn_fs.h
    subversion/trunk/subversion/include/svn_repos.h
    subversion/trunk/subversion/libsvn_fs/fs-loader.c
    subversion/trunk/subversion/libsvn_fs/fs-loader.h
    subversion/trunk/subversion/libsvn_fs_base/fs.c
    subversion/trunk/subversion/libsvn_fs_fs/fs.c
    subversion/trunk/subversion/libsvn_fs_fs/rep-cache-db.sql
    subversion/trunk/subversion/libsvn_fs_fs/rep-cache.c
    subversion/trunk/subversion/libsvn_fs_fs/rep-cache.h
    subversion/trunk/subversion/libsvn_repos/repos.c
    subversion/trunk/subversion/svnadmin/main.c

Modified: subversion/trunk/subversion/include/svn_fs.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_fs.h?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_fs.h (original)
+++ subversion/trunk/subversion/include/svn_fs.h Wed Aug 22 20:47:09 2012
@@ -402,6 +402,24 @@ svn_fs_recover(const char *path,
                apr_pool_t *pool);
 
 
+/**
+ * Take an exclusive lock on @a fs to prevent commits and then invoke
+ * @a freeze_body passing @a baton.
+ *
+ * @note The BDB backend doesn't implement this feature so most
+ * callers should not call this function directly but should use the
+ * higher level #svn_repos_freeze instead.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_fs_freeze(svn_fs_t *fs,
+              svn_error_t *(*freeze_body)(void *baton, apr_pool_t *pool),
+              void *baton,
+              apr_pool_t *pool);
+              
+
+
 /** Subversion filesystems based on Berkeley DB.
  *
  * The following functions are specific to Berkeley DB filesystems.

Modified: subversion/trunk/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_repos.h?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_repos.h (original)
+++ subversion/trunk/subversion/include/svn_repos.h Wed Aug 22 20:47:09 2012
@@ -653,6 +653,20 @@ svn_error_t *
 svn_repos_recover(const char *path,
                   apr_pool_t *pool);
 
+/**
+ * Take an exclusive lock on @a path to prevent commits and then
+ * invoke @a freeze_body passing @a baton.  The repository may be
+ * readable by Subversion while frozen, or it may be unreadable,
+ * depending on which FS backend the repository uses.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_repos_freeze(const char *path,
+                 svn_error_t *(*freeze_body)(void *baton, apr_pool_t *pool),
+                 void *baton,
+                 apr_pool_t *pool);
+
 /** This function is a wrapper around svn_fs_berkeley_logfiles(),
  * returning log file paths relative to the root of the repository.
  *

Modified: subversion/trunk/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs/fs-loader.c?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/trunk/subversion/libsvn_fs/fs-loader.c Wed Aug 22 20:47:09 2012
@@ -624,6 +624,17 @@ svn_fs_recover(const char *path,
                                          pool));
 }
 
+svn_error_t *
+svn_fs_freeze(svn_fs_t *fs,
+              svn_error_t *(*freeze_body)(void *baton, apr_pool_t *pool),
+              void *baton,
+              apr_pool_t *pool)
+{
+  SVN_ERR(fs->vtable->freeze(fs, freeze_body, baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* --- Berkeley-specific functions --- */
 

Modified: subversion/trunk/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs/fs-loader.h?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/trunk/subversion/libsvn_fs/fs-loader.h Wed Aug 22 20:47:09 2012
@@ -202,6 +202,9 @@ typedef struct fs_vtable_t
                             svn_fs_get_locks_callback_t get_locks_func,
                             void *get_locks_baton,
                             apr_pool_t *pool);
+  svn_error_t *(*freeze)(svn_fs_t *fs,
+                         svn_error_t *(*freeze_body)(void *, apr_pool_t *),
+                         void *baton, apr_pool_t *pool);
   svn_error_t *(*bdb_set_errcall)(svn_fs_t *fs,
                                   void (*handler)(const char *errpfx,
                                                   char *msg));

Modified: subversion/trunk/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/fs.c?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/trunk/subversion/libsvn_fs_base/fs.c Wed Aug 22 20:47:09 2012
@@ -471,6 +471,14 @@ bdb_write_config(svn_fs_t *fs)
   return svn_io_file_close(dbconfig_file, fs->pool);
 }
 
+static svn_error_t *
+base_bdb_freeze(svn_fs_t *fs,
+                svn_error_t *(*freeze_body)(void *, apr_pool_t *),
+                void *baton,
+                apr_pool_t *pool)
+{
+  SVN__NOT_IMPLEMENTED();
+}
 
 
 /* Creating a new filesystem */
@@ -492,6 +500,7 @@ static fs_vtable_t fs_vtable = {
   svn_fs_base__unlock,
   svn_fs_base__get_lock,
   svn_fs_base__get_locks,
+  base_bdb_freeze,
   base_bdb_set_errcall,
 };
 

Modified: subversion/trunk/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/fs.c?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/fs.c Wed Aug 22 20:47:09 2012
@@ -38,6 +38,7 @@
 #include "tree.h"
 #include "lock.h"
 #include "id.h"
+#include "rep-cache.h"
 #include "svn_private_config.h"
 #include "private/svn_fs_util.h"
 
@@ -123,6 +124,46 @@ fs_set_errcall(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+struct fs_freeze_baton_t {
+  svn_fs_t *fs;
+  svn_error_t *(*freeze_body)(void *, apr_pool_t *);
+  void *baton;
+};
+
+static svn_error_t *
+fs_freeze_body(void *baton,
+               apr_pool_t *pool)
+{
+  struct fs_freeze_baton_t *b = baton;
+  svn_boolean_t exists;
+
+  SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, b->fs, pool));
+  if (exists)
+    SVN_ERR(svn_fs_fs__lock_rep_cache(b->fs, pool));
+
+  SVN_ERR(b->freeze_body(b->baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fs_freeze(svn_fs_t *fs,
+          svn_error_t *(*freeze_body)(void *, apr_pool_t *),
+          void *baton,
+          apr_pool_t *pool)
+{
+  struct fs_freeze_baton_t b;
+
+  b.fs = fs;
+  b.freeze_body = freeze_body;
+  b.baton = baton;
+
+  SVN_ERR(svn_fs__check_fs(fs, TRUE));
+  SVN_ERR(svn_fs_fs__with_write_lock(fs, fs_freeze_body, &b, pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 
 /* The vtable associated with a specific open filesystem. */
@@ -143,6 +184,7 @@ static fs_vtable_t fs_vtable = {
   svn_fs_fs__unlock,
   svn_fs_fs__get_lock,
   svn_fs_fs__get_locks,
+  fs_freeze,
   fs_set_errcall
 };
 

Modified: subversion/trunk/subversion/libsvn_fs_fs/rep-cache-db.sql
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/rep-cache-db.sql?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/rep-cache-db.sql (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/rep-cache-db.sql Wed Aug 22 20:47:09 2012
@@ -57,3 +57,11 @@ FROM rep_cache
 -- STMT_DEL_REPS_YOUNGER_THAN_REV
 DELETE FROM rep_cache
 WHERE revision > ?1
+
+/* An INSERT takes an SQLite reserved lock that prevents other writes
+   but doesn't block reads.  The incomplete transaction means that no
+   permanent change is made to the database and the transaction is
+   removed when the database is closed.  */
+-- STMT_LOCK_REP
+BEGIN TRANSACTION;
+INSERT INTO rep_cache VALUES ('dummy', 0, 0, 0, 0)

Modified: subversion/trunk/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/rep-cache.c?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/rep-cache.c Wed Aug 22 20:47:09 2012
@@ -351,3 +351,17 @@ svn_fs_fs__del_rep_reference(svn_fs_t *f
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_fs_fs__lock_rep_cache(svn_fs_t *fs,
+                          apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  if (! ffd->rep_cache_db)
+    SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool));
+
+  SVN_ERR(svn_sqlite__exec_statements(ffd->rep_cache_db, STMT_LOCK_REP));
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/trunk/subversion/libsvn_fs_fs/rep-cache.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/rep-cache.h?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/rep-cache.h (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/rep-cache.h Wed Aug 22 20:47:09 2012
@@ -88,6 +88,12 @@ svn_fs_fs__del_rep_reference(svn_fs_t *f
                              svn_revnum_t youngest,
                              apr_pool_t *pool);
 
+/* Start a transaction to take an SQLite reserved lock that prevents
+   other writes. */
+svn_error_t *
+svn_fs_fs__lock_rep_cache(svn_fs_t *fs,
+                          apr_pool_t *pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/trunk/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/repos.c?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/repos.c (original)
+++ subversion/trunk/subversion/libsvn_repos/repos.c Wed Aug 22 20:47:09 2012
@@ -1690,6 +1690,47 @@ svn_repos_recover4(const char *path,
   return SVN_NO_ERROR;
 }
 
+/* For BDB we fall back on BDB's repos layer lock which means that the
+   repository is unreadable while frozen.
+
+   For FSFS we delegate to the FS layer which uses the FSFS write-lock
+   and an SQLite reserved lock which means the repository is readable
+   while frozen. */
+svn_error_t *
+svn_repos_freeze(const char *path,
+                 svn_error_t *(*freeze_body)(void *, apr_pool_t *),
+                 void *baton,
+                 apr_pool_t *pool)
+{
+  svn_repos_t *repos;
+
+  /* Using a subpool as the only way to unlock the repos lock used by
+     BDB is to clear the pool used to take the lock. */
+  apr_pool_t *subpool = svn_pool_create(pool);
+
+  SVN_ERR(get_repos(&repos, path,
+                    TRUE  /* exclusive */,
+                    FALSE /* non-blocking */,
+                    FALSE /* open-fs */,
+                    NULL, subpool));
+
+  if (strcmp(repos->fs_type, SVN_FS_TYPE_BDB) == 0)
+    {
+      svn_error_t *err = freeze_body(baton, subpool);
+      svn_pool_destroy(subpool);
+      return err;
+    }
+  else
+    {
+      SVN_ERR(svn_fs_open(&repos->fs, repos->db_path, NULL, subpool));
+      SVN_ERR(svn_fs_freeze(svn_repos_fs(repos), freeze_body, baton, subpool));
+    }
+
+  svn_pool_destroy(subpool);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *svn_repos_db_logfiles(apr_array_header_t **logfiles,
                                    const char *path,
                                    svn_boolean_t only_unused,

Modified: subversion/trunk/subversion/svnadmin/main.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnadmin/main.c?rev=1376228&r1=1376227&r2=1376228&view=diff
==============================================================================
--- subversion/trunk/subversion/svnadmin/main.c (original)
+++ subversion/trunk/subversion/svnadmin/main.c Wed Aug 22 20:47:09 2012
@@ -150,6 +150,7 @@ static svn_opt_subcommand_t
   subcommand_create,
   subcommand_deltify,
   subcommand_dump,
+  subcommand_freeze,
   subcommand_help,
   subcommand_hotcopy,
   subcommand_load,
@@ -336,6 +337,11 @@ static const svn_opt_subcommand_desc2_t 
     "changed in those revisions.)\n"),
   {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M'} },
 
+  {"freeze", subcommand_freeze, {0}, N_
+   ("usage: svnadmin freeze REPOS_PATH PROGRAM [ARG...]\n\n"
+    "Run PROGRAM passing ARGS while holding a write-lock on REPOS_PATH.\n"),
+   {0} },
+
   {"help", subcommand_help, {"?", "h"}, N_
    ("usage: svnadmin help [SUBCOMMAND...]\n\n"
     "Describe the usage of this program or its subcommands.\n"),
@@ -969,6 +975,66 @@ subcommand_dump(apr_getopt_t *os, void *
   return SVN_NO_ERROR;
 }
 
+struct freeze_baton_t {
+  const char *command;
+  const char **args;
+  int status;
+};
+
+static svn_error_t *
+freeze_body(void *baton,
+            apr_pool_t *pool)
+{
+  struct freeze_baton_t *b = baton;
+  apr_status_t apr_err;
+  apr_file_t *infile, *outfile, *errfile;
+
+  apr_err = apr_file_open_stdin(&infile, pool);
+  if (apr_err)
+    return svn_error_wrap_apr(apr_err, "Can't open stdin");
+  apr_err = apr_file_open_stdout(&outfile, pool);
+  if (apr_err)
+    return svn_error_wrap_apr(apr_err, "Can't open stdout");
+  apr_err = apr_file_open_stderr(&errfile, pool);
+  if (apr_err)
+    return svn_error_wrap_apr(apr_err, "Can't open stderr");
+
+  SVN_ERR(svn_io_run_cmd(NULL, b->command, b->args, &b->status,
+                         NULL, TRUE,
+                         infile, outfile, errfile, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+subcommand_freeze(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  struct svnadmin_opt_state *opt_state = baton;
+  apr_array_header_t *args;
+  int i;
+  struct freeze_baton_t b;
+
+  SVN_ERR(svn_opt_parse_all_args(&args, os, pool));
+
+  if (!args->nelts)
+    return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0,
+                            _("No program provided"));
+
+  b.command = APR_ARRAY_IDX(args, 0, const char *);
+  b.args = apr_palloc(pool, sizeof(char *) * args->nelts + 1);
+  for (i = 0; i < args->nelts; ++i)
+    b.args[i] = APR_ARRAY_IDX(args, i, const char *);
+  b.args[args->nelts] = NULL;
+
+  SVN_ERR(svn_repos_freeze(opt_state->repository_path, freeze_body, &b, pool));
+
+  /* Make any non-zero status visible to the user. */
+  if (b.status)
+    exit(b.status);
+
+  return SVN_NO_ERROR;
+}
+
 
 /* This implements `svn_opt_subcommand_t'. */
 static svn_error_t *