aboutsummaryrefslogtreecommitdiff
path: root/subversion/libsvn_fs_x/fs_x.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_fs_x/fs_x.c')
-rw-r--r--subversion/libsvn_fs_x/fs_x.c169
1 files changed, 118 insertions, 51 deletions
diff --git a/subversion/libsvn_fs_x/fs_x.c b/subversion/libsvn_fs_x/fs_x.c
index b766b58b2201..ba1982f278bb 100644
--- a/subversion/libsvn_fs_x/fs_x.c
+++ b/subversion/libsvn_fs_x/fs_x.c
@@ -33,6 +33,7 @@
#include "cached_data.h"
#include "id.h"
+#include "low_level.h"
#include "rep-cache.h"
#include "revprops.h"
#include "transaction.h"
@@ -95,13 +96,27 @@ check_format(int format)
{
/* Put blacklisted versions here. */
- /* We support all formats from 1-current simultaneously */
- if (1 <= format && format <= SVN_FS_X__FORMAT_NUMBER)
+ /* We support any format if it matches the current format. */
+ if (format == SVN_FS_X__FORMAT_NUMBER)
+ return SVN_NO_ERROR;
+
+ /* Experimental formats are only supported if they match the current, but
+ * that case has already been handled. So, reject any experimental format.
+ */
+ if (SVN_FS_X__EXPERIMENTAL_FORMAT_NUMBER >= format)
+ return svn_error_createf(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL,
+ _("Unsupported experimental FSX format '%d' found; current format is '%d'"),
+ format, SVN_FS_X__FORMAT_NUMBER);
+
+ /* By default, we will support any non-experimental format released so far.
+ */
+ if (format <= SVN_FS_X__FORMAT_NUMBER)
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_X__FORMAT_NUMBER, format);
+ _("Expected FSX format between '%d' and '%d'; found format '%d'"),
+ SVN_FS_X__EXPERIMENTAL_FORMAT_NUMBER + 1, SVN_FS_X__FORMAT_NUMBER,
+ format);
}
/* Read the format file at PATH and set *PFORMAT to the format version found
@@ -184,8 +199,9 @@ svn_fs_x__write_format(svn_fs_t *fs,
}
else
{
- SVN_ERR(svn_io_write_atomic(path, sb->data, sb->len,
- NULL /* copy_perms_path */, scratch_pool));
+ SVN_ERR(svn_io_write_atomic2(path, sb->data, sb->len,
+ NULL /* copy_perms_path */,
+ ffd->flush_to_disk, scratch_pool));
}
/* And set the perms to make it read only */
@@ -519,6 +535,20 @@ write_config(svn_fs_t *fs,
fsx_conf_contents, scratch_pool);
}
+/* Read / Evaluate the global configuration in FS->CONFIG to set up
+ * parameters in FS. */
+static svn_error_t *
+read_global_config(svn_fs_t *fs)
+{
+ svn_fs_x__data_t *ffd = fs->fsap_data;
+
+ ffd->flush_to_disk = !svn_hash__get_bool(fs->config,
+ SVN_FS_CONFIG_NO_FLUSH_TO_DISK,
+ FALSE);
+
+ return SVN_NO_ERROR;
+}
+
/* Read FS's UUID file and store the data in the FS struct. */
static svn_error_t *
read_uuid(svn_fs_t *fs,
@@ -587,8 +617,12 @@ svn_fs_x__open(svn_fs_t *fs,
/* Read the configuration file. */
SVN_ERR(read_config(ffd, fs->path, fs->pool, scratch_pool));
- return svn_error_trace(svn_fs_x__read_current(&ffd->youngest_rev_cache,
- fs, scratch_pool));
+ /* Global configuration options. */
+ SVN_ERR(read_global_config(fs));
+
+ ffd->youngest_rev_cache = 0;
+
+ return SVN_NO_ERROR;
}
/* Baton type bridging svn_fs_x__upgrade and upgrade_body carrying
@@ -840,16 +874,14 @@ static svn_error_t *
write_revision_zero(svn_fs_t *fs,
apr_pool_t *scratch_pool)
{
- /* Use an explicit sub-pool to have full control over temp file lifetimes.
- * Since we have it, use it for everything else as well. */
- apr_pool_t *subpool = svn_pool_create(scratch_pool);
- const char *path_revision_zero = svn_fs_x__path_rev(fs, 0, subpool);
+ const char *path_revision_zero = svn_fs_x__path_rev(fs, 0, scratch_pool);
apr_hash_t *proplist;
svn_string_t date;
apr_array_header_t *index_entries;
svn_fs_x__p2l_entry_t *entry;
svn_fs_x__revision_file_t *rev_file;
+ apr_file_t *apr_file;
const char *l2p_proto_index, *p2l_proto_index;
/* Construct a skeleton r0 with no indexes. */
@@ -860,62 +892,72 @@ write_revision_zero(svn_fs_t *fs,
"count: 0\n"
"cpath: /\n"
"\n",
- subpool);
+ scratch_pool);
svn_string_t *changes_str = svn_string_create("\n",
- subpool);
- svn_string_t *r0 = svn_string_createf(subpool, "%s%s",
+ scratch_pool);
+ svn_string_t *r0 = svn_string_createf(scratch_pool, "%s%s",
noderev_str->data,
changes_str->data);
/* Write skeleton r0 to disk. */
- SVN_ERR(svn_io_file_create(path_revision_zero, r0->data, subpool));
+ SVN_ERR(svn_io_file_create(path_revision_zero, r0->data, scratch_pool));
/* Construct the index P2L contents: describe the 2 items we have.
Be sure to create them in on-disk order. */
- index_entries = apr_array_make(subpool, 2, sizeof(entry));
+ index_entries = apr_array_make(scratch_pool, 2, sizeof(entry));
- entry = apr_pcalloc(subpool, sizeof(*entry));
+ entry = apr_pcalloc(scratch_pool, sizeof(*entry));
entry->offset = 0;
entry->size = (apr_off_t)noderev_str->len;
entry->type = SVN_FS_X__ITEM_TYPE_NODEREV;
entry->item_count = 1;
- entry->items = apr_pcalloc(subpool, sizeof(*entry->items));
+ entry->items = apr_pcalloc(scratch_pool, sizeof(*entry->items));
entry->items[0].change_set = 0;
entry->items[0].number = SVN_FS_X__ITEM_INDEX_ROOT_NODE;
APR_ARRAY_PUSH(index_entries, svn_fs_x__p2l_entry_t *) = entry;
- entry = apr_pcalloc(subpool, sizeof(*entry));
+ entry = apr_pcalloc(scratch_pool, sizeof(*entry));
entry->offset = (apr_off_t)noderev_str->len;
entry->size = (apr_off_t)changes_str->len;
entry->type = SVN_FS_X__ITEM_TYPE_CHANGES;
entry->item_count = 1;
- entry->items = apr_pcalloc(subpool, sizeof(*entry->items));
+ entry->items = apr_pcalloc(scratch_pool, sizeof(*entry->items));
entry->items[0].change_set = 0;
entry->items[0].number = SVN_FS_X__ITEM_INDEX_CHANGES;
APR_ARRAY_PUSH(index_entries, svn_fs_x__p2l_entry_t *) = entry;
/* Now re-open r0, create proto-index files from our entries and
- rewrite the index section of r0. */
- SVN_ERR(svn_fs_x__open_pack_or_rev_file_writable(&rev_file, fs, 0,
- subpool, subpool));
+ rewrite the index section of r0. */
+ SVN_ERR(svn_fs_x__rev_file_open_writable(&rev_file, fs, 0,
+ scratch_pool, scratch_pool));
SVN_ERR(svn_fs_x__p2l_index_from_p2l_entries(&p2l_proto_index, fs,
rev_file, index_entries,
- subpool, subpool));
+ scratch_pool, scratch_pool));
SVN_ERR(svn_fs_x__l2p_index_from_p2l_entries(&l2p_proto_index, fs,
index_entries,
- subpool, subpool));
- SVN_ERR(svn_fs_x__add_index_data(fs, rev_file->file, l2p_proto_index,
- p2l_proto_index, 0, subpool));
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_fs_x__rev_file_get(&apr_file, rev_file));
+ SVN_ERR(svn_fs_x__add_index_data(fs, apr_file, l2p_proto_index,
+ p2l_proto_index, 0, scratch_pool));
SVN_ERR(svn_fs_x__close_revision_file(rev_file));
- SVN_ERR(svn_io_set_file_read_only(path_revision_zero, FALSE, fs->pool));
+ SVN_ERR(svn_io_set_file_read_only(path_revision_zero, FALSE, scratch_pool));
/* Set a date on revision 0. */
- date.data = svn_time_to_cstring(apr_time_now(), fs->pool);
+ date.data = svn_time_to_cstring(apr_time_now(), scratch_pool);
date.len = strlen(date.data);
- proplist = apr_hash_make(fs->pool);
+ proplist = apr_hash_make(scratch_pool);
svn_hash_sets(proplist, SVN_PROP_REVISION_DATE, &date);
- return svn_fs_x__set_revision_proplist(fs, 0, proplist, fs->pool);
+
+ SVN_ERR(svn_io_file_open(&apr_file,
+ svn_fs_x__path_revprops(fs, 0, scratch_pool),
+ APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
+ scratch_pool));
+ SVN_ERR(svn_fs_x__write_non_packed_revprops(apr_file, proplist,
+ scratch_pool));
+ SVN_ERR(svn_io_file_close(apr_file, scratch_pool));
+
+ return SVN_NO_ERROR;
}
svn_error_t *
@@ -935,14 +977,9 @@ svn_fs_x__create_file_tree(svn_fs_t *fs,
/* Create the revision data directories. */
SVN_ERR(svn_io_make_dir_recursively(
- svn_fs_x__path_rev_shard(fs, 0, scratch_pool),
+ svn_fs_x__path_shard(fs, 0, scratch_pool),
scratch_pool));
- /* Create the revprops directory. */
- SVN_ERR(svn_io_make_dir_recursively(
- svn_fs_x__path_revprops_shard(fs, 0, scratch_pool),
- scratch_pool));
-
/* Create the transaction directory. */
SVN_ERR(svn_io_make_dir_recursively(
svn_fs_x__path_txns_dir(fs, scratch_pool),
@@ -954,19 +991,21 @@ svn_fs_x__create_file_tree(svn_fs_t *fs,
scratch_pool));
/* Create the 'current' file. */
- SVN_ERR(svn_io_file_create_empty(svn_fs_x__path_current(fs, scratch_pool),
- scratch_pool));
- SVN_ERR(svn_fs_x__write_current(fs, 0, scratch_pool));
+ SVN_ERR(svn_io_file_create(svn_fs_x__path_current(fs, scratch_pool),
+ "0\n", scratch_pool));
/* Create the 'uuid' file. */
SVN_ERR(svn_io_file_create_empty(svn_fs_x__path_lock(fs, scratch_pool),
scratch_pool));
- SVN_ERR(svn_fs_x__set_uuid(fs, NULL, NULL, scratch_pool));
+ SVN_ERR(svn_fs_x__set_uuid(fs, NULL, NULL, FALSE, scratch_pool));
/* Create the fsfs.conf file. */
SVN_ERR(write_config(fs, scratch_pool));
SVN_ERR(read_config(ffd, fs->path, fs->pool, scratch_pool));
+ /* Global configuration options. */
+ SVN_ERR(read_global_config(fs));
+
/* Add revision 0. */
SVN_ERR(write_revision_zero(fs, scratch_pool));
@@ -984,6 +1023,9 @@ svn_fs_x__create_file_tree(svn_fs_t *fs,
scratch_pool));
/* Initialize the revprop caching info. */
+ SVN_ERR(svn_io_file_create_empty(
+ svn_fs_x__path_revprop_generation(fs, scratch_pool),
+ scratch_pool));
SVN_ERR(svn_fs_x__reset_revprop_generation_file(fs, scratch_pool));
ffd->youngest_rev_cache = 0;
@@ -1040,6 +1082,7 @@ svn_error_t *
svn_fs_x__set_uuid(svn_fs_t *fs,
const char *uuid,
const char *instance_id,
+ svn_boolean_t overwrite,
apr_pool_t *scratch_pool)
{
svn_fs_x__data_t *ffd = fs->fsap_data;
@@ -1058,11 +1101,23 @@ svn_fs_x__set_uuid(svn_fs_t *fs,
svn_stringbuf_appendcstr(contents, "\n");
/* We use the permissions of the 'current' file, because the 'uuid'
- file does not exist during repository creation. */
- SVN_ERR(svn_io_write_atomic(uuid_path, contents->data, contents->len,
- /* perms */
- svn_fs_x__path_current(fs, scratch_pool),
- scratch_pool));
+ file does not exist during repository creation.
+
+ svn_io_write_atomic2() 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(uuid_path, contents->data, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(svn_io_write_atomic2(uuid_path, contents->data, contents->len,
+ /* perms */
+ svn_fs_x__path_current(fs, scratch_pool),
+ ffd->flush_to_disk, scratch_pool));
+ }
fs->uuid = apr_pstrdup(fs->pool, uuid);
ffd->instance_id = apr_pstrdup(fs->pool, instance_id);
@@ -1100,13 +1155,14 @@ svn_fs_x__revision_prop(svn_string_t **value_p,
svn_fs_t *fs,
svn_revnum_t rev,
const char *propname,
+ svn_boolean_t refresh,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_hash_t *table;
SVN_ERR(svn_fs__check_fs(fs, TRUE));
- SVN_ERR(svn_fs_x__get_revision_proplist(&table, fs, rev, FALSE,
+ SVN_ERR(svn_fs_x__get_revision_proplist(&table, fs, rev, FALSE, refresh,
scratch_pool, scratch_pool));
*value_p = svn_string_dup(svn_hash_gets(table, propname), result_pool);
@@ -1133,17 +1189,18 @@ change_rev_prop_body(void *baton,
{
change_rev_prop_baton_t *cb = baton;
apr_hash_t *table;
+ const svn_string_t *present_value;
/* Read current revprop values from disk (never from cache).
Even if somehow the cache got out of sync, we want to make sure that
we read, update and write up-to-date data. */
SVN_ERR(svn_fs_x__get_revision_proplist(&table, cb->fs, cb->rev, TRUE,
- scratch_pool, scratch_pool));
+ TRUE, scratch_pool, scratch_pool));
+ present_value = svn_hash_gets(table, cb->name);
if (cb->old_value_p)
{
const svn_string_t *wanted_value = *cb->old_value_p;
- const svn_string_t *present_value = svn_hash_gets(table, cb->name);
if ((!wanted_value != !present_value)
|| (wanted_value && present_value
&& !svn_string_compare(wanted_value, present_value)))
@@ -1156,6 +1213,13 @@ change_rev_prop_body(void *baton,
}
/* Fall through. */
}
+
+ /* If the prop-set is a no-op, skip the actual write. */
+ if ((!present_value && !cb->value)
+ || (present_value && cb->value
+ && svn_string_compare(present_value, cb->value)))
+ return SVN_NO_ERROR;
+
svn_hash_sets(table, cb->name, cb->value);
return svn_fs_x__set_revision_proplist(cb->fs, cb->rev, table,
@@ -1205,8 +1269,11 @@ svn_fs_x__info_format(int *fs_format,
{
case 1:
break;
+ case 2:
+ (*supports_version)->minor = 10;
+ break;
#ifdef SVN_DEBUG
-# if SVN_FS_X__FORMAT_NUMBER != 1
+# if SVN_FS_X__FORMAT_NUMBER != 2
# error "Need to add a 'case' statement here"
# endif
#endif