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 *