You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2016/04/29 20:38:56 UTC
svn commit: r1741682 [9/26] - in /subversion/branches/authzperf: ./ build/
build/ac-macros/ build/generator/ contrib/server-side/svncutter/ notes/
notes/api-errata/1.9/ notes/move-tracking/ subversion/
subversion/bindings/ctypes-python/ subversion/bind...
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/cached_data.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/cached_data.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/cached_data.c Fri Apr 29 18:38:53 2016
@@ -30,6 +30,7 @@
#include "private/svn_io_private.h"
#include "private/svn_sorts_private.h"
+#include "private/svn_string_private.h"
#include "private/svn_subr_private.h"
#include "private/svn_temp_serializer.h"
@@ -54,6 +55,7 @@ block_read(void **result,
svn_fs_t *fs,
const svn_fs_x__id_t *id,
svn_fs_x__revision_file_t *revision_file,
+ void *baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
@@ -288,14 +290,13 @@ get_node_revision_body(svn_fs_x__noderev
scratch_pool),
APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
scratch_pool);
- if (err)
+ if (err && APR_STATUS_IS_ENOENT(err->apr_err))
+ {
+ svn_error_clear(err);
+ return svn_error_trace(err_dangling_id(fs, id));
+ }
+ else if (err)
{
- if (APR_STATUS_IS_ENOENT(err->apr_err))
- {
- svn_error_clear(err);
- return svn_error_trace(err_dangling_id(fs, id));
- }
-
return svn_error_trace(err);
}
@@ -352,6 +353,7 @@ get_node_revision_body(svn_fs_x__noderev
SVN_ERR(block_read((void **)noderev_p, fs,
id,
revision_file,
+ NULL,
result_pool,
scratch_pool));
SVN_ERR(svn_fs_x__close_revision_file(revision_file));
@@ -698,7 +700,7 @@ create_rep_state_body(rep_state_t **rep_
/* populate the cache if appropriate */
if (SVN_IS_VALID_REVNUM(revision))
{
- SVN_ERR(block_read(NULL, fs, &rs->rep_id, rs->sfile->rfile,
+ SVN_ERR(block_read(NULL, fs, &rs->rep_id, rs->sfile->rfile, NULL,
result_pool, scratch_pool));
SVN_ERR(svn_cache__set(ffd->rep_header_cache, &key, rh,
scratch_pool));
@@ -1310,7 +1312,7 @@ read_delta_window(svn_txdelta_window_t *
&& svn_fs_x__is_revision(rs->rep_id.change_set)
&& rs->window_cache)
{
- SVN_ERR(block_read(NULL, rs->sfile->fs, &rs->rep_id, file,
+ SVN_ERR(block_read(NULL, rs->sfile->fs, &rs->rep_id, file, NULL,
result_pool, scratch_pool));
/* reading the whole block probably also provided us with the
@@ -1341,7 +1343,7 @@ read_delta_window(svn_txdelta_window_t *
SVN_ERR(svn_fs_x__rev_file_get(&apr_file, file));
SVN_ERR(svn_txdelta_skip_svndiff_window(apr_file, rs->ver, iterpool));
rs->chunk_index++;
- SVN_ERR(svn_fs_x__get_file_offset(&start_offset, apr_file, iterpool));
+ SVN_ERR(svn_io_file_get_offset(&start_offset, apr_file, iterpool));
rs->current = start_offset - rs->start;
if (rs->current >= rs->size)
@@ -1405,7 +1407,8 @@ read_container_window(svn_stringbuf_t **
{
SVN_ERR(auto_open_shared_file(rs->sfile));
SVN_ERR(block_read((void **)&extractor, fs, &rs->rep_id,
- rs->sfile->rfile, result_pool, scratch_pool));
+ rs->sfile->rfile, NULL,
+ result_pool, scratch_pool));
}
SVN_ERR(svn_fs_x__extractor_drive(nwin, extractor, rs->current, size,
@@ -1510,7 +1513,7 @@ get_combined_window(svn_stringbuf_t **re
}
/* Returns whether or not the expanded fulltext of the file is cachable
- * based on its size SIZE. The decision depends on the cache used by RB.
+ * based on its size SIZE. The decision depends on the cache used by FFD.
*/
static svn_boolean_t
fulltext_size_is_cachable(svn_fs_x__data_t *ffd,
@@ -1748,10 +1751,10 @@ get_contents_from_windows(rep_read_baton
This is where we need the pseudo rep_state created
by build_rep_list(). */
apr_size_t offset = (apr_size_t)rs->current;
- if (copy_len + offset > rb->base_window->len)
- copy_len = offset < rb->base_window->len
- ? rb->base_window->len - offset
- : 0ul;
+ if (offset >= rb->base_window->len)
+ copy_len = 0ul;
+ else if (copy_len > rb->base_window->len - offset)
+ copy_len = rb->base_window->len - offset;
memcpy (cur, rb->base_window->data + offset, copy_len);
}
@@ -2366,117 +2369,147 @@ compare_dirent_name(const void *a,
return strcmp(lhs->name, rhs);
}
-/* Into ENTRIES, read all directories entries from the key-value text in
- * STREAM. If INCREMENTAL is TRUE, read until the end of the STREAM and
+/* Into ENTRIES, parse all directories entries from the serialized form in
+ * DATA. If INCREMENTAL is TRUE, read until the end of the STREAM and
* update the data. ID is provided for nicer error messages.
+ *
+ * The contents of DATA will be shared with the items in ENTRIES, i.e. it
+ * must not be modified afterwards and must remain valid as long as ENTRIES
+ * is valid. Use SCRATCH_POOL for temporary allocations.
*/
static svn_error_t *
-read_dir_entries(apr_array_header_t *entries,
- svn_stream_t *stream,
- svn_boolean_t incremental,
- const svn_fs_x__id_t *id,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+parse_dir_entries(apr_array_header_t **entries_p,
+ const svn_stringbuf_t *data,
+ svn_boolean_t incremental,
+ const svn_fs_x__id_t *id,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ const apr_byte_t *p = (const apr_byte_t *)data->data;
+ const apr_byte_t *end = p + data->len;
+ apr_uint64_t count;
apr_hash_t *hash = incremental ? svn_hash__make(scratch_pool) : NULL;
- const char *terminator = SVN_HASH_TERMINATOR;
-
- /* Read until the terminator (non-incremental) or the end of STREAM
- (incremental mode). In the latter mode, we use a temporary HASH
- to make updating and removing entries cheaper. */
- while (1)
- {
- svn_hash__entry_t entry;
- svn_fs_x__dirent_t *dirent;
- char *str;
-
- svn_pool_clear(iterpool);
- SVN_ERR(svn_hash__read_entry(&entry, stream, terminator,
- incremental, iterpool));
+ apr_array_header_t *entries;
- /* End of directory? */
- if (entry.key == NULL)
- {
- /* In incremental mode, we skip the terminator and read the
- increments following it until the end of the stream. */
- if (incremental && terminator)
- terminator = NULL;
- else
- break;
- }
+ /* Construct the resulting container. */
+ p = svn__decode_uint(&count, p, end);
+ if (count > INT_MAX)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory for '%s' is too large"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
- /* Deleted entry? */
- if (entry.val == NULL)
- {
- /* We must be in incremental mode */
- assert(hash);
- apr_hash_set(hash, entry.key, entry.keylen, NULL);
- continue;
- }
+ entries = apr_array_make(result_pool, (int)count,
+ sizeof(svn_fs_x__dirent_t *));
- /* Add a new directory entry. */
+ while (p != end)
+ {
+ apr_size_t len;
+ svn_fs_x__dirent_t *dirent;
dirent = apr_pcalloc(result_pool, sizeof(*dirent));
- dirent->name = apr_pstrmemdup(result_pool, entry.key, entry.keylen);
- str = svn_cstring_tokenize(" ", &entry.val);
- if (str == NULL)
+ /* The part of the serialized entry that is not the name will be
+ * about 6 bytes or less. Since APR allocates with an 8 byte
+ * alignment (4 bytes loss on average per string), simply using
+ * the name string in DATA already gives us near-optimal memory
+ * usage. */
+ dirent->name = (const char *)p;
+ len = strlen(dirent->name);
+ p += len + 1;
+ if (p == end)
return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, scratch_pool)->data);
+ _("Directory entry missing kind in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
- if (strcmp(str, SVN_FS_X__KIND_FILE) == 0)
- {
- dirent->kind = svn_node_file;
- }
- else if (strcmp(str, SVN_FS_X__KIND_DIR) == 0)
- {
- dirent->kind = svn_node_dir;
- }
- else
- {
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, scratch_pool)->data);
- }
+ dirent->kind = (svn_node_kind_t)*(p++);
+ if (p == end)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory entry missing change set in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
- str = svn_cstring_tokenize(" ", &entry.val);
- if (str == NULL)
+ p = svn__decode_int(&dirent->id.change_set, p, end);
+ if (p == end)
return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, scratch_pool)->data);
+ _("Directory entry missing item number in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
- SVN_ERR(svn_fs_x__id_parse(&dirent->id, str));
+ p = svn__decode_uint(&dirent->id.number, p, end);
/* In incremental mode, update the hash; otherwise, write to the
* final array. */
if (incremental)
- apr_hash_set(hash, dirent->name, entry.keylen, dirent);
+ {
+ /* Insertion / update or a deletion? */
+ if (svn_fs_x__id_used(&dirent->id))
+ apr_hash_set(hash, dirent->name, len, dirent);
+ else
+ apr_hash_set(hash, dirent->name, len, NULL);
+ }
else
- APR_ARRAY_PUSH(entries, svn_fs_x__dirent_t *) = dirent;
+ {
+ APR_ARRAY_PUSH(entries, svn_fs_x__dirent_t *) = dirent;
+ }
}
- /* Convert container to a sorted array. */
if (incremental)
{
+ /* Convert container into a sorted array. */
apr_hash_index_t *hi;
- for (hi = apr_hash_first(iterpool, hash); hi; hi = apr_hash_next(hi))
+ for (hi = apr_hash_first(scratch_pool, hash); hi; hi = apr_hash_next(hi))
APR_ARRAY_PUSH(entries, svn_fs_x__dirent_t *) = apr_hash_this_val(hi);
+
+ if (!sorted(entries))
+ svn_sort__array(entries, compare_dirents);
+ }
+ else
+ {
+ /* Check that we read the expected amount of entries. */
+ if ((apr_uint64_t)entries->nelts != count)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory length mismatch in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
}
- if (!sorted(entries))
- svn_sort__array(entries, compare_dirents);
+ *entries_p = entries;
- svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
+/* For directory NODEREV in FS, return the *FILESIZE of its in-txn
+ * representation. If the directory representation is comitted data,
+ * set *FILESIZE to SVN_INVALID_FILESIZE. Use SCRATCH_POOL for temporaries.
+ */
+static svn_error_t *
+get_txn_dir_info(svn_filesize_t *filesize,
+ svn_fs_t *fs,
+ svn_fs_x__noderev_t *noderev,
+ apr_pool_t *scratch_pool)
+{
+ if (noderev->data_rep
+ && ! svn_fs_x__is_revision(noderev->data_rep->id.change_set))
+ {
+ const svn_io_dirent2_t *dirent;
+ const char *filename;
+
+ filename = svn_fs_x__path_txn_node_children(fs, &noderev->noderev_id,
+ scratch_pool, scratch_pool);
+
+ SVN_ERR(svn_io_stat_dirent2(&dirent, filename, FALSE, FALSE,
+ scratch_pool, scratch_pool));
+ *filesize = dirent->filesize;
+ }
+ else
+ {
+ *filesize = SVN_INVALID_FILESIZE;
+ }
return SVN_NO_ERROR;
}
-/* Fetch the contents of a directory into ENTRIES. Values are stored
+/* Fetch the contents of a directory into DIR. Values are stored
as filename to string mappings; further conversion is necessary to
convert them into svn_fs_x__dirent_t values. */
static svn_error_t *
-get_dir_contents(apr_array_header_t **entries,
+get_dir_contents(svn_fs_x__dir_data_t *dir,
svn_fs_t *fs,
svn_fs_x__noderev_t *noderev,
apr_pool_t *result_pool,
@@ -2484,43 +2517,66 @@ get_dir_contents(apr_array_header_t **en
{
svn_stream_t *contents;
const svn_fs_x__id_t *id = &noderev->noderev_id;
+ apr_size_t len;
+ svn_stringbuf_t *text;
+ svn_boolean_t incremental;
+
+ /* Initialize the result. */
+ dir->txn_filesize = SVN_INVALID_FILESIZE;
- *entries = apr_array_make(result_pool, 16, sizeof(svn_fs_x__dirent_t *));
+ /* Read dir contents - unless there is none in which case we are done. */
if (noderev->data_rep
&& ! svn_fs_x__is_revision(noderev->data_rep->id.change_set))
{
- const char *filename
- = svn_fs_x__path_txn_node_children(fs, id, scratch_pool,
- scratch_pool);
+ /* Get location & current size of the directory representation. */
+ const char *filename;
+ apr_file_t *file;
+
+ filename = svn_fs_x__path_txn_node_children(fs, id, scratch_pool,
+ scratch_pool);
/* The representation is mutable. Read the old directory
contents from the mutable children file, followed by the
changes we've made in this transaction. */
- SVN_ERR(svn_stream_open_readonly(&contents, filename, scratch_pool,
- scratch_pool));
- SVN_ERR(read_dir_entries(*entries, contents, TRUE, id,
- result_pool, scratch_pool));
- SVN_ERR(svn_stream_close(contents));
+ SVN_ERR(svn_io_file_open(&file, filename, APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT, scratch_pool));
+
+ /* Obtain txn children file size. */
+ SVN_ERR(svn_io_file_size_get(&dir->txn_filesize, file, scratch_pool));
+ len = (apr_size_t)dir->txn_filesize;
+
+ /* Finally, provide stream access to FILE. */
+ contents = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
+ incremental = TRUE;
}
else if (noderev->data_rep)
{
- /* Undeltify content before parsing it. Otherwise, we could only
- * parse it byte-by-byte.
- */
- apr_size_t len = noderev->data_rep->expanded_size;
- svn_stringbuf_t *text;
-
/* The representation is immutable. Read it normally. */
+ len = noderev->data_rep->expanded_size;
SVN_ERR(svn_fs_x__get_contents(&contents, fs, noderev->data_rep,
FALSE, scratch_pool));
- SVN_ERR(svn_stringbuf_from_stream(&text, contents, len, scratch_pool));
- SVN_ERR(svn_stream_close(contents));
-
- /* de-serialize hash */
- contents = svn_stream_from_stringbuf(text, scratch_pool);
- SVN_ERR(read_dir_entries(*entries, contents, FALSE, id,
- result_pool, scratch_pool));
+ incremental = FALSE;
}
+ else
+ {
+ /* Empty representation == empty directory. */
+ dir->entries = apr_array_make(result_pool, 0,
+ sizeof(svn_fs_x__dirent_t *));
+ return SVN_NO_ERROR;
+ }
+
+ /* Read the whole stream contents into a single buffer.
+ * Due to our LEN hint, no allocation overhead occurs.
+ *
+ * Also, a large portion of TEXT will be file / dir names which we
+ * directly reference from DIR->ENTRIES instead of copying them.
+ * Hence, we need to use the RESULT_POOL here. */
+ SVN_ERR(svn_stringbuf_from_stream(&text, contents, len, result_pool));
+ SVN_ERR(svn_stream_close(contents));
+
+ /* de-serialize hash */
+ SVN_ERR(parse_dir_entries(&dir->entries, text, incremental, id,
+ result_pool, scratch_pool));
return SVN_NO_ERROR;
}
@@ -2535,26 +2591,24 @@ locate_dir_cache(svn_fs_t *fs,
svn_fs_x__noderev_t *noderev)
{
svn_fs_x__data_t *ffd = fs->fsap_data;
- if (svn_fs_x__is_txn(noderev->noderev_id.change_set))
+
+ if (!noderev->data_rep)
+ {
+ /* no data rep -> empty directory.
+ Use a key that does definitely not clash with non-NULL reps. */
+ key->change_set = SVN_FS_X__INVALID_CHANGE_SET;
+ key->number = SVN_FS_X__ITEM_INDEX_UNUSED;
+ }
+ else if (svn_fs_x__is_txn(noderev->noderev_id.change_set))
{
- /* data in txns must be addressed by ID since the representation has
- not been created, yet. */
+ /* data in txns must be addressed by noderev ID since the
+ representation has not been created, yet. */
*key = noderev->noderev_id;
}
else
{
/* committed data can use simple rev,item pairs */
- if (noderev->data_rep)
- {
- *key = noderev->data_rep->id;
- }
- else
- {
- /* no data rep -> empty directory.
- Use a key that does definitely not clash with non-NULL reps. */
- key->change_set = SVN_FS_X__INVALID_CHANGE_SET;
- key->number = SVN_FS_X__ITEM_INDEX_UNUSED;
- }
+ *key = noderev->data_rep->id;
}
return ffd->dir_cache;
@@ -2568,22 +2622,40 @@ svn_fs_x__rep_contents_dir(apr_array_hea
apr_pool_t *scratch_pool)
{
svn_fs_x__id_t key;
+ svn_fs_x__dir_data_t *dir;
/* find the cache we may use */
svn_cache__t *cache = locate_dir_cache(fs, &key, noderev);
svn_boolean_t found;
- SVN_ERR(svn_cache__get((void **)entries_p, &found, cache, &key,
- result_pool));
+ SVN_ERR(svn_cache__get((void **)&dir, &found, cache, &key, result_pool));
if (found)
- return SVN_NO_ERROR;
+ {
+ /* Verify that the cached dir info is not stale
+ * (no-op for committed data). */
+ svn_filesize_t filesize;
+ SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
+
+ if (filesize == dir->txn_filesize)
+ {
+ /* Still valid. Done. */
+ *entries_p = dir->entries;
+ return SVN_NO_ERROR;
+ }
+ }
/* Read in the directory contents. */
- SVN_ERR(get_dir_contents(entries_p, fs, noderev, result_pool,
- scratch_pool));
+ dir = apr_pcalloc(scratch_pool, sizeof(*dir));
+ SVN_ERR(get_dir_contents(dir, fs, noderev, result_pool, scratch_pool));
+ *entries_p = dir->entries;
- /* Update the cache, if we are to use one. */
- SVN_ERR(svn_cache__set(cache, &key, *entries_p, scratch_pool));
+ /* Update the cache, if we are to use one.
+ *
+ * Don't even attempt to serialize very large directories; it would cause
+ * an unnecessary memory allocation peak. 100 bytes/entry is about right.
+ */
+ if (svn_cache__is_cachable(cache, 100 * dir->entries->nelts))
+ SVN_ERR(svn_cache__set(cache, &key, dir, scratch_pool));
return SVN_NO_ERROR;
}
@@ -2613,10 +2685,15 @@ svn_fs_x__rep_contents_dir_entry(svn_fs_
svn_fs_x__id_t key;
svn_cache__t *cache = locate_dir_cache(fs, &key, noderev);
svn_fs_x__ede_baton_t baton;
+
+ svn_filesize_t filesize;
+ SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
+
+ /* Cache lookup. */
baton.hint = *hint;
baton.name = name;
+ baton.txn_filesize = filesize;
- /* Cache lookup. */
SVN_ERR(svn_cache__get_partial((void **)dirent,
&found,
cache,
@@ -2630,19 +2707,26 @@ svn_fs_x__rep_contents_dir_entry(svn_fs_
*hint = baton.hint;
/* fetch data from disk if we did not find it in the cache */
- if (! found)
+ if (! found || baton.out_of_date)
{
- apr_array_header_t *entries;
svn_fs_x__dirent_t *entry;
svn_fs_x__dirent_t *entry_copy = NULL;
+ svn_fs_x__dir_data_t dir;
+
+ /* Read in the directory contents. */
+ SVN_ERR(get_dir_contents(&dir, fs, noderev, scratch_pool,
+ scratch_pool));
- /* read the dir from the file system. It will probably be put it
- into the cache for faster lookup in future calls. */
- SVN_ERR(svn_fs_x__rep_contents_dir(&entries, fs, noderev,
- scratch_pool, scratch_pool));
+ /* Update the cache, if we are to use one.
+ *
+ * Don't even attempt to serialize very large directories; it would
+ * cause an unnecessary memory allocation peak. 150 bytes / entry is
+ * about right. */
+ if (cache && svn_cache__is_cachable(cache, 150 * dir.entries->nelts))
+ SVN_ERR(svn_cache__set(cache, &key, &dir, scratch_pool));
/* find desired entry and return a copy in POOL, if found */
- entry = svn_fs_x__find_dir_entry(entries, name, NULL);
+ entry = svn_fs_x__find_dir_entry(dir.entries, name, NULL);
if (entry)
{
entry_copy = apr_pmemdup(result_pool, entry, sizeof(*entry_copy));
@@ -2656,135 +2740,156 @@ svn_fs_x__rep_contents_dir_entry(svn_fs_
}
svn_error_t *
-svn_fs_x__get_proplist(apr_hash_t **proplist_p,
+svn_fs_x__get_proplist(apr_hash_t **proplist,
svn_fs_t *fs,
svn_fs_x__noderev_t *noderev,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_hash_t *proplist;
svn_stream_t *stream;
const svn_fs_x__id_t *noderev_id = &noderev->noderev_id;
if (noderev->prop_rep
&& !svn_fs_x__is_revision(noderev->prop_rep->id.change_set))
{
+ svn_stringbuf_t *content;
+ svn_string_t *as_string;
const char *filename = svn_fs_x__path_txn_node_props(fs, noderev_id,
scratch_pool,
scratch_pool);
- proplist = apr_hash_make(result_pool);
+ SVN_ERR(svn_stringbuf_from_file2(&content, filename, result_pool));
- SVN_ERR(svn_stream_open_readonly(&stream, filename, scratch_pool,
- scratch_pool));
- SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR,
- result_pool));
- SVN_ERR(svn_stream_close(stream));
+ as_string = svn_stringbuf__morph_into_string(content);
+ SVN_ERR_W(svn_fs_x__parse_properties(proplist, as_string, result_pool),
+ apr_psprintf(scratch_pool,
+ "malformed property list for node-revision '%s' in '%s'",
+ svn_fs_x__id_unparse(&noderev->noderev_id,
+ scratch_pool)->data,
+ filename));
}
else if (noderev->prop_rep)
{
svn_fs_x__data_t *ffd = fs->fsap_data;
svn_fs_x__representation_t *rep = noderev->prop_rep;
svn_fs_x__pair_cache_key_t key = { 0 };
+ svn_string_t *content;
+ svn_boolean_t is_cached;
key.revision = svn_fs_x__get_revnum(rep->id.change_set);
key.second = rep->id.number;
- if (SVN_IS_VALID_REVNUM(key.revision))
- {
- svn_boolean_t is_cached;
- SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
- ffd->properties_cache, &key, result_pool));
- if (is_cached)
- return SVN_NO_ERROR;
- }
+ SVN_ERR(svn_cache__get((void **) proplist, &is_cached,
+ ffd->properties_cache, &key, result_pool));
+ if (is_cached)
+ return SVN_NO_ERROR;
- proplist = apr_hash_make(result_pool);
- SVN_ERR(svn_fs_x__get_contents(&stream, fs, noderev->prop_rep, FALSE,
- scratch_pool));
- SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR,
- result_pool));
- SVN_ERR(svn_stream_close(stream));
+ SVN_ERR(svn_fs_x__get_contents(&stream, fs, rep, FALSE, scratch_pool));
+ SVN_ERR(svn_string_from_stream2(&content, stream, rep->expanded_size,
+ result_pool));
+
+ SVN_ERR_W(svn_fs_x__parse_properties(proplist, content, result_pool),
+ apr_psprintf(scratch_pool,
+ "malformed property list for node-revision '%s'",
+ svn_fs_x__id_unparse(&noderev->noderev_id,
+ scratch_pool)->data));
- if (SVN_IS_VALID_REVNUM(rep->id.change_set))
- SVN_ERR(svn_cache__set(ffd->properties_cache, &key, proplist,
- scratch_pool));
+ SVN_ERR(svn_cache__set(ffd->properties_cache, &key, *proplist,
+ scratch_pool));
}
else
{
/* return an empty prop list if the node doesn't have any props */
- proplist = apr_hash_make(result_pool);
+ *proplist = apr_hash_make(result_pool);
}
- *proplist_p = proplist;
-
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_x__create_changes_context(svn_fs_x__changes_context_t **context,
+ svn_fs_t *fs,
+ svn_revnum_t rev,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_fs_x__changes_context_t *result = apr_pcalloc(result_pool,
+ sizeof(*result));
+ result->fs = fs;
+ result->revision = rev;
+
+ SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool));
+ SVN_ERR(svn_fs_x__rev_file_init(&result->revision_file, fs, rev,
+ result_pool));
+ *context = result;
+ return SVN_NO_ERROR;
+}
svn_error_t *
svn_fs_x__get_changes(apr_array_header_t **changes,
- svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *result_pool)
+ svn_fs_x__changes_context_t *context,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_fs_x__revision_file_t *revision_file;
svn_boolean_t found;
- svn_fs_x__data_t *ffd = fs->fsap_data;
- apr_pool_t *scratch_pool = svn_pool_create(result_pool);
+ svn_fs_x__data_t *ffd = context->fs->fsap_data;
svn_fs_x__id_t id;
- id.change_set = svn_fs_x__change_set_by_rev(rev);
+ id.change_set = svn_fs_x__change_set_by_rev(context->revision);
id.number = SVN_FS_X__ITEM_INDEX_CHANGES;
- /* Provide revision file. */
-
- SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool));
- SVN_ERR(svn_fs_x__rev_file_init(&revision_file, fs, rev, scratch_pool));
-
/* try cache lookup first */
- if (svn_fs_x__is_packed_rev(fs, rev))
+ if (svn_fs_x__is_packed_rev(context->fs, context->revision))
{
apr_off_t offset;
- apr_uint32_t sub_item;
svn_fs_x__pair_cache_key_t key;
+ svn_fs_x__changes_get_list_baton_t baton;
+ baton.start = (int)context->next;
+ baton.eol = &context->eol;
- SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, revision_file,
+ SVN_ERR(svn_fs_x__item_offset(&offset, &baton.sub_item, context->fs,
+ context->revision_file,
&id, scratch_pool));
- key.revision = svn_fs_x__packed_base_rev(fs, rev);
+ key.revision = svn_fs_x__packed_base_rev(context->fs,
+ context->revision);
key.second = offset;
SVN_ERR(svn_cache__get_partial((void **)changes, &found,
ffd->changes_container_cache, &key,
svn_fs_x__changes_get_list_func,
- &sub_item, result_pool));
+ &baton, result_pool));
}
else
{
- SVN_ERR(svn_cache__get((void **) changes, &found, ffd->changes_cache,
- &rev, result_pool));
+ svn_fs_x__read_changes_block_baton_t baton;
+ baton.start = (int)context->next;
+ baton.eol = &context->eol;
+
+ SVN_ERR(svn_cache__get_partial((void **)changes, &found,
+ ffd->changes_cache, &context->revision,
+ svn_fs_x__read_changes_block,
+ &baton, result_pool));
}
if (!found)
{
/* 'block-read' will also provide us with the desired data */
- SVN_ERR(block_read((void **)changes, fs, &id, revision_file,
+ SVN_ERR(block_read((void **)changes, context->fs, &id,
+ context->revision_file, context,
result_pool, scratch_pool));
-
- SVN_ERR(svn_fs_x__close_revision_file(revision_file));
}
- SVN_ERR(dgb__log_access(fs, &id, *changes, SVN_FS_X__ITEM_TYPE_CHANGES,
- scratch_pool));
+ context->next += (*changes)->nelts;
+
+ SVN_ERR(dgb__log_access(context->fs, &id, *changes,
+ SVN_FS_X__ITEM_TYPE_CHANGES, scratch_pool));
- svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
/* Fetch the representation data (header, txdelta / plain windows)
- * addressed by ENTRY->ITEM in FS and cache it if caches are enabled.
- * Read the data from the already open FILE and the wrapping
- * STREAM object. If MAX_OFFSET is not -1, don't read windows that start
+ * addressed by ENTRY->ITEM in FS and cache it under KEY. Read the data
+ * from REV_FILE. If MAX_OFFSET is not -1, don't read windows that start
* at or beyond that offset. Use SCRATCH_POOL for temporary allocations.
*/
static svn_error_t *
@@ -2814,27 +2919,28 @@ block_read_contents(svn_fs_t *fs,
/* For the given REV_FILE in FS, in *STREAM return a stream covering the
* item specified by ENTRY. Also, verify the item's content by low-level
- * checksum. Allocate the result in POOL.
+ * checksum. Allocate the result in RESULT_POOL.
*/
static svn_error_t *
read_item(svn_stream_t **stream,
svn_fs_t *fs,
svn_fs_x__revision_file_t *rev_file,
svn_fs_x__p2l_entry_t* entry,
- apr_pool_t *pool)
+ apr_pool_t *result_pool)
{
apr_uint32_t digest;
svn_checksum_t *expected, *actual;
apr_uint32_t plain_digest;
+ svn_stringbuf_t *text;
/* Read item into string buffer. */
- svn_stringbuf_t *text = svn_stringbuf_create_ensure(entry->size, pool);
+ text = svn_stringbuf_create_ensure(entry->size, result_pool);
text->len = entry->size;
text->data[text->len] = 0;
SVN_ERR(svn_fs_x__rev_file_read(rev_file, text->data, text->len));
/* Return (construct, calculate) stream and checksum. */
- *stream = svn_stream_from_stringbuf(text, pool);
+ *stream = svn_stream_from_stringbuf(text, result_pool);
digest = svn__fnv1a_32x4(text->data, text->len);
/* Checksums will match most of the time. */
@@ -2845,30 +2951,31 @@ read_item(svn_stream_t **stream,
* nice error messages. */
plain_digest = htonl(entry->fnv1_checksum);
expected = svn_checksum__from_digest_fnv1a_32x4(
- (const unsigned char *)&plain_digest, pool);
+ (const unsigned char *)&plain_digest, result_pool);
plain_digest = htonl(digest);
actual = svn_checksum__from_digest_fnv1a_32x4(
- (const unsigned char *)&plain_digest, pool);
+ (const unsigned char *)&plain_digest, result_pool);
/* Construct the full error message with all the info we have. */
- return svn_checksum_mismatch_err(expected, actual, pool,
+ return svn_checksum_mismatch_err(expected, actual, result_pool,
_("Low-level checksum mismatch while reading\n"
"%s bytes of meta data at offset %s "),
- apr_psprintf(pool, "%" APR_OFF_T_FMT, entry->size),
- apr_psprintf(pool, "%" APR_OFF_T_FMT, entry->offset));
+ apr_psprintf(result_pool, "%" APR_OFF_T_FMT, entry->size),
+ apr_psprintf(result_pool, "%" APR_OFF_T_FMT, entry->offset));
}
-/* Read all txdelta / plain windows following REP_HEADER in FS as described
- * by ENTRY. Read the data from the already open FILE and the wrapping
- * STREAM object. If MAX_OFFSET is not -1, don't read windows that start
- * at or beyond that offset. Use SCRATCH_POOL for temporary allocations.
- * If caching is not enabled, this is a no-op.
+/* If not already cached or if MUST_READ is set, read the changed paths
+ * list addressed by ENTRY in FS and retúrn it in *CHANGES. Cache the
+ * result if caching is enabled. Read the data from REV_FILE. Trim the
+ * data in *CHANGES to the range given by CONTEXT. Allocate *CHANGES in
+ * RESUSLT_POOL and allocate temporaries in SCRATCH_POOL.
*/
static svn_error_t *
block_read_changes(apr_array_header_t **changes,
svn_fs_t *fs,
svn_fs_x__revision_file_t *rev_file,
svn_fs_x__p2l_entry_t* entry,
+ svn_fs_x__changes_context_t *context,
svn_boolean_t must_read,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -2909,15 +3016,43 @@ block_read_changes(apr_array_header_t **
SVN_ERR(svn_cache__set(ffd->changes_cache, &revision, *changes,
scratch_pool));
+ /* Trim the result:
+ * Remove the entries that already been reported. */
+
+ /* TODO: This is transitional code.
+ * The final implementation will read and cache only sections of
+ * the changes list. */
+ if (must_read)
+ {
+ int i;
+ for (i = 0; i + context->next < (*changes)->nelts; ++i)
+ {
+ APR_ARRAY_IDX(*changes, i, svn_fs_x__change_t *)
+ = APR_ARRAY_IDX(*changes, i + context->next,
+ svn_fs_x__change_t *);
+ }
+ (*changes)->nelts = i;
+
+ context->eol = TRUE;
+ }
+
return SVN_NO_ERROR;
}
+/* If not already cached or if MUST_READ is set, read the changed paths
+ * list container addressed by ENTRY in FS. Return the changes list
+ * identified by SUB_ITEM in *CHANGES, using CONTEXT to select a sub-range
+ * within that list. Read the data from REV_FILE and cache the result.
+ *
+ * Allocate *CHANGES in RESUSLT_POOL and everything else in SCRATCH_POOL.
+ */
static svn_error_t *
block_read_changes_container(apr_array_header_t **changes,
svn_fs_t *fs,
svn_fs_x__revision_file_t *rev_file,
svn_fs_x__p2l_entry_t* entry,
apr_uint32_t sub_item,
+ svn_fs_x__changes_context_t *context,
svn_boolean_t must_read,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -2952,13 +3087,19 @@ block_read_changes_container(apr_array_h
if (must_read)
SVN_ERR(svn_fs_x__changes_get_list(changes, container, sub_item,
- result_pool));
+ context, result_pool));
SVN_ERR(svn_cache__set(ffd->changes_container_cache, &key, container,
scratch_pool));
return SVN_NO_ERROR;
}
+/* If not already cached or if MUST_READ is set, read the node revision
+ * addressed by ENTRY in FS and return it in *NODEREV_P. Cache the
+ * result under KEY if caching is enabled. Read the data from REV_FILE.
+ * Allocate *NODEREV_P in RESUSLT_POOL and allocate temporaries in
+ * SCRATCH_POOL.
+ */
static svn_error_t *
block_read_noderev(svn_fs_x__noderev_t **noderev_p,
svn_fs_t *fs,
@@ -2997,6 +3138,12 @@ block_read_noderev(svn_fs_x__noderev_t *
return SVN_NO_ERROR;
}
+/* If not already cached or if MUST_READ is set, read the node revision
+ * container addressed by ENTRY in FS. Return the item identified by
+ * SUB_ITEM in *NODEREV_P. Read the data from REV_FILE and cache it.
+ * Allocate *NODEREV_P in RESUSLT_POOL and allocate temporaries in
+ * SCRATCH_POOL.
+ */
static svn_error_t *
block_read_noderevs_container(svn_fs_x__noderev_t **noderev_p,
svn_fs_t *fs,
@@ -3043,6 +3190,12 @@ block_read_noderevs_container(svn_fs_x__
return SVN_NO_ERROR;
}
+/* If not already cached or if MUST_READ is set, read the representation
+ * container addressed by ENTRY in FS. Return an extractor object for the
+ * item identified by SUB_ITEM in *EXTRACTOR. Read the data from REV_FILE
+ * and cache it. Allocate *EXTRACTOR in RESUSLT_POOL and all temporaries
+ * in SCRATCH_POOL.
+ */
static svn_error_t *
block_read_reps_container(svn_fs_x__rep_extractor_t **extractor,
svn_fs_t *fs,
@@ -3090,11 +3243,24 @@ block_read_reps_container(svn_fs_x__rep_
return SVN_NO_ERROR;
}
+/* Read the whole (e.g. 64kB) block containing the item identified by ID in
+ * FS and put all data into cache. If necessary and depending on heuristics,
+ * neighboring blocks may also get read. The data is being read from
+ * already open REVISION_FILE, which must be the correct rev / pack file
+ * w.r.t. ID->CHANGE_SET.
+ *
+ * For noderevs and changed path lists, the item fetched can be allocated
+ * RESULT_POOL and returned in *RESULT. Otherwise, RESULT must be NULL.
+ * The BATON is passed along to the extractor sub-functions and will be
+ * used only when constructing the *RESULT. SCRATCH_POOL will be used for
+ * all temporary allocations.
+ */
static svn_error_t *
block_read(void **result,
svn_fs_t *fs,
const svn_fs_x__id_t *id,
svn_fs_x__revision_file_t *revision_file,
+ void *baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -3185,7 +3351,7 @@ block_read(void **result,
case SVN_FS_X__ITEM_TYPE_CHANGES:
SVN_ERR(block_read_changes((apr_array_header_t **)&item,
fs, revision_file,
- entry, is_result,
+ entry, baton, is_result,
pool, iterpool));
break;
@@ -3194,7 +3360,8 @@ block_read(void **result,
((apr_array_header_t **)&item,
fs, revision_file,
entry, wanted_sub_item,
- is_result, pool, iterpool));
+ baton, is_result,
+ pool, iterpool));
break;
case SVN_FS_X__ITEM_TYPE_NODEREVS_CONT:
@@ -3223,7 +3390,7 @@ block_read(void **result,
/* if we crossed a block boundary, read the remainder of
* the last block as well */
offset = entry->offset + entry->size;
- if (offset > block_start + ffd->block_size)
+ if (offset - block_start > ffd->block_size)
++run_count;
svn_pool_clear(iterpool);
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/cached_data.h?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/cached_data.h (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/cached_data.h Fri Apr 29 18:38:53 2016
@@ -168,13 +168,24 @@ svn_fs_x__get_proplist(apr_hash_t **prop
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-/* Fetch the list of change in revision REV in FS and return it in *CHANGES.
- * Allocate the result in POOL.
+/* Create a changes retrieval context object in *RESULT_POOL and return it
+ * in *CONTEXT. It will allow svn_fs_x__get_changes to fetch consecutive
+ * blocks (one per invocation) from REV's changed paths list in FS.
+ * Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *
+svn_fs_x__create_changes_context(svn_fs_x__changes_context_t **context,
+ svn_fs_t *fs,
+ svn_revnum_t rev,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/* Fetch the block of changes from the CONTEXT and return it in *CHANGES.
+ * Allocate the result in RESULT_POOL and use SCRATCH_POOL for temporaries.
*/
svn_error_t *
svn_fs_x__get_changes(apr_array_header_t **changes,
- svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *pool);
+ svn_fs_x__changes_context_t *context,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
#endif
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/caching.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/caching.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/caching.c Fri Apr 29 18:38:53 2016
@@ -69,9 +69,9 @@ normalize_key_part(const char *original,
return normalized->data;
}
-/* *CACHE_TXDELTAS, *CACHE_FULLTEXTS and *CACHE_REVPROPS flags will be set
- according to FS->CONFIG. *CACHE_NAMESPACE receives the cache prefix
- to use.
+/* *CACHE_TXDELTAS, *CACHE_FULLTEXTS, *CACHE_REVPROPS and *CACHE_NODEPROPS
+ flags will be set according to FS->CONFIG. *CACHE_NAMESPACE receives
+ the cache prefix to use.
Allocate CACHE_NAMESPACE in RESULT_POOL. */
static svn_error_t *
@@ -79,6 +79,7 @@ read_config(const char **cache_namespace
svn_boolean_t *cache_txdeltas,
svn_boolean_t *cache_fulltexts,
svn_boolean_t *cache_revprops,
+ svn_boolean_t *cache_nodeprops,
svn_fs_t *fs,
apr_pool_t *result_pool)
{
@@ -137,6 +138,15 @@ read_config(const char **cache_namespace
else
*cache_revprops = TRUE;
+ /* by default, cache nodeprops: this will match pre-1.10
+ * behavior where node properties caching was controlled
+ * by SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS configuration option.
+ */
+ *cache_nodeprops
+ = svn_hash__get_bool(fs->config,
+ SVN_FS_CONFIG_FSFS_CACHE_NODEPROPS,
+ TRUE);
+
return SVN_NO_ERROR;
}
@@ -370,6 +380,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
svn_fs_x__data_t *ffd = fs->fsap_data;
const char *prefix = apr_pstrcat(scratch_pool,
"fsx:", fs->uuid,
+ "--", ffd->instance_id,
"/", normalize_key_part(fs->path,
scratch_pool),
":",
@@ -379,6 +390,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
svn_boolean_t cache_txdeltas;
svn_boolean_t cache_fulltexts;
svn_boolean_t cache_revprops;
+ svn_boolean_t cache_nodeprops;
const char *cache_namespace;
svn_boolean_t has_namespace;
@@ -387,6 +399,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
&cache_txdeltas,
&cache_fulltexts,
&cache_revprops,
+ &cache_nodeprops,
fs,
scratch_pool));
@@ -429,7 +442,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
svn_fs_x__deserialize_dir_entries,
sizeof(svn_fs_x__id_t),
apr_pstrcat(scratch_pool, prefix, "DIR", SVN_VA_NULL),
- SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
has_namespace,
fs,
no_handler, FALSE,
@@ -511,7 +524,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
has_namespace,
fs,
- no_handler, !cache_fulltexts,
+ no_handler, !cache_nodeprops,
fs->pool, scratch_pool));
/* if enabled, cache revprops */
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/changes.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/changes.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/changes.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/changes.c Fri Apr 29 18:38:53 2016
@@ -21,6 +21,7 @@
*/
#include "svn_private_config.h"
+#include "svn_sorts.h"
#include "private/svn_packed_data.h"
@@ -37,8 +38,8 @@
/* the change contains a property modification */
#define CHANGE_PROP_MOD 0x00002
-/* the last part (rev_id) of node revision ID is a transaction ID */
-#define CHANGE_TXN_NODE 0x00004
+/* the change contains a mergeinfo modification */
+#define CHANGE_MERGEINFO_MOD 0x00004
/* (flags & CHANGE_NODE_MASK) >> CHANGE_NODE_SHIFT extracts the node type */
#define CHANGE_NODE_SHIFT 0x00003
@@ -52,16 +53,13 @@
/* (flags & CHANGE_KIND_MASK) >> CHANGE_KIND_SHIFT extracts the change type */
#define CHANGE_KIND_SHIFT 0x00005
-#define CHANGE_KIND_MASK 0x000E0
+#define CHANGE_KIND_MASK 0x00060
/* node types according to svn_fs_path_change_kind_t */
#define CHANGE_KIND_MODIFY 0x00000
#define CHANGE_KIND_ADD 0x00020
#define CHANGE_KIND_DELETE 0x00040
#define CHANGE_KIND_REPLACE 0x00060
-#define CHANGE_KIND_RESET 0x00080
-#define CHANGE_KIND_MOVE 0x000A0
-#define CHANGE_KIND_MOVEREPLACE 0x000C0
/* Our internal representation of a change */
typedef struct binary_change_t
@@ -77,10 +75,6 @@ typedef struct binary_change_t
svn_revnum_t copyfrom_rev;
apr_size_t copyfrom_path;
- /* Relevant parts of the node revision ID of the change.
- * Empty, if REV_ID is not "used". */
- svn_fs_x__id_t noderev_id;
-
} binary_change_t;
/* The actual container object. Change lists are concatenated into CHANGES
@@ -138,20 +132,16 @@ append_change(svn_fs_x__changes_t *chang
svn_fs_x__change_t *change)
{
binary_change_t binary_change = { 0 };
- svn_boolean_t is_txn_id;
/* CHANGE must be sufficiently complete */
SVN_ERR_ASSERT(change);
SVN_ERR_ASSERT(change->path.data);
- /* Relevant parts of the revision ID of the change. */
- binary_change.noderev_id = change->noderev_id;
-
/* define the kind of change and what specific information is present */
- is_txn_id = svn_fs_x__is_txn(binary_change.noderev_id.change_set);
binary_change.flags = (change->text_mod ? CHANGE_TEXT_MOD : 0)
| (change->prop_mod ? CHANGE_PROP_MOD : 0)
- | (is_txn_id ? CHANGE_TXN_NODE : 0)
+ | (change->mergeinfo_mod == svn_tristate_true
+ ? CHANGE_MERGEINFO_MOD : 0)
| ((int)change->change_kind << CHANGE_KIND_SHIFT)
| ((int)change->node_kind << CHANGE_NODE_SHIFT);
@@ -222,12 +212,19 @@ svn_error_t *
svn_fs_x__changes_get_list(apr_array_header_t **list,
const svn_fs_x__changes_t *changes,
apr_size_t idx,
+ svn_fs_x__changes_context_t *context,
apr_pool_t *result_pool)
{
+ int list_first;
+ int list_last;
int first;
int last;
int i;
+ /* Return up to this many entries. Anything > 0 will do.
+ * At 100..300 bytes per entry, this limits the allocation to ~30kB. */
+ enum { BLOCK_SIZE = 100 };
+
/* CHANGES must be in 'finalized' mode */
SVN_ERR_ASSERT(changes->builder == NULL);
SVN_ERR_ASSERT(changes->paths);
@@ -242,8 +239,16 @@ svn_fs_x__changes_get_list(apr_array_hea
idx, changes->offsets->nelts - 1);
/* range of changes to return */
- first = APR_ARRAY_IDX(changes->offsets, (int)idx, int);
- last = APR_ARRAY_IDX(changes->offsets, (int)idx + 1, int);
+ list_first = APR_ARRAY_IDX(changes->offsets, (int)idx, int);
+ list_last = APR_ARRAY_IDX(changes->offsets, (int)idx + 1, int);
+
+ /* Restrict it to the sub-range requested by the caller.
+ * Clip the range to never exceed the list's content. */
+ first = MIN(context->next + list_first, list_last);
+ last = MIN(first + BLOCK_SIZE, list_last);
+
+ /* Indicate to the caller whether the end of the list has been reached. */
+ context->eol = last == list_last;
/* construct result */
*list = apr_array_make(result_pool, last - first,
@@ -260,13 +265,13 @@ svn_fs_x__changes_get_list(apr_array_hea
&change->path.len,
result_pool);
- if (binary_change->noderev_id.change_set != SVN_FS_X__INVALID_CHANGE_SET)
- change->noderev_id = binary_change->noderev_id;
-
change->change_kind = (svn_fs_path_change_kind_t)
((binary_change->flags & CHANGE_KIND_MASK) >> CHANGE_KIND_SHIFT);
change->text_mod = (binary_change->flags & CHANGE_TEXT_MOD) != 0;
change->prop_mod = (binary_change->flags & CHANGE_PROP_MOD) != 0;
+ change->mergeinfo_mod = (binary_change->flags & CHANGE_MERGEINFO_MOD)
+ ? svn_tristate_true
+ : svn_tristate_false;
change->node_kind = (svn_node_kind_t)
((binary_change->flags & CHANGE_NODE_MASK) >> CHANGE_NODE_SHIFT);
@@ -312,8 +317,6 @@ svn_fs_x__write_changes_container(svn_st
svn_packed__create_int_substream(changes_stream, TRUE, FALSE);
svn_packed__create_int_substream(changes_stream, TRUE, TRUE);
svn_packed__create_int_substream(changes_stream, TRUE, FALSE);
- svn_packed__create_int_substream(changes_stream, TRUE, TRUE);
- svn_packed__create_int_substream(changes_stream, TRUE, FALSE);
/* serialize offsets array */
for (i = 0; i < changes->offsets->nelts; ++i)
@@ -331,9 +334,6 @@ svn_fs_x__write_changes_container(svn_st
svn_packed__add_int(changes_stream, change->copyfrom_rev);
svn_packed__add_uint(changes_stream, change->copyfrom_path);
-
- svn_packed__add_int(changes_stream, change->noderev_id.change_set);
- svn_packed__add_uint(changes_stream, change->noderev_id.number);
}
/* write to disk */
@@ -388,9 +388,6 @@ svn_fs_x__read_changes_container(svn_fs_
change.copyfrom_rev = (svn_revnum_t)svn_packed__get_int(changes_stream);
change.copyfrom_path = (apr_size_t)svn_packed__get_uint(changes_stream);
- change.noderev_id.change_set = svn_packed__get_int(changes_stream);
- change.noderev_id.number = svn_packed__get_uint(changes_stream);
-
APR_ARRAY_PUSH(changes->changes, binary_change_t) = change;
}
@@ -464,8 +461,10 @@ svn_fs_x__changes_get_list_func(void **o
int last;
int i;
apr_array_header_t *list;
+ enum { BLOCK_SIZE = 100 };
- apr_uint32_t idx = *(apr_uint32_t *)baton;
+ svn_fs_x__changes_get_list_baton_t *b = baton;
+ apr_uint32_t idx = b->sub_item;
const svn_fs_x__changes_t *container = data;
/* resolve all the sub-container pointers we need */
@@ -496,6 +495,12 @@ svn_fs_x__changes_get_list_func(void **o
first = offsets[idx];
last = offsets[idx+1];
+ /* Restrict range to the block requested by the BATON.
+ * Tell the caller whether we reached the end of the list. */
+ first = MIN(first + b->start, last);
+ last = MIN(first + BLOCK_SIZE, last);
+ *b->eol = last == offsets[idx+1];
+
/* construct result */
list = apr_array_make(pool, last - first, sizeof(svn_fs_x__change_t*));
@@ -509,8 +514,6 @@ svn_fs_x__changes_get_list_func(void **o
= svn_fs_x__string_table_get_func(paths, binary_change->path,
&change->path.len, pool);
- change->noderev_id = binary_change->noderev_id;
-
change->change_kind = (svn_fs_path_change_kind_t)
((binary_change->flags & CHANGE_KIND_MASK) >> CHANGE_KIND_SHIFT);
change->text_mod = (binary_change->flags & CHANGE_TEXT_MOD) != 0;
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/changes.h
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/changes.h?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/changes.h (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/changes.h Fri Apr 29 18:38:53 2016
@@ -71,13 +71,15 @@ svn_fs_x__changes_estimate_size(const sv
/* Read changes containers. */
-/* From CHANGES, extract the change list with the given IDX. Allocate
- * the result in POOL and return it in *LIST.
+/* From CHANGES, access the change list with the given IDX and extract the
+ * next entries according to CONTEXT. Allocate the result in RESULT_POOL
+ * and return it in *LIST.
*/
svn_error_t *
svn_fs_x__changes_get_list(apr_array_header_t **list,
const svn_fs_x__changes_t *changes,
apr_size_t idx,
+ svn_fs_x__changes_context_t *context,
apr_pool_t *result_pool);
/* I/O interface. */
@@ -116,11 +118,25 @@ svn_fs_x__deserialize_changes_container(
apr_size_t data_len,
apr_pool_t *result_pool);
+/* Baton type to be used with svn_fs_x__changes_get_list_func. */
+typedef struct svn_fs_x__changes_get_list_baton_t
+{
+ /* Sub-item to query */
+ apr_uint32_t sub_item;
+
+ /* Deliver data starting from this index within the changes list. */
+ int start;
+
+ /* To be set by svn_fs_x__changes_get_list_func:
+ Did we deliver the last change in that list? */
+ svn_boolean_t *eol;
+} svn_fs_x__changes_get_list_baton_t;
+
/* Implements svn_cache__partial_getter_func_t for svn_fs_x__changes_t,
* setting *OUT to the change list (apr_array_header_t *) selected by
- * the apr_uint32_t index passed in as *BATON. This function is similar
- * to svn_fs_x__changes_get_list but operates on the cache serialized
- * representation of the container.
+ * the svn_fs_x__changes_get_list_baton_t passed in as *BATON. This
+ * function is similar to svn_fs_x__changes_get_list but operates on
+ * the cache serialized representation of the container.
*/
svn_error_t *
svn_fs_x__changes_get_list_func(void **out,
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/fs.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/fs.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/fs.c Fri Apr 29 18:38:53 2016
@@ -137,6 +137,18 @@ x_serialized_init(svn_fs_t *fs,
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_x__initialize_shared_data(svn_fs_t *fs,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *scratch_pool,
+ apr_pool_t *common_pool)
+{
+ SVN_MUTEX__WITH_LOCK(common_pool_lock,
+ x_serialized_init(fs, common_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
/* This function is provided for Subversion 1.0.x compatibility. It
@@ -218,20 +230,11 @@ x_info(const void **fsx_info,
return SVN_NO_ERROR;
}
-/* Wrapper around svn_fs_x__revision_prop() adapting between function
- signatures. */
static svn_error_t *
-x_revision_prop(svn_string_t **value_p,
- svn_fs_t *fs,
- svn_revnum_t rev,
- const char *propname,
- apr_pool_t *pool)
+x_refresh_revprops(svn_fs_t *fs,
+ apr_pool_t *scratch_pool)
{
- apr_pool_t *scratch_pool = svn_pool_create(pool);
- SVN_ERR(svn_fs_x__revision_prop(value_p, fs, rev, propname, pool,
- scratch_pool));
- svn_pool_destroy(scratch_pool);
-
+ svn_fs_x__invalidate_revprop_generation(fs);
return SVN_NO_ERROR;
}
@@ -241,14 +244,14 @@ static svn_error_t *
x_revision_proplist(apr_hash_t **proplist_p,
svn_fs_t *fs,
svn_revnum_t rev,
- apr_pool_t *pool)
+ svn_boolean_t refresh,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_pool_t *scratch_pool = svn_pool_create(pool);
-
/* No need to bypass the caches for r/o access to revprops. */
SVN_ERR(svn_fs_x__get_revision_proplist(proplist_p, fs, rev, FALSE,
- pool, scratch_pool));
- svn_pool_destroy(scratch_pool);
+ refresh, result_pool,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -262,7 +265,8 @@ x_set_uuid(svn_fs_t *fs,
{
/* Whenever we set a new UUID, imply that FS will also be a different
* instance (on formats that support this). */
- return svn_error_trace(svn_fs_x__set_uuid(fs, uuid, NULL, scratch_pool));
+ return svn_error_trace(svn_fs_x__set_uuid(fs, uuid, NULL, TRUE,
+ scratch_pool));
}
/* Wrapper around svn_fs_x__begin_txn() providing the scratch pool. */
@@ -285,7 +289,8 @@ x_begin_txn(svn_fs_txn_t **txn_p,
/* The vtable associated with a specific open filesystem. */
static fs_vtable_t fs_vtable = {
svn_fs_x__youngest_rev,
- x_revision_prop,
+ x_refresh_revprops,
+ svn_fs_x__revision_prop,
x_revision_proplist,
svn_fs_x__change_rev_prop,
x_set_uuid,
@@ -316,6 +321,8 @@ static svn_error_t *
initialize_fs_struct(svn_fs_t *fs)
{
svn_fs_x__data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
+ ffd->revprop_generation = -1;
+
fs->vtable = &fs_vtable;
fs->fsap_data = ffd;
return SVN_NO_ERROR;
@@ -536,24 +543,17 @@ x_hotcopy(svn_fs_t *src_fs,
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
- /* Test target repo when in INCREMENTAL mode, initialize it when not.
- * For this, we need our FS internal data structures to be temporarily
- * available. */
+ SVN_ERR(svn_fs__check_fs(dst_fs, FALSE));
SVN_ERR(initialize_fs_struct(dst_fs));
- SVN_ERR(svn_fs_x__hotcopy_prepare_target(src_fs, dst_fs, dst_path,
- incremental, scratch_pool));
- uninitialize_fs_struct(dst_fs);
- /* Now, the destination repo should open just fine. */
- SVN_ERR(x_open(dst_fs, dst_path, common_pool_lock, scratch_pool,
- common_pool));
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
-
- /* Now, we may copy data as needed ... */
- return svn_fs_x__hotcopy(src_fs, dst_fs, incremental,
- notify_func, notify_baton,
- cancel_func, cancel_baton, scratch_pool);
+ /* In INCREMENTAL mode, svn_fs_x__hotcopy() will open DST_FS.
+ Otherwise, it's not an FS yet --- possibly just an empty dir --- so
+ can't be opened.
+ */
+ return svn_fs_x__hotcopy(src_fs, dst_fs, src_path, dst_path,
+ incremental, notify_func, notify_baton,
+ cancel_func, cancel_baton, common_pool_lock,
+ scratch_pool, common_pool);
}
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/fs.h?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/fs.h (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/fs.h Fri Apr 29 18:38:53 2016
@@ -37,7 +37,7 @@
#include "private/svn_sqlite.h"
#include "private/svn_mutex.h"
-#include "id.h"
+#include "rev_file.h"
#ifdef __cplusplus
extern "C" {
@@ -60,7 +60,6 @@ extern "C" {
#define PATH_TXNS_DIR "transactions" /* Directory of transactions */
#define PATH_TXN_PROTOS_DIR "txn-protorevs" /* Directory of proto-revs */
#define PATH_TXN_CURRENT "txn-current" /* File with next txn key */
-#define PATH_TXN_NEXT "txn-next" /* Will become txn-current */
#define PATH_TXN_CURRENT_LOCK "txn-current-lock" /* Lock for txn-current */
#define PATH_LOCKS_DIR "locks" /* Directory of locks */
#define PATH_MIN_UNPACKED_REV "min-unpacked-rev" /* Oldest revision which
@@ -295,9 +294,8 @@ typedef struct svn_fs_x__data_t
rep key (revision/offset) to svn_stringbuf_t. */
svn_cache__t *fulltext_cache;
- /* Access object to the revprop "generation". Will be NULL until
- the first access. May be also get closed and set to NULL again. */
- apr_file_t *revprop_generation_file;
+ /* Revprop generation number. Will be -1 if it has to reread from disk. */
+ apr_int64_t revprop_generation;
/* Revision property cache. Maps from (rev,generation) to apr_hash_t. */
svn_cache__t *revprop_cache;
@@ -404,19 +402,12 @@ typedef struct svn_fs_x__data_t
svn_error_t *(*svn_fs_open_)(svn_fs_t **, const char *, apr_hash_t *,
apr_pool_t *, apr_pool_t *);
- /* If not 0, this is a pre-allocated transaction ID that can just be
- used for a new txn without needing to consult 'txn-current'. */
- apr_uint64_t next_txn_id;
} svn_fs_x__data_t;
/*** Filesystem Transaction ***/
typedef struct svn_fs_x__transaction_t
{
- /* property list (const char * name, svn_string_t * value).
- may be NULL if there are no properties. */
- apr_hash_t *proplist;
-
/* revision upon which this txn is base. (unfinished only) */
svn_revnum_t base_rev;
@@ -530,28 +521,38 @@ typedef struct svn_fs_x__dirent_t
/*** Change ***/
-typedef struct svn_fs_x__change_t
+typedef svn_fs_path_change3_t svn_fs_x__change_t;
+
+/*** Context for reading changed paths lists iteratively. */
+typedef struct svn_fs_x__changes_context_t
{
- /* Path of the change. */
- svn_string_t path;
+ /* Repository to fetch from. */
+ svn_fs_t *fs;
- /* node revision id of changed path */
- svn_fs_x__id_t noderev_id;
+ /* Revision that we read from. */
+ svn_revnum_t revision;
- /* See svn_fs_path_change2_t for a description for the remaining elements.
- */
- svn_fs_path_change_kind_t change_kind;
-
- svn_boolean_t text_mod;
- svn_boolean_t prop_mod;
- svn_node_kind_t node_kind;
+ /* Revision file object to use when needed. */
+ svn_fs_x__revision_file_t *revision_file;
- svn_boolean_t copyfrom_known;
- svn_revnum_t copyfrom_rev;
- const char *copyfrom_path;
+ /* Index of the next change to fetch. */
+ apr_size_t next;
+
+ /* Has the end of the list been reached? */
+ svn_boolean_t eol;
+
+} svn_fs_x__changes_context_t;
+
+/*** Directory (only used at the cache interface) ***/
+typedef struct svn_fs_x__dir_data_t
+{
+ /* Contents, i.e. all directory entries, sorted by name. */
+ apr_array_header_t *entries;
- svn_tristate_t mergeinfo_mod;
-} svn_fs_x__change_t;
+ /* SVN_INVALID_FILESIZE for committed data, otherwise the length of the
+ * in-txn on-disk representation of that directory. */
+ svn_filesize_t txn_filesize;
+} svn_fs_x__dir_data_t;
#ifdef __cplusplus
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/fs_x.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/fs_x.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/fs_x.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/fs_x.c Fri Apr 29 18:38:53 2016
@@ -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"
@@ -602,8 +603,9 @@ 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));
+ ffd->youngest_rev_cache = 0;
+
+ return SVN_NO_ERROR;
}
/* Baton type bridging svn_fs_x__upgrade and upgrade_body carrying
@@ -855,10 +857,7 @@ 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;
@@ -876,63 +875,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. */
+ rewrite the index section of r0. */
SVN_ERR(svn_fs_x__rev_file_open_writable(&rev_file, fs, 0,
- subpool, subpool));
+ 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));
+ 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, subpool));
+ 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 *
@@ -966,14 +974,13 @@ 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));
@@ -996,6 +1003,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;
@@ -1052,6 +1062,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;
@@ -1070,11 +1081,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_atomic2(uuid_path, contents->data, contents->len,
- /* perms */
- svn_fs_x__path_current(fs, scratch_pool),
- TRUE, 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),
+ TRUE, scratch_pool));
+ }
fs->uuid = apr_pstrdup(fs->pool, uuid);
ffd->instance_id = apr_pstrdup(fs->pool, instance_id);
@@ -1112,13 +1135,14 @@ svn_fs_x__revision_prop(svn_string_t **v
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);
@@ -1151,7 +1175,7 @@ change_rev_prop_body(void *baton,
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)
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/fs_x.h
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/fs_x.h?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/fs_x.h (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/fs_x.h Fri Apr 29 18:38:53 2016
@@ -41,6 +41,16 @@ svn_fs_x__open(svn_fs_t *fs,
const char *path,
apr_pool_t *scratch_pool);
+/* Initialize parts of the FS data that are being shared across multiple
+ filesystem objects. Use COMMON_POOL for process-wide and SCRATCH_POOL
+ for temporary allocations. Use COMMON_POOL_LOCK to ensure that the
+ initialization is serialized. */
+svn_error_t *
+svn_fs_x__initialize_shared_data(svn_fs_t *fs,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *scratch_pool,
+ apr_pool_t *common_pool);
+
/* Upgrade the fsx filesystem FS. Indicate progress via the optional
* NOTIFY_FUNC callback using NOTIFY_BATON. The optional CANCEL_FUNC
* will periodically be called with CANCEL_BATON to allow for preemption.
@@ -138,11 +148,16 @@ svn_fs_x__create(svn_fs_t *fs,
/* Set the uuid of repository FS to UUID and the instance ID to INSTANCE_ID.
If any of them is NULL, use a newly generated UUID / ID instead.
+
+ If OVERWRITE is not set, the uuid file must not exist yet implying this
+ is a fresh repository.
+
Perform temporary allocations in SCRATCH_POOL. */
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);
/* Read the format number and maximum number of files per directory
@@ -160,12 +175,15 @@ svn_fs_x__write_format(svn_fs_t *fs,
/* Find the value of the property named PROPNAME in transaction REV.
Return the contents in *VALUE_P, allocated from RESULT_POOL.
+ If REFRESH is not set, continue using the potentially outdated
+ revprop generation value in FS->FSAP_DATA.
Use SCRATCH_POOL for temporary allocations. */
svn_error_t *
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);
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/hotcopy.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/hotcopy.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/hotcopy.c Fri Apr 29 18:38:53 2016
@@ -326,6 +326,19 @@ hotcopy_copy_packed_shard(svn_boolean_t
return SVN_NO_ERROR;
}
+/* Remove file PATH, if it exists - even if it is read-only.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+hotcopy_remove_file(const char *path,
+ apr_pool_t *scratch_pool)
+{
+ /* Make the rev file writable and remove it. */
+ SVN_ERR(svn_io_set_file_read_write(path, TRUE, scratch_pool));
+ SVN_ERR(svn_io_remove_file2(path, TRUE, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
/* Verify that DST_FS is a suitable destination for an incremental
* hotcopy from SRC_FS. */
static svn_error_t *
@@ -651,6 +664,10 @@ hotcopy_body(void *baton,
/* Copy the rep cache and then remove entries for revisions
* that did not make it into the destination. */
SVN_ERR(svn_sqlite__hotcopy(src_subdir, dst_subdir, scratch_pool));
+
+ /* The source might have r/o flags set on it - which would be
+ carried over to the copy. */
+ SVN_ERR(svn_io_set_file_read_write(dst_subdir, FALSE, scratch_pool));
SVN_ERR(svn_fs_x__del_rep_reference(dst_fs, src_youngest,
scratch_pool));
}
@@ -665,64 +682,33 @@ hotcopy_body(void *baton,
* used for the named atomics implementation. */
SVN_ERR(svn_fs_x__reset_revprop_generation_file(dst_fs, scratch_pool));
- return SVN_NO_ERROR;
-}
-
-/* Wrapper around hotcopy_body taking out all necessary source repository
- * locks.
- */
-static svn_error_t *
-hotcopy_locking_src_body(void *baton,
- apr_pool_t *scratch_pool)
-{
- hotcopy_body_baton_t *hbb = baton;
+ /* Hotcopied FS is complete. Stamp it with a format file. */
+ SVN_ERR(svn_fs_x__write_format(dst_fs, TRUE, scratch_pool));
- return svn_error_trace(svn_fs_x__with_pack_lock(hbb->src_fs, hotcopy_body,
- baton, scratch_pool));
+ return SVN_NO_ERROR;
}
-/* Create an empty filesystem at DST_FS at DST_PATH with the same
- * configuration as SRC_FS (uuid, format, and other parameters).
- * After creation DST_FS has no revisions, not even revision zero. */
-static svn_error_t *
-hotcopy_create_empty_dest(svn_fs_t *src_fs,
- svn_fs_t *dst_fs,
- const char *dst_path,
- apr_pool_t *scratch_pool)
+svn_error_t *
+svn_fs_x__hotcopy(svn_fs_t *src_fs,
+ svn_fs_t *dst_fs,
+ const char *src_path,
+ const char *dst_path,
+ svn_boolean_t incremental,
+ svn_fs_hotcopy_notify_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *scratch_pool,
+ apr_pool_t *common_pool)
{
- svn_fs_x__data_t *src_ffd = src_fs->fsap_data;
-
- /* Create the DST_FS repository with the same layout as SRC_FS. */
- SVN_ERR(svn_fs_x__create_file_tree(dst_fs, dst_path, src_ffd->format,
- src_ffd->max_files_per_dir,
- scratch_pool));
+ hotcopy_body_baton_t hbb;
- /* Copy the UUID. Hotcopy destination receives a new instance ID, but
- * has the same filesystem UUID as the source. */
- SVN_ERR(svn_fs_x__set_uuid(dst_fs, src_fs->uuid, NULL, scratch_pool));
-
- /* Remove revision 0 contents. Otherwise, it may not get overwritten
- * due to having a newer timestamp. */
- SVN_ERR(svn_io_remove_file2(svn_fs_x__path_rev(dst_fs, 0, scratch_pool),
- FALSE, scratch_pool));
- SVN_ERR(svn_io_remove_file2(svn_fs_x__path_revprops(dst_fs, 0,
- scratch_pool),
- FALSE, scratch_pool));
-
- /* This filesystem is ready. Stamp it with a format number. Fail if
- * the 'format' file should already exist. */
- SVN_ERR(svn_fs_x__write_format(dst_fs, FALSE, scratch_pool));
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
- return SVN_NO_ERROR;
-}
+ SVN_ERR(svn_fs_x__open(src_fs, src_path, scratch_pool));
-svn_error_t *
-svn_fs_x__hotcopy_prepare_target(svn_fs_t *src_fs,
- svn_fs_t *dst_fs,
- const char *dst_path,
- svn_boolean_t incremental,
- apr_pool_t *scratch_pool)
-{
if (incremental)
{
const char *dst_format_abspath;
@@ -736,40 +722,53 @@ svn_fs_x__hotcopy_prepare_target(svn_fs_
scratch_pool));
if (dst_format_kind == svn_node_none)
{
- /* Destination doesn't exist yet. Perform a normal hotcopy to a
- * empty destination using the same configuration as the source. */
- SVN_ERR(hotcopy_create_empty_dest(src_fs, dst_fs, dst_path,
- scratch_pool));
- }
- else
- {
- /* Check the existing repository. */
- SVN_ERR(svn_fs_x__open(dst_fs, dst_path, scratch_pool));
- SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs));
+ /* No destination? Fallback to a non-incremental hotcopy. */
+ incremental = FALSE;
}
}
+
+ if (incremental)
+ {
+ /* Check the existing repository. */
+ SVN_ERR(svn_fs_x__open(dst_fs, dst_path, scratch_pool));
+ SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs));
+
+ SVN_ERR(svn_fs_x__initialize_shared_data(dst_fs, common_pool_lock,
+ scratch_pool, common_pool));
+ SVN_ERR(svn_fs_x__initialize_caches(dst_fs, scratch_pool));
+ }
else
{
/* Start out with an empty destination using the same configuration
* as the source. */
- SVN_ERR(hotcopy_create_empty_dest(src_fs, dst_fs, dst_path,
- scratch_pool));
- }
+ svn_fs_x__data_t *src_ffd = src_fs->fsap_data;
- return SVN_NO_ERROR;
-}
+ /* Create the DST_FS repository with the same layout as SRC_FS. */
+ SVN_ERR(svn_fs_x__create_file_tree(dst_fs, dst_path, src_ffd->format,
+ src_ffd->max_files_per_dir,
+ scratch_pool));
+
+ /* Copy the UUID. Hotcopy destination receives a new instance ID, but
+ * has the same filesystem UUID as the source. */
+ SVN_ERR(svn_fs_x__set_uuid(dst_fs, src_fs->uuid, NULL, TRUE,
+ scratch_pool));
+
+ /* Remove revision 0 contents. Otherwise, it may not get overwritten
+ * due to having a newer timestamp. */
+ SVN_ERR(hotcopy_remove_file(svn_fs_x__path_rev(dst_fs, 0,
+ scratch_pool),
+ scratch_pool));
+ SVN_ERR(hotcopy_remove_file(svn_fs_x__path_revprops(dst_fs, 0,
+ scratch_pool),
+ scratch_pool));
+
+ SVN_ERR(svn_fs_x__initialize_shared_data(dst_fs, common_pool_lock,
+ scratch_pool, common_pool));
+ SVN_ERR(svn_fs_x__initialize_caches(dst_fs, scratch_pool));
+ }
-svn_error_t *
-svn_fs_x__hotcopy(svn_fs_t *src_fs,
- svn_fs_t *dst_fs,
- svn_boolean_t incremental,
- svn_fs_hotcopy_notify_t notify_func,
- void *notify_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *scratch_pool)
-{
- hotcopy_body_baton_t hbb;
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
hbb.src_fs = src_fs;
hbb.dst_fs = dst_fs;
@@ -778,8 +777,16 @@ svn_fs_x__hotcopy(svn_fs_t *src_fs,
hbb.notify_baton = notify_baton;
hbb.cancel_func = cancel_func;
hbb.cancel_baton = cancel_baton;
- SVN_ERR(svn_fs_x__with_all_locks(dst_fs, hotcopy_locking_src_body, &hbb,
- scratch_pool));
+
+ /* Lock the destination in the incremental mode. For a non-incremental
+ * hotcopy, don't take any locks. In that case the destination cannot be
+ * opened until the hotcopy finishes, and we don't have to worry about
+ * concurrency. */
+ if (incremental)
+ SVN_ERR(svn_fs_x__with_all_locks(dst_fs, hotcopy_body, &hbb,
+ scratch_pool));
+ else
+ SVN_ERR(hotcopy_body(&hbb, scratch_pool));
return SVN_NO_ERROR;
}
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/hotcopy.h
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/hotcopy.h?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/hotcopy.h (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/hotcopy.h Fri Apr 29 18:38:53 2016
@@ -25,29 +25,24 @@
#include "fs.h"
-/* Create an empty copy of the fsfs filesystem SRC_FS into a new DST_FS at
- * DST_PATH. If INCREMENTAL is TRUE, perform a few pre-checks only if
- * a repo already exists at DST_PATH.
- * Use SCRATCH_POOL for temporary allocations. */
-svn_error_t *
-svn_fs_x__hotcopy_prepare_target(svn_fs_t *src_fs,
- svn_fs_t *dst_fs,
- const char *dst_path,
- svn_boolean_t incremental,
- apr_pool_t *scratch_pool);
-
-/* Copy the fsfs filesystem SRC_FS into DST_FS. If INCREMENTAL is TRUE, do
- * not re-copy data which already exists in DST_FS. Indicate progress via
- * the optional NOTIFY_FUNC callback using NOTIFY_BATON.
- * Use SCRATCH_POOL for temporary allocations. */
+/* Copy the fsfs filesystem SRC_FS at SRC_PATH into a new copy DST_FS at
+ * DST_PATH. If INCREMENTAL is TRUE, do not re-copy data which already
+ * exists in DST_FS. Indicate progress via the optional NOTIFY_FUNC
+ * callback using NOTIFY_BATON. Use COMMON_POOL for process-wide and
+ * SCRATCH_POOL for temporary allocations. Use COMMON_POOL_LOCK to ensure
+ * that the initialization of the shared data is serialized. */
svn_error_t *
svn_fs_x__hotcopy(svn_fs_t *src_fs,
svn_fs_t *dst_fs,
+ const char *src_path,
+ const char *dst_path,
svn_boolean_t incremental,
svn_fs_hotcopy_notify_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
- apr_pool_t *scratch_pool);
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *scratch_pool,
+ apr_pool_t *common_pool);
#endif