[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] Implement sharding for FSFS

From: Malcolm Rowe <malcolm_at_farside.org.uk>
Date: 2007-04-04 18:55:19 CEST

See below.

I'm planning to commit this within a few days, so comments are welcome.

[[[
FSFS: Shard revision files and revprop files into many directories.

This changes the path used to store revisions and revprop files so they
are grouped into directories of N files (1000, by default). In the
default scheme, r12345 will now be stored in the file db/revs/12/12345.

This is primarily intended to allow the usage of large repositories
on filesystems that prohibit directories larger than a certain size
(either a hard limit, like the VFAT 64k limit, or a configurable limit,
like some NFS servers).

It will also improve performance on filesystems that have poor performance
if the number of files in a directory exceeds a certain size. The SCO
UNIX default filesystem and VFAT are good examples.

This implementation appends information to the FSFS db/format file to
describe the directory layout, rather than forcing a fixed sharding
amount. It also adds a --pre-1.5-compatible flag to svnadmin to allow
creation of repositories in the format created by 1.4 by default.

* subversion/libsvn_fs_fs/fs_fs.c
  (DEFAULT_MAX_FILES_PER_DIR): New.
  (path_rev_shard, path_revprops_shard): New. Return the shard directory
    for a particular rev or revprop.
  (svn_fs_fs__path_rev, path_revprops): Take account of sharding when
    determining the paths.
  (check_format_file_buffer_numeric): New. Helper function for
    read_format().
  (read_format): Implement without using svn_io_read_version_file(),
    since we need to read content after the first line. Parse the new
    'layout' option.
  (write_format): New. Function to write out the format number and
    format options.
  (check_format): Support our new format.
  (svn_fs_fs__open): Read the format options and store in the FSFS
    private data.
  (svn_fs_fs__hotcopy): Read the format options, and take account of
    sharding when copying the revision and revprop files. Write the
    format file out using write_format().
  (commit_body): Create new shards on demand.
  (svn_fs_fs__create): Determine the format number to use earlier,
    determine the layout to use (based on the format number), and
    optionally create the new sharded layout. Write the format file
    out using write_format().

* subversion/libsvn_fs_fs/fs.h
  (SVN_FS_FS__FORMAT_NUMBER): Bump the default filesystem format to '3'.
  (SVN_FS_FS__MIN_LAYOUT_FORMAT_OPTION_FORMAT): New.
  (fs_fs_data_t): Add 'max_files_per_dir'.

* subversion/libsvn_fs_fs/structure
  Document the new filesystem format and format options.

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

* subversion/svnadmin/main.c
  (svnadmin__pre_1_5_compatible): New option value.
  (options): Add --pre-1.5-compatible.
  (cmd_table): Make 'svnadmin create' accept --pre-1.5-compatible.
  (struct svnadmin_opt_state): Add 'pre_1_5_compatible'.
  (subcommand_create): Set the SVN_FS_CONFIG_PRE_1_5_COMPATIBLE value in
    the filesystem config hash if the --pre-1.5-compatible option is given.
  (main): Set the option state for --pre-1.5-compatible.
]]]

Regards,
Malcolm

Index: subversion/libsvn_fs_fs/fs_fs.c
===================================================================
--- subversion/libsvn_fs_fs/fs_fs.c (revision 24413)
+++ subversion/libsvn_fs_fs/fs_fs.c (working copy)
@@ -25,6 +25,7 @@
 #include <apr_pools.h>
 #include <apr_file_io.h>
 #include <apr_uuid.h>
+#include <apr_lib.h>
 #include <apr_md5.h>
 #include <apr_thread_mutex.h>
 
@@ -55,6 +56,12 @@
  * by giving us arbitrarily large paths. */
 #define FSFS_MAX_PATH_LEN 4096
 
+/* The default maximum number of files per directory to store in the rev
+ and revprops directory. This number is somewhat arbitrary; this figure
+ is reasonable for VFAT filesystems, which are by far the worst performers
+ in this area. */
+#define DEFAULT_MAX_FILES_PER_DIR 1000
+
 /* Following are defines that specify the textual elements of the
    native filesystem directories and revision files. */
 
@@ -160,16 +167,58 @@ path_lock(svn_fs_t *fs, apr_pool_t *pool
   return svn_path_join(fs->path, PATH_LOCK_FILE, pool);
 }
 
+static const char *
+path_rev_shard(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+
+ assert(ffd->max_files_per_dir);
+ return svn_path_join_many(pool, fs->path, PATH_REVS_DIR,
+ apr_psprintf(pool, "%ld",
+ rev / ffd->max_files_per_dir),
+ NULL);
+}
+
 const char *
 svn_fs_fs__path_rev(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
 {
+ fs_fs_data_t *ffd = fs->fsap_data;
+
+ if (ffd->max_files_per_dir)
+ {
+ return svn_path_join(path_rev_shard(fs, rev, pool),
+ apr_psprintf(pool, "%ld", rev),
+ pool);
+ }
+
   return svn_path_join_many(pool, fs->path, PATH_REVS_DIR,
                             apr_psprintf(pool, "%ld", rev), NULL);
 }
 
 static const char *
+path_revprops_shard(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+
+ assert(ffd->max_files_per_dir);
+ return svn_path_join_many(pool, fs->path, PATH_REVPROPS_DIR,
+ apr_psprintf(pool, "%ld",
+ rev / ffd->max_files_per_dir),
+ NULL);
+}
+
+static const char *
 path_revprops(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
 {
+ fs_fs_data_t *ffd = fs->fsap_data;
+
+ if (ffd->max_files_per_dir)
+ {
+ return svn_path_join(path_revprops_shard(fs, rev, pool),
+ apr_psprintf(pool, "%ld", rev),
+ pool);
+ }
+
   return svn_path_join_many(pool, fs->path, PATH_REVPROPS_DIR,
                             apr_psprintf(pool, "%ld", rev), NULL);
 }
@@ -603,12 +652,44 @@ get_file_offset(apr_off_t *offset_p, apr
 }
 
 
-/* Read the format version from FILE and return it in *PFORMAT.
+/* Check that BUF, a buffer of text from format file PATH, contains
+ only digits, raising error SVN_ERR_BAD_VERSION_FILE_FORMAT if not.
+
+ Uses POOL for temporary allocation. */
+static svn_error_t *
+check_format_file_buffer_numeric(const char *buf, const char *path,
+ apr_pool_t *pool)
+{
+ const char *p;
+
+ for (p = buf; *p; p++)
+ if (!apr_isdigit(*p))
+ return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL,
+ _("Format file '%s' contains an unexpected non-digit"),
+ svn_path_local_style(path, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Read the format number and maximum number of files per directory
+ from PATH and return them in *PFORMAT and *MAX_FILES_PER_DIR
+ respectively.
+
+ *MAX_FILES_PER_DIR is obtained from the 'layout' format option, and
+ will be set to zero if a linear scheme should be used.
+
    Use POOL for temporary allocation. */
 static svn_error_t *
-read_format(int *pformat, const char *file, apr_pool_t *pool)
+read_format(int *pformat, int *max_files_per_dir,
+ const char *path, apr_pool_t *pool)
 {
- svn_error_t *err = svn_io_read_version_file(pformat, file, pool);
+ svn_error_t *err;
+ apr_file_t *file;
+ char buf[80];
+ apr_size_t len;
+
+ err = svn_io_file_open(&file, path, APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT, pool);
   if (err && APR_STATUS_IS_ENOENT(err->apr_err))
     {
       /* Treat an absent format file as format 1. Do not try to
@@ -619,31 +700,125 @@ read_format(int *pformat, const char *fi
          http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=97600
          for more. */
       svn_error_clear(err);
- err = SVN_NO_ERROR;
       *pformat = 1;
+ *max_files_per_dir = 0;
+
+ return SVN_NO_ERROR;
     }
- return err;
+
+ len = sizeof(buf);
+ err = svn_io_read_length_line(file, buf, &len, pool);
+ if (err && APR_STATUS_IS_EOF(err->apr_err))
+ {
+ /* Return a more useful error message. */
+ svn_error_clear(err);
+ return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL,
+ _("Can't read first line of format file '%s'"),
+ svn_path_local_style(path, pool));
+ }
+ SVN_ERR(err);
+
+ /* Check that the first line contains only digits. */
+ SVN_ERR(check_format_file_buffer_numeric(buf, path, pool));
+ *pformat = atoi(buf);
+
+ /* Set the default values for anything that can be set via an option. */
+ *max_files_per_dir = 0;
+
+ /* Read any options. */
+ while (1)
+ {
+ len = sizeof(buf);
+ err = svn_io_read_length_line(file, buf, &len, pool);
+ if (err && APR_STATUS_IS_EOF(err->apr_err))
+ {
+ /* No more options; that's okay. */
+ svn_error_clear(err);
+ break;
+ }
+ SVN_ERR(err);
+
+ if (*pformat >= SVN_FS_FS__MIN_LAYOUT_FORMAT_OPTION_FORMAT &&
+ strncmp(buf, "layout ", 7) == 0)
+ {
+ if (strcmp(buf+7, "linear") == 0)
+ {
+ *max_files_per_dir = 0;
+ continue;
+ }
+
+ if (strncmp(buf+7, "sharded ", 8) == 0)
+ {
+ /* Check that the argument is numeric. */
+ SVN_ERR(check_format_file_buffer_numeric(buf+15, path, pool));
+ *max_files_per_dir = atoi(buf+15);
+ continue;
+ }
+ }
+
+ return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL,
+ _("'%s' contains invalid filesystem format option '%s'"),
+ svn_path_local_style(path, pool), buf);
+ }
+
+ SVN_ERR(svn_io_file_close(file, pool));
+
+ return SVN_NO_ERROR;
 }
 
+/* Write the format number and maximum number of files per directory
+ to a new format file in PATH.
+
+ 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_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 (format > 0);
+ 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"
+ "linear", format);
+ }
+ else
+ {
+ contents = apr_psprintf(pool, "%d\n", format);
+ }
+
+ /* Create the file */
+ SVN_ERR(svn_io_file_create(path, contents, 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 the format number supported by this
+ number is not the same as a format number supported by this
    Subversion. */
 static svn_error_t *
 check_format(int format)
 {
- /* We support format 1 and 2 simultaneously */
- if (format == 1 && SVN_FS_FS__FORMAT_NUMBER == 2)
+ /* We support all formats from 1-current simultaneously */
+ if (format >= 1 && format <= SVN_FS_FS__FORMAT_NUMBER)
     return SVN_NO_ERROR;
 
- if (format != SVN_FS_FS__FORMAT_NUMBER)
- {
- return svn_error_createf
- (SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL,
- _("Expected FS format '%d'; found format '%d'"),
- SVN_FS_FS__FORMAT_NUMBER, format);
- }
-
- return SVN_NO_ERROR;
+ return svn_error_createf(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL,
+ _("Expected FS format between '1' and '%d'; found format '%d'"),
+ SVN_FS_FS__FORMAT_NUMBER, format);
 }
 
 svn_error_t *
@@ -651,17 +826,19 @@ svn_fs_fs__open(svn_fs_t *fs, const char
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   apr_file_t *uuid_file;
- int format;
+ int format, max_files_per_dir;
   char buf[APR_UUID_FORMATTED_LENGTH + 2];
   apr_size_t limit;
 
   fs->path = apr_pstrdup(fs->pool, path);
 
   /* Read the FS format number. */
- SVN_ERR(read_format(&format, path_format(fs, pool), pool));
+ SVN_ERR(read_format(&format, &max_files_per_dir,
+ path_format(fs, pool), pool));
 
   /* Now we've got a format number no matter what. */
   ffd->format = format;
+ ffd->max_files_per_dir = max_files_per_dir;
   SVN_ERR(check_format(format));
 
   /* Read in and cache the repository uuid. */
@@ -713,10 +890,10 @@ svn_fs_fs__hotcopy(const char *src_path,
   svn_revnum_t youngest, rev;
   apr_pool_t *iterpool;
   svn_node_kind_t kind;
- int format;
+ int format, max_files_per_dir;
 
   /* Check format to be sure we know how to hotcopy this FS. */
- SVN_ERR(read_format(&format,
+ SVN_ERR(read_format(&format, &max_files_per_dir,
                       svn_path_join(src_path, PATH_FORMAT, pool),
                       pool));
   SVN_ERR(check_format(format));
@@ -743,7 +920,22 @@ svn_fs_fs__hotcopy(const char *src_path,
   iterpool = svn_pool_create(pool);
   for (rev = 0; rev <= youngest; rev++)
     {
- SVN_ERR(svn_io_dir_file_copy(src_subdir, dst_subdir,
+ const char *src_subdir_shard = src_subdir,
+ *dst_subdir_shard = dst_subdir;
+
+ if (max_files_per_dir)
+ {
+ const char *shard = apr_psprintf(iterpool, "%ld",
+ rev / max_files_per_dir);
+ src_subdir_shard = svn_path_join(src_subdir, shard, iterpool);
+ dst_subdir_shard = svn_path_join(dst_subdir, shard, iterpool);
+
+ if (rev % max_files_per_dir == 0)
+ SVN_ERR(svn_io_dir_make(dst_subdir_shard, APR_OS_DEFAULT,
+ iterpool));
+ }
+
+ SVN_ERR(svn_io_dir_file_copy(src_subdir_shard, dst_subdir_shard,
                                    apr_psprintf(iterpool, "%ld", rev),
                                    iterpool));
       svn_pool_clear(iterpool);
@@ -757,8 +949,24 @@ svn_fs_fs__hotcopy(const char *src_path,
 
   for (rev = 0; rev <= youngest; rev++)
     {
+ const char *src_subdir_shard = src_subdir,
+ *dst_subdir_shard = dst_subdir;
+
       svn_pool_clear(iterpool);
- SVN_ERR(svn_io_dir_file_copy(src_subdir, dst_subdir,
+
+ if (max_files_per_dir)
+ {
+ const char *shard = apr_psprintf(iterpool, "%ld",
+ rev / max_files_per_dir);
+ src_subdir_shard = svn_path_join(src_subdir, shard, iterpool);
+ dst_subdir_shard = svn_path_join(dst_subdir, shard, iterpool);
+
+ if (rev % max_files_per_dir == 0)
+ SVN_ERR(svn_io_dir_make(dst_subdir_shard, APR_OS_DEFAULT,
+ iterpool));
+ }
+
+ SVN_ERR(svn_io_dir_file_copy(src_subdir_shard, dst_subdir_shard,
                                    apr_psprintf(iterpool, "%ld", rev),
                                    iterpool));
     }
@@ -780,8 +988,8 @@ svn_fs_fs__hotcopy(const char *src_path,
                                         NULL, pool));
 
   /* Hotcopied FS is complete. Stamp it with a format file. */
- SVN_ERR(svn_io_write_version_file
- (svn_path_join(dst_path, PATH_FORMAT, pool), format, pool));
+ SVN_ERR(write_format(svn_path_join(dst_path, PATH_FORMAT, pool),
+ format, max_files_per_dir, pool));
 
   return SVN_NO_ERROR;
 }
@@ -4347,6 +4555,7 @@ static svn_error_t *
 commit_body(void *baton, apr_pool_t *pool)
 {
   struct commit_baton *cb = baton;
+ fs_fs_data_t *ffd = cb->fs->fsap_data;
   const char *old_rev_filename, *rev_filename, *proto_filename;
   const char *revprop_filename, *final_revprop;
   const svn_fs_id_t *root_id, *new_root_id;
@@ -4435,6 +4644,26 @@ commit_body(void *baton, apr_pool_t *poo
       
     }
 
+ /* Create the shard for the rev and revprop file, if we're sharding and
+ this is the first revision of a new shard. We don't care if this
+ fails because the shard already existed for some reason. */
+ if (ffd->max_files_per_dir && new_rev % ffd->max_files_per_dir == 0)
+ {
+ svn_error_t *err;
+ err = svn_io_dir_make(path_rev_shard(cb->fs, new_rev, pool),
+ APR_OS_DEFAULT, pool);
+ if (err && APR_STATUS_IS_EEXIST(err->apr_err))
+ svn_error_clear(err);
+ else
+ SVN_ERR(err);
+ err = svn_io_dir_make(path_revprops_shard(cb->fs, new_rev, pool),
+ APR_OS_DEFAULT, pool);
+ if (err && APR_STATUS_IS_EEXIST(err->apr_err))
+ svn_error_clear(err);
+ else
+ SVN_ERR(err);
+ }
+
   /* Move the finished rev file into place. */
   old_rev_filename = svn_fs_fs__path_rev(cb->fs, old_rev, pool);
   rev_filename = svn_fs_fs__path_rev(cb->fs, new_rev, pool);
@@ -4547,15 +4776,41 @@ svn_fs_fs__create(svn_fs_t *fs,
                   apr_pool_t *pool)
 {
   int format = SVN_FS_FS__FORMAT_NUMBER;
-
+ fs_fs_data_t *ffd = fs->fsap_data;
+
   fs->path = apr_pstrdup(pool, path);
+ /* See if we had an explicitly requested pre-1.4- or pre-1.5-compatible. */
+ if (fs->config)
+ {
+ if (apr_hash_get(fs->config, SVN_FS_CONFIG_PRE_1_4_COMPATIBLE,
+ APR_HASH_KEY_STRING))
+ format = 1;
+ else if (apr_hash_get(fs->config, SVN_FS_CONFIG_PRE_1_5_COMPATIBLE,
+ APR_HASH_KEY_STRING))
+ format = 2;
+ }
+ ffd->format = format;
 
- SVN_ERR(svn_io_make_dir_recursively(svn_path_join(path, PATH_REVS_DIR,
- pool),
- pool));
- SVN_ERR(svn_io_make_dir_recursively(svn_path_join(path, PATH_REVPROPS_DIR,
- pool),
- pool));
+ /* Override the default linear layout if this is a new-enough format. */
+ if (format >= SVN_FS_FS__MIN_LAYOUT_FORMAT_OPTION_FORMAT)
+ ffd->max_files_per_dir = DEFAULT_MAX_FILES_PER_DIR;
+
+ if (ffd->max_files_per_dir)
+ {
+ SVN_ERR(svn_io_make_dir_recursively(path_rev_shard(fs, 0, pool),
+ pool));
+ SVN_ERR(svn_io_make_dir_recursively(path_revprops_shard(fs, 0, pool),
+ pool));
+ }
+ else
+ {
+ SVN_ERR(svn_io_make_dir_recursively(svn_path_join(path, PATH_REVS_DIR,
+ pool),
+ pool));
+ SVN_ERR(svn_io_make_dir_recursively(svn_path_join(path, PATH_REVPROPS_DIR,
+ pool),
+ pool));
+ }
   SVN_ERR(svn_io_make_dir_recursively(svn_path_join(path, PATH_TXNS_DIR,
                                                     pool),
                                       pool));
@@ -4565,18 +4820,13 @@ svn_fs_fs__create(svn_fs_t *fs,
   SVN_ERR(svn_io_file_create(path_lock(fs, pool), "", pool));
   SVN_ERR(svn_fs_fs__set_uuid(fs, svn_uuid_generate(pool), pool));
 
- /* See if we had an explicitly requested pre 1.4 compatible. */
- if (fs->config && apr_hash_get(fs->config, SVN_FS_CONFIG_PRE_1_4_COMPATIBLE,
- APR_HASH_KEY_STRING))
- format = 1;
-
   SVN_ERR(write_revision_zero(fs));
 
   /* This filesystem is ready. Stamp it with a format number. */
- SVN_ERR(svn_io_write_version_file
- (path_format(fs, pool), format, pool));
- ((fs_fs_data_t *) fs->fsap_data)->format = format;
+ SVN_ERR(write_format(path_format(fs, pool),
+ ffd->format, ffd->max_files_per_dir, pool));
 
+ /* ### this should be before the format file */
   SVN_ERR(svn_fs_merge_info__create_index(path, pool));
   return SVN_NO_ERROR;
 }
Index: subversion/libsvn_fs_fs/fs.h
===================================================================
--- subversion/libsvn_fs_fs/fs.h (revision 24413)
+++ subversion/libsvn_fs_fs/fs.h (working copy)
@@ -35,11 +35,15 @@ extern "C" {
 /* The format number of this filesystem.
    This is independent of the repository format number, and
    independent of any other FS back ends. */
-#define SVN_FS_FS__FORMAT_NUMBER 2
+#define SVN_FS_FS__FORMAT_NUMBER 3
 
 /* The minimum format number that supports svndiff version 1. */
 #define SVN_FS_FS__MIN_SVNDIFF1_FORMAT 2
 
+/* The minimum format number that supports the "layout" filesystem
+ format option. */
+#define SVN_FS_FS__MIN_LAYOUT_FORMAT_OPTION_FORMAT 3
+
 /* Maximum number of directories to cache dirents for.
    This *must* be a power of 2 for DIR_CACHE_ENTRIES_INDEX
    to work. */
@@ -114,6 +118,9 @@ typedef struct
 
   /* The format number of this FS. */
   int format;
+ /* The maximum number of files to store per directory (for sharded
+ layouts) or zero (for linear layouts). */
+ int max_files_per_dir;
 
   /* The uuid of this FS. */
   const char *uuid;
Index: subversion/libsvn_fs_fs/structure
===================================================================
--- subversion/libsvn_fs_fs/structure (revision 24413)
+++ subversion/libsvn_fs_fs/structure (working copy)
@@ -32,9 +32,11 @@ The layout of the FS directory (the "db"
 repository) is:
 
   revs Subdirectory containing revs
- <revnum> File containing rev <revnum>
+ <shard> Shard directory, if sharding is in use (see below)
+ <revnum> File containing rev <revnum>
   revprops Subdirectory containing rev-props
- <revnum> File containing rev-props for <revnum>
+ <shard> Shard directory, if sharding is in use (see below)
+ <revnum> File containing rev-props for <revnum>
   transactions Subdirectory containing transactions
     <txnid>.txn Directory containing transaction <txnid>
   locks Subdirectory containing locks
@@ -75,15 +77,59 @@ version of Subversion. An absent format
 indicating a format 1 filesystem.
 
 The format file is a single line of the form "<format number>\n",
-where the format number has the following meanings:
+followed by any number of lines specifying 'format options' -
+additional information about the filesystem's format. Each format
+option line is of the form "<option>\n" or "<option> <parameters>\n".
+
+Clients should raise an error if they encounter an option not
+permitted by the format number in use.
+
+The format numbers have the following meanings:
 
 Format 1: (understood by Subversion 1.1+)
   Delta representations in revision files must contain only svndiff0
- data.
+ data. No format options are permitted.
 
 Format 2: (understood by Subversion 1.4+)
   Delta representations in revision files may contain either svndiff0
- or svndiff1 data.
+ or svndiff1 data. No format options are permitted.
+
+Format 3: (understood by Subversion 1.5+)
+ Delta representations in revision files may contain either svndiff0
+ or svndiff1 data. The 'layout' format option is permitted.
+
+Filesystem format options
+-------------------------
+
+Currently, the only recognised format option is "layout", which
+specifies the paths that will be used to store the revision files and
+revision property files.
+
+The "layout" option is followed by the name of the filesystem layout
+and any required parameters. The default layout, if no "layout"
+keyword is specified, is the 'linear' layout.
+
+The known layouts, and the parameters they require, are as follows:
+
+"linear"
+ Revision files and rev-prop files are named after the revision they
+ represent, and are placed directly in the revs/ and revprops/
+ directories. r1234 will be represented by the revision file
+ revs/1234 and the rev-prop file revprops/1234.
+
+"sharded <max-files-per-directory>"
+ Revision files and rev-prop files are named after the revision they
+ represent, and are placed in a subdirectory of the revs/ and
+ revprops/ directories named according to the 'shard' they belong to.
+
+ Shards are numbered from zero and contain between one and the
+ maximum number of files per directory specified in the layout's
+ parameters.
+
+ For the "sharded 1000" layout, r1234 will be represented by the
+ revision file revs/1/1234 and rev-prop file revprops/1/1234. The
+ revs/0/ directory will contain revisions 0-999, revs/1/ will contain
+ 1000-1999, and so on.
 
 Node-revision IDs
 -----------------
Index: subversion/include/svn_fs.h
===================================================================
--- subversion/include/svn_fs.h (revision 24413)
+++ subversion/include/svn_fs.h (working copy)
@@ -73,6 +73,13 @@ typedef struct svn_fs_t svn_fs_t;
  * @since New in 1.4.
  */
 #define SVN_FS_CONFIG_PRE_1_4_COMPATIBLE "pre-1.4-compatible"
+
+/** Create repository format compatible with Subversion versions
+ * earlier than 1.5.
+ *
+ * @since New in 1.5.
+ */
+#define SVN_FS_CONFIG_PRE_1_5_COMPATIBLE "pre-1.5-compatible"
 /** @} */
 
 
Index: subversion/svnadmin/main.c
===================================================================
--- subversion/svnadmin/main.c (revision 24415)
+++ subversion/svnadmin/main.c (working copy)
@@ -217,7 +217,8 @@ enum
     svnadmin__use_post_revprop_change_hook,
     svnadmin__clean_logs,
     svnadmin__wait,
- svnadmin__pre_1_4_compatible
+ svnadmin__pre_1_4_compatible,
+ svnadmin__pre_1_5_compatible
   };
 
 /* Option codes and descriptions.
@@ -295,6 +296,10 @@ static const apr_getopt_option_t options
      N_("use format compatible with Subversion versions\n"
         " earlier than 1.4")},
 
+ {"pre-1.5-compatible", svnadmin__pre_1_5_compatible, 0,
+ N_("use format compatible with Subversion versions\n"
+ " earlier than 1.5")},
+
     {NULL}
   };
 
@@ -314,7 +319,8 @@ static const svn_opt_subcommand_desc_t c
    ("usage: svnadmin create REPOS_PATH\n\n"
     "Create a new, empty repository at REPOS_PATH.\n"),
    {svnadmin__bdb_txn_nosync, svnadmin__bdb_log_keep,
- svnadmin__config_dir, svnadmin__fs_type, svnadmin__pre_1_4_compatible} },
+ svnadmin__config_dir, svnadmin__fs_type, svnadmin__pre_1_4_compatible,
+ svnadmin__pre_1_5_compatible } },
 
   {"deltify", subcommand_deltify, {0}, N_
    ("usage: svnadmin deltify [-r LOWER[:UPPER]] REPOS_PATH\n\n"
@@ -434,6 +440,7 @@ struct svnadmin_opt_state
   const char *new_repository_path; /* hotcopy dest. path */
   const char *fs_type; /* --fs-type */
   svn_boolean_t pre_1_4_compatible; /* --pre-1.4-compatible */
+ svn_boolean_t pre_1_5_compatible; /* --pre-1.5-compatible */
   svn_opt_revision_t start_revision, end_revision; /* -r X[:Y] */
   svn_boolean_t help; /* --help or -? */
   svn_boolean_t version; /* --version */
@@ -514,6 +521,11 @@ subcommand_create(apr_getopt_t *os, void
                  APR_HASH_KEY_STRING,
                  "1");
 
+ if (opt_state->pre_1_5_compatible)
+ apr_hash_set(fs_config, SVN_FS_CONFIG_PRE_1_5_COMPATIBLE,
+ APR_HASH_KEY_STRING,
+ "1");
+
   SVN_ERR(svn_config_get_config(&config, opt_state->config_dir, pool));
   SVN_ERR(svn_repos_create(&repos, opt_state->repository_path,
                            NULL, NULL,
@@ -1343,7 +1355,10 @@ main(int argc, const char *argv[])
         break;
       case svnadmin__pre_1_4_compatible:
         opt_state.pre_1_4_compatible = TRUE;
- break;
+ break;
+ case svnadmin__pre_1_5_compatible:
+ opt_state.pre_1_5_compatible = TRUE;
+ break;
       case svnadmin__fs_type:
         err = svn_utf_cstring_to_utf8(&opt_state.fs_type, opt_arg, pool);
         if (err)

  • application/pgp-signature attachment: stored
Received on Wed Apr 4 18:55:38 2007

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.