#include <stdlib.h>
#include <string.h>
#include <apr_pools.h>
#include "../svn_test.h"
#include "../../libsvn_fs_fs/fs.h"
#include "svn_pools.h"
#include "svn_props.h"
#include "svn_fs.h"
#include "../svn_test_fs.h"
static svn_error_t *
write_format(const char *path,
int format,
int max_files_per_dir,
apr_pool_t *pool)
{
const char *contents;
path = svn_dirent_join(path, "format", pool);
if (format >= SVN_FS_FS__MIN_LAYOUT_FORMAT_OPTION_FORMAT)
{
if (max_files_per_dir)
contents = apr_psprintf(pool,
"%d\n"
"layout sharded %d\n",
format, max_files_per_dir);
else
contents = apr_psprintf(pool,
"%d\n"
"layout linear",
format);
}
else
{
contents = apr_psprintf(pool, "%d\n", format);
}
{
const char *path_tmp;
SVN_ERR(svn_io_write_unique(&path_tmp,
svn_dirent_dirname(path, pool),
contents, strlen(contents),
svn_io_file_del_none, pool));
SVN_ERR(svn_io_file_rename(path_tmp, path, pool));
}
return svn_io_set_file_read_only(path, FALSE, pool);
}
static const char *
get_rev_contents(svn_revnum_t rev, apr_pool_t *pool)
{
apr_int64_t num = ((rev * 1234353 + 4358) * 4583 + ((rev % 4) << 1)) / 42;
return apr_psprintf(pool, "%" APR_INT64_T_FMT "\n", num);
}
static svn_error_t *
create_packed_filesystem(const char *dir,
const svn_test_opts_t *opts,
int num_revs,
int shard_size,
apr_pool_t *pool)
{
svn_fs_t *fs;
svn_fs_txn_t *txn;
svn_fs_root_t *txn_root;
const char *conflict;
svn_revnum_t after_rev;
apr_pool_t *subpool = svn_pool_create(pool);
apr_pool_t *iterpool;
int version;
SVN_ERR(svn_test__create_fs(&fs, dir, opts, subpool));
svn_pool_destroy(subpool);
subpool = svn_pool_create(pool);
SVN_ERR(svn_io_read_version_file(&version,
svn_dirent_join(dir, "format", subpool),
subpool));
SVN_ERR(write_format(dir, version, shard_size, subpool));
SVN_ERR(svn_fs_open(&fs, dir, NULL, subpool));
SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, subpool));
SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
SVN_ERR(svn_test__create_greek_tree(txn_root, subpool));
SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
iterpool = svn_pool_create(subpool);
while (after_rev < num_revs)
{
svn_pool_clear(iterpool);
SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, iterpool));
SVN_ERR(svn_fs_txn_root(&txn_root, txn, iterpool));
SVN_ERR(svn_test__set_file_contents(txn_root, "iota",
get_rev_contents(after_rev + 1,
iterpool),
iterpool));
SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, iterpool));
SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
}
svn_pool_destroy(iterpool);
svn_pool_destroy(subpool);
return svn_fs_pack(dir, NULL, NULL, NULL, NULL, pool);
}
#define REPO_NAME "test-repo-fsfs-pack"
#define SHARD_SIZE 7
#define MAX_REV 53
static svn_error_t *
pack_filesystem(const svn_test_opts_t *opts,
apr_pool_t *pool)
{
int i;
svn_node_kind_t kind;
const char *path;
char buf[80];
apr_file_t *file;
apr_size_t len;
if ((strcmp(opts->fs_type, "fsfs") != 0)
|| (opts->server_minor_version && (opts->server_minor_version < 6)))
return SVN_NO_ERROR;
SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE,
pool));
for (i = 0; i < (MAX_REV + 1) / SHARD_SIZE; i++)
{
path = svn_dirent_join_many(pool, REPO_NAME, "revs",
apr_psprintf(pool, "%d.pack", i / SHARD_SIZE),
"pack", NULL);
SVN_ERR(svn_io_check_path(path, &kind, pool));
if (kind != svn_node_file)
return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
"Expected pack file '%s' not found", path);
path = svn_dirent_join_many(pool, REPO_NAME, "revs",
apr_psprintf(pool, "%d.pack", i / SHARD_SIZE),
"manifest", NULL);
SVN_ERR(svn_io_check_path(path, &kind, pool));
if (kind != svn_node_file)
return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
"Expected manifest file '%s' not found",
path);
path = svn_dirent_join_many(pool, REPO_NAME, "revs",
apr_psprintf(pool, "%d", i / SHARD_SIZE),
NULL);
SVN_ERR(svn_io_check_path(path, &kind, pool));
if (kind != svn_node_none)
return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
"Unexpected directory '%s' found", path);
}
SVN_ERR(svn_io_file_open(&file,
svn_dirent_join(REPO_NAME, PATH_MIN_UNPACKED_REV,
pool),
APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
len = sizeof(buf);
SVN_ERR(svn_io_read_length_line(file, buf, &len, pool));
SVN_ERR(svn_io_file_close(file, pool));
if (SVN_STR_TO_REV(buf) != (MAX_REV / SHARD_SIZE) * SHARD_SIZE)
return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
"Bad '%s' contents", PATH_MIN_UNPACKED_REV);
path = svn_dirent_join_many(pool, REPO_NAME, "revs",
apr_psprintf(pool, "%d", (i / SHARD_SIZE) + 1),
NULL);
SVN_ERR(svn_io_check_path(path, &kind, pool));
if (kind != svn_node_none)
return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
"Expected directory '%s' not found", path);
return SVN_NO_ERROR;
}
#undef REPO_NAME
#undef SHARD_SIZE
#undef MAX_REV
#define REPO_NAME "test-repo-fsfs-pack-even"
#define SHARD_SIZE 4
#define MAX_REV 11
static svn_error_t *
pack_even_filesystem(const svn_test_opts_t *opts,
apr_pool_t *pool)
{
svn_node_kind_t kind;
const char *path;
if ((strcmp(opts->fs_type, "fsfs") != 0)
|| (opts->server_minor_version && (opts->server_minor_version < 6)))
return SVN_NO_ERROR;
SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE,
pool));
path = svn_dirent_join_many(pool, REPO_NAME, "revs", "2.pack", NULL);
SVN_ERR(svn_io_check_path(path, &kind, pool));
if (kind != svn_node_dir)
return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
"Packing did not complete as expected");
return SVN_NO_ERROR;
}
#undef REPO_NAME
#undef SHARD_SIZE
#undef MAX_REV
#define REPO_NAME "test-repo-read-packed-fs"
#define SHARD_SIZE 5
#define MAX_REV 11
static svn_error_t *
read_packed_fs(const svn_test_opts_t *opts,
apr_pool_t *pool)
{
svn_fs_t *fs;
svn_stream_t *rstream;
svn_stringbuf_t *rstring;
svn_revnum_t i;
if ((strcmp(opts->fs_type, "fsfs") != 0)
|| (opts->server_minor_version && (opts->server_minor_version < 6)))
return SVN_NO_ERROR;
SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, pool));
for (i = 1; i < (MAX_REV + 1); i++)
{
svn_fs_root_t *rev_root;
svn_stringbuf_t *sb;
SVN_ERR(svn_fs_revision_root(&rev_root, fs, i, pool));
SVN_ERR(svn_fs_file_contents(&rstream, rev_root, "iota", pool));
SVN_ERR(svn_test__stream_to_string(&rstring, rstream, pool));
if (i == 1)
sb = svn_stringbuf_create("This is the file 'iota'.\n", pool);
else
sb = svn_stringbuf_create(get_rev_contents(i, pool), pool);
if (! svn_stringbuf_compare(rstring, sb))
return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
"Bad data in revision %ld.", i);
}
return SVN_NO_ERROR;
}
#undef REPO_NAME
#undef SHARD_SIZE
#undef MAX_REV
#define REPO_NAME "test-repo-commit-packed-fs"
#define SHARD_SIZE 5
#define MAX_REV 10
static svn_error_t *
commit_packed_fs(const svn_test_opts_t *opts,
apr_pool_t *pool)
{
svn_fs_t *fs;
svn_fs_txn_t *txn;
svn_fs_root_t *txn_root;
const char *conflict;
svn_revnum_t after_rev;
if ((strcmp(opts->fs_type, "fsfs") != 0)
|| (opts->server_minor_version && (opts->server_minor_version < 6)))
return SVN_NO_ERROR;
SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, 5, pool));
SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, pool));
SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, pool));
SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
SVN_ERR(svn_test__set_file_contents(txn_root, "iota",
"How much better is it to get wisdom than gold! and to get "
"understanding rather to be chosen than silver!", pool));
SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, pool));
SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
return SVN_NO_ERROR;
}
#undef REPO_NAME
#undef MAX_REV
#undef SHARD_SIZE
#define REPO_NAME "test-repo-get-set-revprop-packed-fs"
#define SHARD_SIZE 4
#define MAX_REV 1
static svn_error_t *
get_set_revprop_packed_fs(const svn_test_opts_t *opts,
apr_pool_t *pool)
{
svn_fs_t *fs;
svn_fs_txn_t *txn;
svn_fs_root_t *txn_root;
const char *conflict;
svn_revnum_t after_rev;
svn_string_t *prop_value;
apr_pool_t *subpool;
if ((strcmp(opts->fs_type, "fsfs") != 0)
|| (opts->server_minor_version && (opts->server_minor_version < 7)))
return SVN_NO_ERROR;
SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, pool));
subpool = svn_pool_create(pool);
SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, subpool));
SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
SVN_ERR(svn_test__set_file_contents(txn_root, "iota", "new-iota", subpool));
SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
svn_pool_clear(subpool);
SVN_ERR(svn_fs_pack(REPO_NAME, NULL, NULL, NULL, NULL, pool));
SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 0, SVN_PROP_REVISION_AUTHOR,
pool));
SVN_ERR(svn_fs_change_rev_prop(fs, 0, SVN_PROP_REVISION_AUTHOR,
svn_string_create("tweaked-author", pool),
pool));
return SVN_NO_ERROR;
}
#undef REPO_NAME
#undef MAX_REV
#undef SHARD_SIZE
#define REPO_NAME "test-repo-recover-fully-packed"
#define SHARD_SIZE 4
#define MAX_REV 7
static svn_error_t *
recover_fully_packed(const svn_test_opts_t *opts,
apr_pool_t *pool)
{
apr_pool_t *subpool;
svn_fs_t *fs;
svn_fs_txn_t *txn;
svn_fs_root_t *txn_root;
const char *conflict;
svn_revnum_t after_rev;
svn_error_t *err;
if ((strcmp(opts->fs_type, "fsfs") != 0)
|| (opts->server_minor_version && (opts->server_minor_version < 7)))
return SVN_NO_ERROR;
SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
SVN_ERR(svn_fs_recover(REPO_NAME, NULL, NULL, pool));
subpool = svn_pool_create(pool);
SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, subpool));
SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, subpool));
SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
SVN_ERR(svn_test__set_file_contents(txn_root, "A/mu", "new-mu", subpool));
SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
svn_pool_destroy(subpool);
SVN_ERR(svn_fs_pack(REPO_NAME, NULL, NULL, NULL, NULL, pool));
SVN_ERR(svn_fs_recover(REPO_NAME, NULL, NULL, pool));
SVN_ERR(svn_io_remove_file2(
svn_dirent_join_many(pool, REPO_NAME, PATH_REVPROPS_DIR,
apr_psprintf(pool, "%ld/%ld",
after_rev / SHARD_SIZE,
after_rev),
NULL),
FALSE, pool));
err = svn_fs_recover(REPO_NAME, NULL, NULL, pool);
if (! err)
return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
"Expected SVN_ERR_FS_CORRUPT error; got none");
if (err->apr_err != SVN_ERR_FS_CORRUPT)
return svn_error_create(SVN_ERR_TEST_FAILED, err,
"Expected SVN_ERR_FS_CORRUPT error; got:");
svn_error_clear(err);
return SVN_NO_ERROR;
}
#undef REPO_NAME
#undef MAX_REV
#undef SHARD_SIZE
struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
SVN_TEST_OPTS_PASS(pack_filesystem,
"pack a FSFS filesystem"),
SVN_TEST_OPTS_PASS(pack_even_filesystem,
"pack FSFS where revs % shard = 0"),
SVN_TEST_OPTS_PASS(read_packed_fs,
"read from a packed FSFS filesystem"),
SVN_TEST_OPTS_PASS(commit_packed_fs,
"commit to a packed FSFS filesystem"),
SVN_TEST_OPTS_PASS(get_set_revprop_packed_fs,
"get/set revprop while packing FSFS filesystem"),
SVN_TEST_OPTS_PASS(recover_fully_packed,
"recover a fully packed filesystem"),
SVN_TEST_NULL
};