This commit accidentally included unrelated changes to fs_fs.c for the
node-ID cache which aren't ready yet. I need to go now (I've spent
hours beating my head against a segfault I found in trying to
investigate), but can somebody revert this, do the merge described in
the log message, commit that, and nominate *that* for backport?
--dave
On Feb 1, 2008 11:53 AM, <cmpilato_at_tigris.org> wrote:
> Author: cmpilato
> Date: Fri Feb 1 11:53:37 2008
> New Revision: 29139
>
> Log:
> Merge all changes (r29086:29138) from the 'svnadmin-upgrade' branch,
> introducing (of all things) a new 'svnadmin upgrade' subcommand and
> backing APIs.
>
> (Merged branches/svnadmin-upgrade:29087-29138.)
>
>
> Modified:
> trunk/subversion/include/svn_error_codes.h
> trunk/subversion/include/svn_fs.h
> trunk/subversion/include/svn_repos.h
> trunk/subversion/libsvn_fs/fs-loader.c
> trunk/subversion/libsvn_fs/fs-loader.h
> trunk/subversion/libsvn_fs_base/fs.c
> trunk/subversion/libsvn_fs_fs/fs.c
> trunk/subversion/libsvn_fs_fs/fs_fs.c
> trunk/subversion/libsvn_fs_fs/fs_fs.h
> trunk/subversion/libsvn_repos/repos.c
> trunk/subversion/svnadmin/main.c
>
> Modified: trunk/subversion/include/svn_error_codes.h
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/include/svn_error_codes.h?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/include/svn_error_codes.h (original)
> +++ trunk/subversion/include/svn_error_codes.h Fri Feb 1 11:53:37 2008
> @@ -640,6 +640,11 @@
> SVN_ERR_FS_CATEGORY_START + 46,
> "Filesystem has no such node origin record")
>
> + /** @since New in 1.5. */
> + SVN_ERRDEF(SVN_ERR_FS_UNSUPPORTED_UPGRADE,
> + SVN_ERR_FS_CATEGORY_START + 47,
> + "Filesystem upgrade is not supported")
> +
> /* repos errors */
>
> SVN_ERRDEF(SVN_ERR_REPOS_LOCKED,
> @@ -689,6 +694,10 @@
> SVN_ERR_REPOS_CATEGORY_START + 9,
> "Error running post-unlock hook")
>
> + /** @since New in 1.5. */
> + SVN_ERRDEF(SVN_ERR_REPOS_UNSUPPORTED_UPGRADE,
> + SVN_ERR_REPOS_CATEGORY_START + 10,
> + "Repository upgrade is not supported")
>
> /* generic RA errors */
>
>
> Modified: trunk/subversion/include/svn_fs.h
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/include/svn_fs.h?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/include/svn_fs.h (original)
> +++ trunk/subversion/include/svn_fs.h Fri Feb 1 11:53:37 2008
> @@ -201,6 +201,22 @@
> apr_pool_t *pool);
>
> /**
> + * Upgrade the Subversion filesystem located in the directory @a path
> + * to the latest version supported by this library. Return @c
> + * SVN_ERR_FS_UNSUPPORTED_UPGRADE and make no changes to the
> + * filesystem if the requested upgrade is not supported. Use @a pool
> + * for necessary allocations.
> + *
> + * @note You probably don't want to use this directly. Take a look at
> + * svn_repos_upgrade() instead.
> + *
> + * @since New in 1.5.
> + */
> +svn_error_t *
> +svn_fs_upgrade(const char *path,
> + apr_pool_t *pool);
> +
> +/**
> * Return, in @a *fs_type, a string identifying the back-end type of
> * the Subversion filesystem located in @a path. Allocate @a *fs_type
> * in @a pool.
>
> Modified: trunk/subversion/include/svn_repos.h
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/include/svn_repos.h?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/include/svn_repos.h (original)
> +++ trunk/subversion/include/svn_repos.h Fri Feb 1 11:53:37 2008
> @@ -204,11 +204,51 @@
> apr_hash_t *fs_config,
> apr_pool_t *pool);
>
> +/**
> + * Upgrade the Subversion repository (and its underlying versioned
> + * filesystem) located in the directory @a path to the latest version
> + * supported by this library. If the requested upgrade is not
> + * supported due to the current state of the repository or it
> + * underlying filesystem, return @c SVN_ERR_REPOS_UNSUPPORTED_UPGRADE
> + * or @c SVN_ERR_FS_UNSUPPORTED_UPGRADE (respectively) and make no
> + * changes to the repository or filesystem.
> + *
> + * Acquires an exclusive lock on the repository, upgrades the
> + * repository, and releases the lock. If an exclusive lock can't be
> + * acquired, returns error.
> + *
> + * If @a nonblocking is TRUE, an error of type EWOULDBLOCK is
> + * returned if the lock is not immediately available.
> + *
> + * If @a start_callback is not NULL, it will be called with @a
> + * start_callback_baton as argument before the upgrade starts, but
> + * after the exclusive lock has been acquired.
> + *
> + * Use @a pool for necessary allocations.
> + *
> + * @note This functionality is provided as a convenience for
> + * administrators wishing to make use of new Subversion functionality
> + * without a potentially costly full repository dump/load. As such,
> + * the operation performs only the minimum amount of work needed to
> + * accomplish this while maintaining the integrity of the repository.
> + * It does *not* guarantee the most optimized repository state as a
> + * dump and subsequent load would.
> + *
> + * @since New in 1.5.
> + */
> +svn_error_t *
> +svn_repos_upgrade(const char *path,
> + svn_boolean_t nonblocking,
> + svn_error_t *(*start_callback)(void *baton),
> + void *start_callback_baton,
> + apr_pool_t *pool);
> +
> /** Destroy the Subversion repository found at @a path, using @a pool for any
> * necessary allocations.
> */
> svn_error_t *svn_repos_delete(const char *path, apr_pool_t *pool);
>
> +
> /** Return the filesystem associated with repository object @a repos. */
> svn_fs_t *svn_repos_fs(svn_repos_t *repos);
>
>
> Modified: trunk/subversion/libsvn_fs/fs-loader.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_fs/fs-loader.c?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/libsvn_fs/fs-loader.c (original)
> +++ trunk/subversion/libsvn_fs/fs-loader.c Fri Feb 1 11:53:37 2008
> @@ -403,6 +403,27 @@
> return err2;
> }
>
> +svn_error_t *
> +svn_fs_upgrade(const char *path, apr_pool_t *pool)
> +{
> + svn_error_t *err;
> + svn_error_t *err2;
> + fs_library_vtable_t *vtable;
> + svn_fs_t *fs;
> +
> + SVN_ERR(fs_library_vtable(&vtable, path, pool));
> + fs = svn_fs_new(NULL, pool);
> + SVN_ERR(acquire_fs_mutex());
> + err = vtable->upgrade_fs(fs, path, pool, common_pool);
> + err2 = release_fs_mutex();
> + if (err)
> + {
> + svn_error_clear(err2);
> + return err;
> + }
> + return err2;
> +}
> +
> const char *
> svn_fs_path(svn_fs_t *fs, apr_pool_t *pool)
> {
>
> Modified: trunk/subversion/libsvn_fs/fs-loader.h
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_fs/fs-loader.h?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/libsvn_fs/fs-loader.h (original)
> +++ trunk/subversion/libsvn_fs/fs-loader.h Fri Feb 1 11:53:37 2008
> @@ -66,9 +66,9 @@
> this statement, now that the minor version has increased. */
> const svn_version_t *(*get_version)(void);
>
> - /* The open_fs/create/open_fs_for_recovery functions are serialized
> - so that they may use the common_pool parameter to allocate
> - fs-global objects such as the bdb env cache. */
> + /* The open_fs/create/open_fs_for_recovery/upgrade_fs functions are
> + serialized so that they may use the common_pool parameter to
> + allocate fs-global objects such as the bdb env cache. */
> svn_error_t *(*create)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
> apr_pool_t *common_pool);
> svn_error_t *(*open_fs)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
> @@ -79,6 +79,8 @@
> svn_error_t *(*open_fs_for_recovery)(svn_fs_t *fs, const char *path,
> apr_pool_t *pool,
> apr_pool_t *common_pool);
> + svn_error_t *(*upgrade_fs)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
> + apr_pool_t *common_pool);
> svn_error_t *(*delete_fs)(const char *path, apr_pool_t *pool);
> svn_error_t *(*hotcopy)(const char *src_path, const char *dest_path,
> svn_boolean_t clean, apr_pool_t *pool);
>
> Modified: trunk/subversion/libsvn_fs_base/fs.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_fs_base/fs.c?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/libsvn_fs_base/fs.c (original)
> +++ trunk/subversion/libsvn_fs_base/fs.c Fri Feb 1 11:53:37 2008
> @@ -786,6 +786,16 @@
> }
>
> static svn_error_t *
> +base_upgrade(svn_fs_t *fs, const char *path, apr_pool_t *pool,
> + apr_pool_t *common_pool)
> +{
> + /* Currently, upgrading just means bumping the format file's stored
> + version number. */
> + return svn_io_write_version_file(svn_path_join(path, FORMAT_FILE, pool),
> + SVN_FS_BASE__FORMAT_NUMBER, pool);
> +}
> +
> +static svn_error_t *
> base_bdb_recover(svn_fs_t *fs,
> svn_cancel_func_t cancel_func, void *cancel_baton,
> apr_pool_t *pool)
> @@ -1221,6 +1231,7 @@
> base_create,
> base_open,
> base_open_for_recovery,
> + base_upgrade,
> base_delete_fs,
> base_hotcopy,
> base_get_description,
>
> Modified: trunk/subversion/libsvn_fs_fs/fs.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_fs_fs/fs.c?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/libsvn_fs_fs/fs.c (original)
> +++ trunk/subversion/libsvn_fs_fs/fs.c Fri Feb 1 11:53:37 2008
> @@ -236,6 +236,21 @@
>
>
>
> +/* This implements the fs_library_vtable_t.uprade_fs() API. */
> +static svn_error_t *
> +fs_upgrade(svn_fs_t *fs, const char *path, apr_pool_t *pool,
> + apr_pool_t *common_pool)
> +{
> + SVN_ERR(svn_fs__check_fs(fs, FALSE));
> + initialize_fs_struct(fs);
> + SVN_ERR(svn_fs_fs__open(fs, path, pool));
> + SVN_ERR(fs_serialized_init(fs, common_pool, pool));
> + return svn_fs_fs__upgrade(fs, pool);
> +}
> +
> +
> +
> +
> /* This implements the fs_library_vtable_t.hotcopy() API. Copy a
> possibly live Subversion filesystem from SRC_PATH to DEST_PATH.
> The CLEAN_LOGS argument is ignored and included for Subversion
> @@ -301,6 +316,7 @@
> fs_create,
> fs_open,
> fs_open_for_recovery,
> + fs_upgrade,
> fs_delete_fs,
> fs_hotcopy,
> fs_get_description,
>
> Modified: trunk/subversion/libsvn_fs_fs/fs_fs.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_fs_fs/fs_fs.c?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/libsvn_fs_fs/fs_fs.c (original)
> +++ trunk/subversion/libsvn_fs_fs/fs_fs.c Fri Feb 1 11:53:37 2008
> @@ -299,8 +299,11 @@
> static APR_INLINE const char *
> path_node_origin(svn_fs_t *fs, const char *node_id, apr_pool_t *pool)
> {
> + int len = strlen(node_id);
> + const char *node_id_minus_last_char =
> + (len == 1) ? "0" : apr_pstrmemdup(pool, node_id, len - 1);
> return svn_path_join_many(pool, fs->path, PATH_NODE_ORIGINS_DIR,
> - node_id, NULL);
> + node_id_minus_last_char, NULL);
> }
>
>
> @@ -888,16 +891,14 @@
> }
>
> /* Write the format number and maximum number of files per directory
> - to a new format file in PATH.
> + to a new format file in PATH, possibly expecting to overwrite a
> + previously existing file.
>
> Use POOL for temporary allocation. */
> static svn_error_t *
> write_format(const char *path, int format, int max_files_per_dir,
> - apr_pool_t *pool)
> + svn_boolean_t overwrite, apr_pool_t *pool)
> {
> - /* svn_io_write_version_file() does a load of magic to allow it to
> - replace version files that already exist. Luckily, we never need to
> - do that. */
> const char *contents;
>
> assert (1 <= format && format <= SVN_FS_FS__FORMAT_NUMBER);
> @@ -919,15 +920,46 @@
> contents = apr_psprintf(pool, "%d\n", format);
> }
>
> - /* Create the file */
> - SVN_ERR(svn_io_file_create(path, contents, pool));
> + /* svn_io_write_version_file() does a load of magic to allow it to
> + replace version files that already exist. We only need to do
> + that when we're allowed to overwrite an existing file. */
> + if (! overwrite)
> + {
> + /* Create the file */
> + SVN_ERR(svn_io_file_create(path, contents, pool));
> + }
> + else
> + {
> + apr_file_t *format_file;
> + const char *path_tmp;
> +
> + /* Create a temporary file to write the data to */
> + SVN_ERR(svn_io_open_unique_file2(&format_file, &path_tmp, path, ".tmp",
> + svn_io_file_del_none, pool));
> +
> + /* ...dump out our version number string... */
> + SVN_ERR(svn_io_file_write_full(format_file, contents,
> + strlen(contents), NULL, pool));
> +
> + /* ...and close the file. */
> + SVN_ERR(svn_io_file_close(format_file, pool));
> +
> +#ifdef WIN32
> + /* make the destination writable, but only on Windows, because
> + Windows does not let us replace read-only files. */
> + SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
> +#endif /* WIN32 */
> +
> + /* rename the temp file as the real destination */
> + SVN_ERR(svn_io_file_rename(path_tmp, path, pool));
> + }
> +
> /* And set the perms to make it read only */
> SVN_ERR(svn_io_set_file_read_only(path, FALSE, pool));
>
> return SVN_NO_ERROR;
> }
>
> -
> /* Return the error SVN_ERR_FS_UNSUPPORTED_FORMAT if FS's format
> number is not the same as a format number supported by this
> Subversion. */
> @@ -981,6 +1013,55 @@
> return SVN_NO_ERROR;
> }
>
> +
> +static svn_error_t *
> +upgrade_body(void *baton, apr_pool_t *pool)
> +{
> + svn_fs_t *fs = baton;
> + int format, max_files_per_dir;
> + const char *format_path = path_format(fs, pool);
> +
> + /* Read the FS format number and max-files-per-dir setting. */
> + SVN_ERR(read_format(&format, &max_files_per_dir, format_path, pool));
> +
> + /* If we're already up-to-date, there's nothing to be done here. */
> + if (format == SVN_FS_FS__FORMAT_NUMBER)
> + return SVN_NO_ERROR;
> +
> + /* If our filesystem predates the existance of the 'txn-current
> + file', make that file and its corresponding lock file. */
> + if (format < SVN_FS_FS__MIN_TXN_CURRENT_FORMAT)
> + {
> + SVN_ERR(svn_io_file_create(path_txn_current(fs, pool), "0\n", pool));
> + SVN_ERR(svn_io_file_create(path_txn_current_lock(fs, pool), "", pool));
> + }
> +
> + /* If our filesystem predates the existance of the 'txn-protorevs'
> + dir, make that directory. */
> + if (format < SVN_FS_FS__MIN_PROTOREVS_DIR_FORMAT)
> + {
> + /* We don't use path_txn_proto_rev() here because it expects
> + we've already bumped our format. */
> + SVN_ERR(svn_io_make_dir_recursively
> + (svn_path_join(fs->path, PATH_TXN_PROTOS_DIR, pool), pool));
> + }
> +
> + /* Bump the format file. We pass 0 for the max_files_per_dir here
> + so we don't have to fuss with sharding directories ourselves. */
> + SVN_ERR(write_format(format_path, SVN_FS_FS__FORMAT_NUMBER, 0,
> + TRUE, pool));
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> +svn_error_t *
> +svn_fs_fs__upgrade(svn_fs_t *fs, apr_pool_t *pool)
> +{
> + return svn_fs_fs__with_write_lock(fs, upgrade_body, (void *)fs, pool);
> +}
> +
> +
> /* SVN_ERR-like macros for dealing with ESTALE
> *
> * In NFS v3 and under, the server doesn't track opened files. If you
> @@ -1218,7 +1299,7 @@
>
> /* Hotcopied FS is complete. Stamp it with a format file. */
> SVN_ERR(write_format(svn_path_join(dst_path, PATH_FORMAT, pool),
> - format, max_files_per_dir, pool));
> + format, max_files_per_dir, FALSE, pool));
>
> return SVN_NO_ERROR;
> }
> @@ -5260,7 +5341,7 @@
>
> /* This filesystem is ready. Stamp it with a format number. */
> SVN_ERR(write_format(path_format(fs, pool),
> - ffd->format, ffd->max_files_per_dir, pool));
> + ffd->format, ffd->max_files_per_dir, FALSE, pool));
>
> ffd->youngest_rev_cache = 0;
> return SVN_NO_ERROR;
> @@ -5640,18 +5721,20 @@
> return SVN_NO_ERROR;
> }
>
> -svn_error_t *
> -svn_fs_fs__get_node_origin(const svn_fs_id_t **origin_id,
> - svn_fs_t *fs,
> - const char *node_id,
> +/* Set *NODE_ORIGINS to a hash mapping 'const char *' node IDs to
> + 'svn_string_t *' node revision IDs. Use POOL for allocations. */
> +static svn_error_t *
> +get_node_origins_from_file(svn_fs_t *fs,
> + apr_hash_t **node_origins,
> + const char *node_origins_file,
> apr_pool_t *pool)
> {
> apr_file_t *fd;
> - svn_stringbuf_t *origin_stringbuf;
> svn_error_t *err;
> + svn_stream_t *stream;
>
> - *origin_id = NULL;
> - err = svn_io_file_open(&fd, path_node_origin(fs, node_id, pool),
> + *node_origins = NULL;
> + err = svn_io_file_open(&fd, node_origins_file,
> APR_READ, APR_OS_DEFAULT, pool);
> if (err && APR_STATUS_IS_ENOENT(err->apr_err))
> {
> @@ -5660,42 +5743,79 @@
> }
> SVN_ERR(err);
>
> - SVN_ERR(svn_stringbuf_from_aprfile(&origin_stringbuf, fd, pool));
> -
> - *origin_id = svn_fs_fs__id_parse(origin_stringbuf->data,
> - origin_stringbuf->len, pool);
> + stream = svn_stream_from_aprfile2(fd, FALSE, pool);
> + *node_origins = apr_hash_make(pool);
> + SVN_ERR(svn_hash_read2(*node_origins, stream, SVN_HASH_TERMINATOR, pool));
> + return svn_stream_close(stream);
> +}
>
> - SVN_ERR(svn_io_file_close(fd, pool));
> +svn_error_t *
> +svn_fs_fs__get_node_origin(const svn_fs_id_t **origin_id,
> + svn_fs_t *fs,
> + const char *node_id,
> + apr_pool_t *pool)
> +{
> + apr_hash_t *node_origins;
>
> + *origin_id = NULL;
> + SVN_ERR(get_node_origins_from_file(fs, &node_origins,
> + path_node_origin(fs, node_id, pool),
> + pool));
> + if (node_origins)
> + {
> + svn_string_t *origin_id_str =
> + apr_hash_get(node_origins, node_id, APR_HASH_KEY_STRING);
> + if (origin_id_str)
> + *origin_id = svn_fs_fs__id_parse(origin_id_str->data,
> + origin_id_str->len, pool);
> + }
> return SVN_NO_ERROR;
> }
>
> -/* Helper for svn_fs_fs__set_node_origin[s]. Exactly like
> - svn_fs_fs__set_node_origin, except that it throws an error if the
> - file can't be written. */
> +
> +/* Helper for svn_fs_fs__set_node_origin[s]. Takes a hash of
> + NODE_ORIGINS records -- all destined for the same NODE_ORIGINS_PATH
> + file -- and merges them with any records already present in that
> + file. */
> static svn_error_t *
> -set_node_origin(svn_fs_t *fs,
> - const char *node_id,
> - const svn_fs_id_t *node_rev_id,
> - apr_pool_t *pool)
> +set_node_origins_for_file(svn_fs_t *fs,
> + const char *node_origins_path,
> + apr_hash_t *node_origins,
> + apr_pool_t *pool)
> {
> - apr_file_t *file;
> - svn_string_t *node_rev_id_string;
> + apr_file_t *fd;
> + const char *path_tmp;
> + svn_stream_t *stream;
> + apr_hash_t *old_origins;
>
> SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_path_join(fs->path,
> PATH_NODE_ORIGINS_DIR,
> pool),
> fs, pool));
>
> - node_rev_id_string = svn_fs_fs__id_unparse(node_rev_id, pool);
> + /* Read the previously existing origins (if any), and merge our
> + updates with it. */
> + SVN_ERR(get_node_origins_from_file(fs, &old_origins,
> + node_origins_path, pool));
> + if (old_origins)
> + node_origins = apr_hash_overlay(pool, old_origins, node_origins);
> +
> +
> + /* ###
> + * ### LA DEE DAH -- Did anybody else spot the race condition here?
> + * ###
> + */
>
> - SVN_ERR(svn_io_file_open(&file, path_node_origin(fs, node_id, pool),
> - APR_WRITE | APR_CREATE | APR_TRUNCATE
> - | APR_BUFFERED, APR_OS_DEFAULT, pool));
> - SVN_ERR(svn_io_file_write_full(file,
> - node_rev_id_string->data,
> - node_rev_id_string->len, NULL, pool));
> - SVN_ERR(svn_io_file_close(file, pool));
> +
> + /* Create a temporary file, write out our hash, and close the file. */
> + SVN_ERR(svn_io_open_unique_file2(&fd, &path_tmp, node_origins_path, ".tmp",
> + svn_io_file_del_none, pool));
> + stream = svn_stream_from_aprfile2(fd, FALSE, pool);
> + SVN_ERR(svn_hash_write2(node_origins, stream, SVN_HASH_TERMINATOR, pool));
> + SVN_ERR(svn_stream_close(stream));
> +
> + /* Rename the temp file as the real destination */
> + SVN_ERR(svn_io_file_rename(path_tmp, node_origins_path, pool));
>
> return SVN_NO_ERROR;
> }
> @@ -5708,7 +5828,11 @@
> {
> apr_hash_index_t *hi;
> apr_pool_t *iterpool = svn_pool_create(pool);
> + apr_hash_t *hash_of_hashes = apr_hash_make(pool);
>
> + /* Split the hash of node IDs and origin node revision IDs into a
> + hash of hashes keyed on the filenames in which each of these bad
> + boys is supposed to be stored. */
> for (hi = apr_hash_first(pool, node_origins);
> hi != NULL;
> hi = apr_hash_next(hi))
> @@ -5716,27 +5840,46 @@
> const void *key;
> void *val;
> const char *node_id;
> - const svn_fs_id_t *node_rev_id;
> + svn_string_t *node_rev_id_str;
> + apr_hash_t *file_hash;
> + const char *filename;
> +
> + apr_hash_this(hi, &key, NULL, &val);
> + node_id = key;
> + node_rev_id_str = svn_fs_fs__id_unparse(val, pool);
> + filename = path_node_origin(fs, node_id, pool);
> + file_hash = apr_hash_get(hash_of_hashes, filename, APR_HASH_KEY_STRING);
> + if (! file_hash)
> + {
> + file_hash = apr_hash_make(pool);
> + apr_hash_set(hash_of_hashes, filename, APR_HASH_KEY_STRING,
> + file_hash);
> + }
> + apr_hash_set(file_hash, node_id, APR_HASH_KEY_STRING, node_rev_id_str);
> + }
> +
> + /* Now, iterate over the hash of hashes, calling
> + set_node_origins_for_file on each set. */
> + for (hi = apr_hash_first(pool, hash_of_hashes);
> + hi != NULL;
> + hi = apr_hash_next(hi))
> + {
> + const void *key;
> + void *val;
> svn_error_t *err;
>
> svn_pool_clear(iterpool);
>
> apr_hash_this(hi, &key, NULL, &val);
> - node_id = key;
> - node_rev_id = val;
> -
> - err = set_node_origin(fs, node_id, node_rev_id, iterpool);
> + err = set_node_origins_for_file(fs, key, val, iterpool);
> if (err && APR_STATUS_IS_EACCES(err->apr_err))
> {
> - /* It's just a cache; stop trying if I can't write. */
> svn_error_clear(err);
> - err = NULL;
> - goto cleanup;
> + err = SVN_NO_ERROR;
> }
> SVN_ERR(err);
> }
>
> - cleanup:
> svn_pool_destroy(iterpool);
> return SVN_NO_ERROR;
> }
> @@ -5747,7 +5890,14 @@
> const svn_fs_id_t *node_rev_id,
> apr_pool_t *pool)
> {
> - svn_error_t *err = set_node_origin(fs, node_id, node_rev_id, pool);
> + svn_error_t *err;
> + apr_hash_t *file_hash = apr_hash_make(pool);
> + const char *filename = path_node_origin(fs, node_id, pool);
> +
> + apr_hash_set(file_hash, node_id, APR_HASH_KEY_STRING,
> + svn_fs_fs__id_unparse(node_rev_id, pool));
> +
> + err = set_node_origins_for_file(fs, filename, file_hash, pool);
> if (err && APR_STATUS_IS_EACCES(err->apr_err))
> {
> /* It's just a cache; stop trying if I can't write. */
>
> Modified: trunk/subversion/libsvn_fs_fs/fs_fs.h
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_fs_fs/fs_fs.h?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/libsvn_fs_fs/fs_fs.h (original)
> +++ trunk/subversion/libsvn_fs_fs/fs_fs.h Fri Feb 1 11:53:37 2008
> @@ -26,6 +26,10 @@
> const char *path,
> apr_pool_t *pool);
>
> +/* Upgrade the fsfs filesystem FS. Use POOL for temporary allocations. */
> +svn_error_t *svn_fs_fs__upgrade(svn_fs_t *fs,
> + apr_pool_t *pool);
> +
> /* Copy the fsfs filesystem at SRC_PATH into a new copy at DST_PATH.
> Use POOL for temporary allocations. */
> svn_error_t *svn_fs_fs__hotcopy(const char *src_path,
>
> Modified: trunk/subversion/libsvn_repos/repos.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_repos/repos.c?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/libsvn_repos/repos.c (original)
> +++ trunk/subversion/libsvn_repos/repos.c Fri Feb 1 11:53:37 2008
> @@ -1372,6 +1372,50 @@
>
>
> svn_error_t *
> +svn_repos_upgrade(const char *path,
> + svn_boolean_t nonblocking,
> + svn_error_t *(*start_callback)(void *baton),
> + void *start_callback_baton,
> + apr_pool_t *pool)
> +{
> + svn_repos_t *repos;
> + const char *format_path;
> + int format;
> + apr_pool_t *subpool = svn_pool_create(pool);
> +
> + /* Fetch a repository object; for the Berkeley DB backend, it is
> + initialized with an EXCLUSIVE lock on the database. This will at
> + least prevent others from trying to read or write to it while we
> + run recovery. (Other backends should do their own locking; see
> + lock_repos.) */
> + SVN_ERR(get_repos(&repos, path, TRUE, nonblocking, FALSE, subpool));
> +
> + if (start_callback)
> + SVN_ERR(start_callback(start_callback_baton));
> +
> + /* Try to overwrite with its own contents. We do this only to
> + verify that we can, because we don't want to actually bump the
> + format of the repository until our underlying filesystem claims
> + to have been upgraded correctly. */
> + format_path = svn_path_join(repos->path, SVN_REPOS__FORMAT, subpool);
> + SVN_ERR(svn_io_read_version_file(&format, format_path, subpool));
> + SVN_ERR(svn_io_write_version_file(format_path, format, subpool));
> +
> + /* Try to upgrade the filesystem. */
> + SVN_ERR(svn_fs_upgrade(repos->db_path, subpool));
> +
> + /* Now overwrite our format file with the latest version. */
> + SVN_ERR(svn_io_write_version_file(format_path, SVN_REPOS__FORMAT_NUMBER,
> + subpool));
> +
> + /* Close shop and free the subpool, to release the exclusive lock. */
> + svn_pool_destroy(subpool);
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> +svn_error_t *
> svn_repos_delete(const char *path,
> apr_pool_t *pool)
> {
>
> Modified: trunk/subversion/svnadmin/main.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/svnadmin/main.c?pathrev=29139&r1=29138&r2=29139
> ==============================================================================
> --- trunk/subversion/svnadmin/main.c (original)
> +++ trunk/subversion/svnadmin/main.c Fri Feb 1 11:53:37 2008
> @@ -197,6 +197,7 @@
> subcommand_setlog,
> subcommand_setrevprop,
> subcommand_setuuid,
> + subcommand_upgrade,
> subcommand_verify;
>
> enum
> @@ -433,6 +434,19 @@
> "generate a brand new UUID for the repository.\n"),
> {0} },
>
> + {"upgrade", subcommand_upgrade, {0}, N_
> + ("usage: svnadmin upgrade REPOS_PATH\n\n"
> + "Upgrade the repository located at REPOS_PATH to the latest supported\n"
> + "schema version.\n\n"
> + "This functionality is provided as a convenience for repository\n"
> + "administrators who wish to make use of new Subversion functionality\n"
> + "without having to undertake a potentially costly full repository dump\n"
> + "and load operation. As such, the upgrade performs only the minimum\n"
> + "amount of work needed to accomplish this while still maintaining the\n"
> + "integrity of the repository. It does not guarantee the most optimized\n"
> + "repository state as a dump and subsequent load would.\n"),
> + {0} },
> +
> {"verify", subcommand_verify, {0}, N_
> ("usage: svnadmin verify REPOS_PATH\n\n"
> "Verifies the data stored in the repository.\n"),
> @@ -1273,6 +1287,76 @@
> }
>
>
> +/* A callback which is called when the upgrade starts. */
> +static svn_error_t *
> +upgrade_started(void *baton)
> +{
> + apr_pool_t *pool = (apr_pool_t *)baton;
> +
> + SVN_ERR(svn_cmdline_printf(pool,
> + _("Repository lock acquired.\n"
> + "Please wait; upgrading the"
> + " repository may take some time...\n")));
> + SVN_ERR(svn_cmdline_fflush(stdout));
> +
> + /* Enable cancellation signal handlers. */
> + setup_cancellation_signals(signal_handler);
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> +/* This implements `svn_opt_subcommand_t'. */
> +static svn_error_t *
> +subcommand_upgrade(apr_getopt_t *os, void *baton, apr_pool_t *pool)
> +{
> + svn_error_t *err;
> + struct svnadmin_opt_state *opt_state = baton;
> +
> + /* Restore default signal handlers. */
> + setup_cancellation_signals(SIG_DFL);
> +
> + err = svn_repos_upgrade(opt_state->repository_path, TRUE,
> + upgrade_started, pool, pool);
> + if (err)
> + {
> + if (APR_STATUS_IS_EAGAIN(err->apr_err))
> + {
> + svn_error_clear(err);
> + err = SVN_NO_ERROR;
> + if (! opt_state->wait)
> + return svn_error_create(SVN_ERR_REPOS_LOCKED, NULL,
> + _("Failed to get exclusive repository "
> + "access; perhaps another process\n"
> + "such as httpd, svnserve or svn "
> + "has it open?"));
> + SVN_ERR(svn_cmdline_printf(pool,
> + _("Waiting on repository lock; perhaps"
> + " another process has it open?\n")));
> + SVN_ERR(svn_cmdline_fflush(stdout));
> + SVN_ERR(svn_repos_upgrade(opt_state->repository_path, FALSE,
> + upgrade_started, pool, pool));
> + }
> + else if (err->apr_err == SVN_ERR_FS_UNSUPPORTED_UPGRADE)
> + {
> + return svn_error_quick_wrap
> + (err, _("Upgrade of this repository's underlying versioned "
> + "filesystem is not supported; consider "
> + "dumping and loading the data elsewhere"));
> + }
> + else if (err->apr_err == SVN_ERR_REPOS_UNSUPPORTED_UPGRADE)
> + {
> + return svn_error_quick_wrap
> + (err, _("Upgrade of this repository is not supported; consider "
> + "dumping and loading the data elsewhere"));
> + }
> + }
> + SVN_ERR(err);
> +
> + SVN_ERR(svn_cmdline_printf(pool, _("\nUpgrade completed.\n")));
> + return SVN_NO_ERROR;
> +}
> +
>
>
> /** Main. **/
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: svn-unsubscribe_at_subversion.tigris.org
> For additional commands, e-mail: svn-help_at_subversion.tigris.org
>
>
--
David Glasser | glasser@davidglasser.net | http://www.davidglasser.net/
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe_at_subversion.tigris.org
For additional commands, e-mail: dev-help_at_subversion.tigris.org
Received on 2008-02-02 03:20:46 CET