You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2016/10/11 09:11:54 UTC
svn commit: r1764214 [5/21] - in /subversion/branches/ra-git: ./ build/
build/ac-macros/ build/generator/ build/win32/ contrib/client-side/
contrib/client-side/svnmerge/ contrib/hook-scripts/ contrib/server-side/
contrib/server-side/fsfsfixer/fixer/ co...
Modified: subversion/branches/ra-git/subversion/libsvn_diff/diff3.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_diff/diff3.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_diff/diff3.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_diff/diff3.c Tue Oct 11 09:11:50 2016
@@ -29,6 +29,7 @@
#include "svn_pools.h"
#include "svn_error.h"
#include "svn_diff.h"
+#include "svn_sorts.h"
#include "svn_types.h"
#include "diff.h"
@@ -324,6 +325,7 @@ svn_diff_diff3_2(svn_diff_t **diff,
/* Produce a merged diff */
{
svn_diff_t **diff_ref = diff;
+ svn_diff_t *diff_last = NULL;
apr_off_t original_start = 1;
apr_off_t modified_start = 1;
@@ -433,6 +435,7 @@ svn_diff_diff3_2(svn_diff_t **diff,
if (is_modified || is_latest)
{
+ svn_boolean_t add_diff = TRUE;
modified_length = modified_sync - modified_start;
latest_length = latest_sync - latest_start;
@@ -453,17 +456,41 @@ svn_diff_diff3_2(svn_diff_t **diff,
&position_list[2],
num_tokens,
pool);
+ /* add_diff = TRUE */
}
- else if (is_modified)
+ else if (is_modified
+ && (!diff_last
+ || diff_last->type != svn_diff__type_diff_latest))
{
(*diff_ref)->type = svn_diff__type_diff_modified;
+ /* add_diff = TRUE */
}
- else
+ else if (is_latest
+ && (!diff_last
+ || diff_last->type != svn_diff__type_diff_modified))
{
(*diff_ref)->type = svn_diff__type_diff_latest;
+ /* add_diff = TRUE */
}
+ else
+ {
+ /* We have a latest and a modified region that touch each other,
+ but not directly change the same location. Create a single
+ conflict region to properly mark a conflict, and to ease
+ resolving. */
+ diff_last->type = svn_diff__type_conflict;
+ diff_last->original_length += (*diff_ref)->original_length;
+ diff_last->modified_length += (*diff_ref)->modified_length;
+ diff_last->latest_length += (*diff_ref)->latest_length;
- diff_ref = &(*diff_ref)->next;
+ add_diff = FALSE;
+ }
+
+ if (add_diff)
+ {
+ diff_last = *diff_ref;
+ diff_ref = &(*diff_ref)->next;
+ }
}
/* Detect EOF */
@@ -474,21 +501,24 @@ svn_diff_diff3_2(svn_diff_t **diff,
- (original_sync - lcs_om->position[0]->offset);
latest_length = lcs_ol->length
- (original_sync - lcs_ol->position[0]->offset);
- common_length = modified_length < latest_length
- ? modified_length : latest_length;
+ common_length = MIN(modified_length, latest_length);
- (*diff_ref) = apr_palloc(pool, sizeof(**diff_ref));
+ if (common_length > 0)
+ {
+ (*diff_ref) = apr_palloc(pool, sizeof(**diff_ref));
- (*diff_ref)->type = svn_diff__type_common;
- (*diff_ref)->original_start = original_sync - 1;
- (*diff_ref)->original_length = common_length;
- (*diff_ref)->modified_start = modified_sync - 1;
- (*diff_ref)->modified_length = common_length;
- (*diff_ref)->latest_start = latest_sync - 1;
- (*diff_ref)->latest_length = common_length;
- (*diff_ref)->resolved_diff = NULL;
+ (*diff_ref)->type = svn_diff__type_common;
+ (*diff_ref)->original_start = original_sync - 1;
+ (*diff_ref)->original_length = common_length;
+ (*diff_ref)->modified_start = modified_sync - 1;
+ (*diff_ref)->modified_length = common_length;
+ (*diff_ref)->latest_start = latest_sync - 1;
+ (*diff_ref)->latest_length = common_length;
+ (*diff_ref)->resolved_diff = NULL;
- diff_ref = &(*diff_ref)->next;
+ diff_last = *diff_ref;
+ diff_ref = &(*diff_ref)->next;
+ }
/* Set the new offsets */
original_start = original_sync + common_length;
Modified: subversion/branches/ra-git/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_diff/parse-diff.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_diff/parse-diff.c Tue Oct 11 09:11:50 2016
@@ -89,6 +89,10 @@ struct svn_diff_hunk_t {
/* Did we see a 'file does not end with eol' marker in this hunk? */
svn_boolean_t original_no_final_eol;
svn_boolean_t modified_no_final_eol;
+
+ /* Fuzz penalty, triggered by bad patch targets */
+ svn_linenum_t original_fuzz;
+ svn_linenum_t modified_fuzz;
};
struct svn_diff_binary_patch_t {
@@ -122,7 +126,7 @@ add_or_delete_single_line(svn_diff_hunk_
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_diff_hunk_t *hunk = apr_palloc(result_pool, sizeof(*hunk));
+ svn_diff_hunk_t *hunk = apr_pcalloc(result_pool, sizeof(*hunk));
static const char *hunk_header[] = { "@@ -1 +0,0 @@\n", "@@ -0,0 +1 @@\n" };
const apr_size_t header_len = strlen(hunk_header[add]);
const apr_size_t len = strlen(line);
@@ -285,6 +289,12 @@ svn_diff_hunk_get_trailing_context(const
return hunk->trailing_context;
}
+svn_linenum_t
+svn_diff_hunk__get_fuzz_penalty(const svn_diff_hunk_t *hunk)
+{
+ return hunk->patch->reverse ? hunk->original_fuzz : hunk->modified_fuzz;
+}
+
/* Baton for the base85 stream implementation */
struct base85_baton_t
{
@@ -1183,24 +1193,38 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
}
c = line->data[0];
- if (original_lines > 0 && modified_lines > 0 &&
- ((c == ' ')
+ if (c == ' '
+ || ((original_lines > 0 && modified_lines > 0)
+ && (
/* Tolerate chopped leading spaces on empty lines. */
- || (! eof && line->len == 0)
+ (! eof && line->len == 0)
/* Maybe tolerate chopped leading spaces on non-empty lines. */
- || (ignore_whitespace && c != del && c != add)))
+ || (ignore_whitespace && c != del && c != add))))
{
/* It's a "context" line in the hunk. */
hunk_seen = TRUE;
- original_lines--;
- modified_lines--;
+ if (original_lines > 0)
+ original_lines--;
+ else
+ {
+ (*hunk)->original_length++;
+ (*hunk)->original_fuzz++;
+ }
+ if (modified_lines > 0)
+ modified_lines--;
+ else
+ {
+ (*hunk)->modified_length++;
+ (*hunk)->modified_fuzz++;
+ }
if (changed_line_seen)
trailing_context++;
else
leading_context++;
last_line_type = context_line;
}
- else if (original_lines > 0 && c == del)
+ else if (c == del
+ && (original_lines > 0 || line->data[1] != del))
{
/* It's a "deleted" line in the hunk. */
hunk_seen = TRUE;
@@ -1211,10 +1235,17 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
if (trailing_context > 0)
trailing_context = 0;
- original_lines--;
+ if (original_lines > 0)
+ original_lines--;
+ else
+ {
+ (*hunk)->original_length++;
+ (*hunk)->original_fuzz++;
+ }
last_line_type = original_line;
}
- else if (modified_lines > 0 && c == add)
+ else if (c == add
+ && (modified_lines > 0 || line->data[1] != add))
{
/* It's an "added" line in the hunk. */
hunk_seen = TRUE;
@@ -1225,7 +1256,13 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
if (trailing_context > 0)
trailing_context = 0;
- modified_lines--;
+ if (modified_lines > 0)
+ modified_lines--;
+ else
+ {
+ (*hunk)->modified_length++;
+ (*hunk)->modified_fuzz++;
+ }
last_line_type = modified_line;
}
else
@@ -1241,7 +1278,6 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
* after the hunk text. */
end = last_line;
}
-
if (original_end == 0)
original_end = end;
if (modified_end == 0)
@@ -1318,6 +1354,21 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
if (hunk_seen && start < end)
{
+ /* Did we get the number of context lines announced in the header?
+
+ If not... let's limit the number from the header to what we
+ actually have, and apply a fuzz penalty */
+ if (original_lines)
+ {
+ (*hunk)->original_length -= original_lines;
+ (*hunk)->original_fuzz += original_lines;
+ }
+ if (modified_lines)
+ {
+ (*hunk)->modified_length -= modified_lines;
+ (*hunk)->modified_fuzz += modified_lines;
+ }
+
(*hunk)->patch = patch;
(*hunk)->apr_file = apr_file;
(*hunk)->leading_context = leading_context;
@@ -2224,11 +2275,14 @@ svn_diff_parse_next_patch(svn_patch_t **
patch->operation = svn_diff_op_added;
break;
- /* ### case svn_diff_op_copied:
- ### case svn_diff_op_moved:*/
-
case svn_diff_op_modified:
- break; /* Stays modify */
+ break; /* Stays modified. */
+
+ case svn_diff_op_copied:
+ case svn_diff_op_moved:
+ break; /* Stays copied or moved, just in the other direction. */
+ case svn_diff_op_unchanged:
+ break; /* Stays unchanged, of course. */
}
ts_tmp = patch->old_executable_bit;
Modified: subversion/branches/ra-git/subversion/libsvn_fs/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs/deprecated.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs/deprecated.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs/deprecated.c Tue Oct 11 09:11:50 2016
@@ -26,6 +26,7 @@
deprecated functions in this file. */
#define SVN_DEPRECATED
+#include <apr_md5.h>
#include "svn_fs.h"
@@ -144,6 +145,51 @@ svn_fs_get_mergeinfo(svn_mergeinfo_catal
}
svn_error_t *
+svn_fs_paths_changed(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
+ apr_pool_t *pool)
+{
+ apr_hash_t *changed_paths_new_structs;
+ apr_hash_index_t *hi;
+
+ SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool));
+ *changed_paths_p = apr_hash_make(pool);
+ for (hi = apr_hash_first(pool, changed_paths_new_structs);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const void *vkey;
+ apr_ssize_t klen;
+ void *vval;
+ svn_fs_path_change2_t *val;
+ svn_fs_path_change_t *change;
+ apr_hash_this(hi, &vkey, &klen, &vval);
+ val = vval;
+ change = apr_palloc(pool, sizeof(*change));
+ change->node_rev_id = val->node_rev_id;
+ change->change_kind = val->change_kind;
+ change->text_mod = val->text_mod;
+ change->prop_mod = val->prop_mod;
+ apr_hash_set(*changed_paths_p, vkey, klen, change);
+ }
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_file_md5_checksum(unsigned char digest[],
+ svn_fs_root_t *root,
+ const char *path,
+ apr_pool_t *pool)
+{
+ svn_checksum_t *md5sum;
+
+ SVN_ERR(svn_fs_file_checksum(&md5sum, svn_checksum_md5, root, path, TRUE,
+ pool));
+ memcpy(digest, md5sum->digest, APR_MD5_DIGESTSIZE);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_fs_history_prev(svn_fs_history_t **prev_history_p,
svn_fs_history_t *history, svn_boolean_t cross_copies,
apr_pool_t *pool)
Modified: subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.c Tue Oct 11 09:11:50 2016
@@ -26,7 +26,6 @@
#include <apr.h>
#include <apr_atomic.h>
#include <apr_hash.h>
-#include <apr_md5.h>
#include <apr_uuid.h>
#include <apr_strings.h>
@@ -46,6 +45,7 @@
#include "private/svn_atomic.h"
#include "private/svn_fs_private.h"
#include "private/svn_fs_util.h"
+#include "private/svn_fspath.h"
#include "private/svn_utf_private.h"
#include "private/svn_mutex.h"
#include "private/svn_subr_private.h"
@@ -60,6 +60,22 @@
#define FS_TYPE_FILENAME "fs-type"
+/* If a FS backend does not implement the PATHS_CHANGED vtable function,
+ it will get emulated. However, if this macro is defined to non-null
+ then the API will always be emulated when feasible, i.e. the calls
+ get "re-directed" to the new API implementation. */
+#ifndef SVN_FS_EMULATE_PATHS_CHANGED
+#define SVN_FS_EMULATE_PATHS_CHANGED FALSE
+#endif
+
+/* If a FS backend does not implement the REPORT_CHANGES vtable function,
+ it will get emulated. However, if this macro is defined to non-null
+ then the API will always be emulated when feasible, i.e. the calls
+ get "re-directed" to the old API implementation. */
+#ifndef SVN_FS_EMULATE_REPORT_CHANGES
+#define SVN_FS_EMULATE_REPORT_CHANGES FALSE
+#endif
+
/* A pool common to all FS objects. See the documentation on the
open/create functions in fs-loader.h and for svn_fs_initialize(). */
static apr_pool_t *common_pool = NULL;
@@ -1052,40 +1068,163 @@ svn_fs_revision_root_revision(svn_fs_roo
}
svn_error_t *
+svn_fs_path_change_get(svn_fs_path_change3_t **change,
+ svn_fs_path_change_iterator_t *iterator)
+{
+ return iterator->vtable->get(change, iterator);
+}
+
+svn_error_t *
svn_fs_paths_changed2(apr_hash_t **changed_paths_p,
svn_fs_root_t *root,
apr_pool_t *pool)
{
- return root->vtable->paths_changed(changed_paths_p, root, pool);
+ svn_boolean_t emulate = !root->vtable->paths_changed
+ || SVN_FS_EMULATE_PATHS_CHANGED;
+
+ if (emulate)
+ {
+ apr_pool_t *scratch_pool = svn_pool_create(pool);
+ apr_hash_t *changes = svn_hash__make(pool);
+
+ svn_fs_path_change_iterator_t *iterator;
+ svn_fs_path_change3_t *change;
+
+ SVN_ERR(svn_fs_paths_changed3(&iterator, root, scratch_pool,
+ scratch_pool));
+
+ SVN_ERR(svn_fs_path_change_get(&change, iterator));
+ while (change)
+ {
+ svn_fs_path_change2_t *copy;
+ const svn_fs_id_t *id_copy;
+ const char *change_path = change->path.data;
+ svn_fs_root_t *change_root = root;
+
+ /* Copy CHANGE to old API struct. */
+ if (change->change_kind == svn_fs_path_change_delete)
+ SVN_ERR(svn_fs__get_deleted_node(&change_root, &change_path,
+ change_root, change_path,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_fs_node_id(&id_copy, change_root, change_path, pool));
+
+ copy = svn_fs_path_change2_create(id_copy, change->change_kind,
+ pool);
+ copy->copyfrom_known = change->copyfrom_known;
+ if ( copy->copyfrom_known
+ && SVN_IS_VALID_REVNUM(change->copyfrom_rev))
+ {
+ copy->copyfrom_rev = change->copyfrom_rev;
+ copy->copyfrom_path = apr_pstrdup(pool, change->copyfrom_path);
+ }
+ copy->mergeinfo_mod = change->mergeinfo_mod;
+ copy->node_kind = change->node_kind;
+ copy->prop_mod = change->prop_mod;
+ copy->text_mod = change->text_mod;
+
+ svn_hash_sets(changes, apr_pstrmemdup(pool, change->path.data,
+ change->path.len), copy);
+
+ /* Next change. */
+ SVN_ERR(svn_fs_path_change_get(&change, iterator));
+ }
+ svn_pool_destroy(scratch_pool);
+
+ *changed_paths_p = changes;
+ }
+ else
+ {
+ SVN_ERR(root->vtable->paths_changed(changed_paths_p, root, pool));
+ }
+
+ return SVN_NO_ERROR;
}
-svn_error_t *
-svn_fs_paths_changed(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
- apr_pool_t *pool)
+/* Implement svn_fs_path_change_iterator_t on top of svn_fs_paths_changed2. */
+
+/* The iterator builds upon a hash iterator, which in turn operates on the
+ full prefetched changes list. */
+typedef struct fsap_iterator_data_t
{
- apr_hash_t *changed_paths_new_structs;
apr_hash_index_t *hi;
- SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool));
- *changed_paths_p = apr_hash_make(pool);
- for (hi = apr_hash_first(pool, changed_paths_new_structs);
- hi;
- hi = apr_hash_next(hi))
- {
- const void *vkey;
- apr_ssize_t klen;
- void *vval;
- svn_fs_path_change2_t *val;
- svn_fs_path_change_t *change;
- apr_hash_this(hi, &vkey, &klen, &vval);
- val = vval;
- change = apr_palloc(pool, sizeof(*change));
- change->node_rev_id = val->node_rev_id;
- change->change_kind = val->change_kind;
- change->text_mod = val->text_mod;
- change->prop_mod = val->prop_mod;
- apr_hash_set(*changed_paths_p, vkey, klen, change);
+ /* For efficicency such that we don't need to dynamically allocate
+ yet another copy of that data. */
+ svn_fs_path_change3_t change;
+} fsap_iterator_data_t;
+
+static svn_error_t *
+changes_iterator_get(svn_fs_path_change3_t **change,
+ svn_fs_path_change_iterator_t *iterator)
+{
+ fsap_iterator_data_t *data = iterator->fsap_data;
+
+ if (data->hi)
+ {
+ const char *path = apr_hash_this_key(data->hi);
+ svn_fs_path_change2_t *entry = apr_hash_this_val(data->hi);
+
+ data->change.path.data = path;
+ data->change.path.len = apr_hash_this_key_len(data->hi);
+ data->change.change_kind = entry->change_kind;
+ data->change.node_kind = entry->node_kind;
+ data->change.text_mod = entry->text_mod;
+ data->change.prop_mod = entry->prop_mod;
+ data->change.mergeinfo_mod = entry->mergeinfo_mod;
+ data->change.copyfrom_known = entry->copyfrom_known;
+ data->change.copyfrom_rev = entry->copyfrom_rev;
+ data->change.copyfrom_path = entry->copyfrom_path;
+
+ *change = &data->change;
+ data->hi = apr_hash_next(data->hi);
+ }
+ else
+ {
+ *change = NULL;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static changes_iterator_vtable_t iterator_vtable =
+{
+ changes_iterator_get
+};
+
+svn_error_t *
+svn_fs_paths_changed3(svn_fs_path_change_iterator_t **iterator,
+ svn_fs_root_t *root,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_boolean_t emulate = !root->vtable->report_changes
+ || ( SVN_FS_EMULATE_REPORT_CHANGES
+ && root->vtable->paths_changed);
+
+ if (emulate)
+ {
+ svn_fs_path_change_iterator_t *result;
+ fsap_iterator_data_t *data;
+
+ apr_hash_t *changes;
+ SVN_ERR(root->vtable->paths_changed(&changes, root, result_pool));
+
+ data = apr_pcalloc(result_pool, sizeof(*data));
+ data->hi = apr_hash_first(result_pool, changes);
+
+ result = apr_pcalloc(result_pool, sizeof(*result));
+ result->fsap_data = data;
+ result->vtable = &iterator_vtable;
+
+ *iterator = result;
}
+ else
+ {
+ SVN_ERR(root->vtable->report_changes(iterator, root, result_pool,
+ scratch_pool));
+ }
+
return SVN_NO_ERROR;
}
@@ -1374,36 +1513,17 @@ svn_fs_file_checksum(svn_checksum_t **ch
if (force && (*checksum == NULL || (*checksum)->kind != kind))
{
- svn_stream_t *contents, *checksum_contents;
+ svn_stream_t *contents;
SVN_ERR(svn_fs_file_contents(&contents, root, path, pool));
- checksum_contents = svn_stream_checksummed2(contents, checksum, NULL,
- kind, TRUE, pool);
-
- /* This will force a read of any remaining data (which is all of it in
- this case) and dump the checksum into checksum->digest. */
- SVN_ERR(svn_stream_close(checksum_contents));
+ SVN_ERR(svn_stream_contents_checksum(checksum, contents, kind,
+ pool, pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
-svn_fs_file_md5_checksum(unsigned char digest[],
- svn_fs_root_t *root,
- const char *path,
- apr_pool_t *pool)
-{
- svn_checksum_t *md5sum;
-
- SVN_ERR(svn_fs_file_checksum(&md5sum, svn_checksum_md5, root, path, TRUE,
- pool));
- memcpy(digest, md5sum->digest, APR_MD5_DIGESTSIZE);
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
svn_fs_file_contents(svn_stream_t **contents, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
@@ -1597,6 +1717,64 @@ svn_fs_get_file_delta_stream(svn_txdelta
}
svn_error_t *
+svn_fs__get_deleted_node(svn_fs_root_t **node_root,
+ const char **node_path,
+ svn_fs_root_t *root,
+ const char *path,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *parent_path, *name;
+ svn_fs_root_t *copy_root;
+ const char *copy_path;
+
+ /* History traversal does not work with transaction roots.
+ * Therefore, do it "by hand". */
+
+ /* If the parent got copied in ROOT, PATH got copied with it.
+ * Otherwise, we will find the node at PATH in the revision prior to ROOT.
+ */
+ svn_fspath__split(&parent_path, &name, path, scratch_pool);
+ SVN_ERR(svn_fs_closest_copy(©_root, ©_path, root, parent_path,
+ scratch_pool));
+
+ /* Copied in ROOT? */
+ if ( copy_root
+ && ( svn_fs_revision_root_revision(copy_root)
+ == svn_fs_revision_root_revision(root)))
+ {
+ svn_revnum_t copyfrom_rev;
+ const char *copyfrom_path;
+ const char *rel_path;
+ SVN_ERR(svn_fs_copied_from(©from_rev, ©from_path,
+ copy_root, copy_path, scratch_pool));
+
+ SVN_ERR(svn_fs_revision_root(node_root, svn_fs_root_fs(root),
+ copyfrom_rev, result_pool));
+ rel_path = svn_fspath__skip_ancestor(copy_path, path);
+ *node_path = svn_fspath__join(copyfrom_path, rel_path, result_pool);
+ }
+ else
+ {
+ svn_revnum_t revision;
+ svn_revnum_t previous_rev;
+
+ /* Determine the latest revision before ROOT. */
+ revision = svn_fs_revision_root_revision(root);
+ if (SVN_IS_VALID_REVNUM(revision))
+ previous_rev = revision - 1;
+ else
+ previous_rev = svn_fs_txn_root_base_revision(root);
+
+ SVN_ERR(svn_fs_revision_root(node_root, svn_fs_root_fs(root),
+ previous_rev, result_pool));
+ *node_path = apr_pstrdup(result_pool, path);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool)
{
/* If you change this, consider changing svn_fs__identifier(). */
@@ -1963,6 +2141,28 @@ svn_fs_path_change2_create(const svn_fs_
return svn_fs__path_change_create_internal(node_rev_id, change_kind, pool);
}
+svn_fs_path_change3_t *
+svn_fs_path_change3_create(svn_fs_path_change_kind_t change_kind,
+ apr_pool_t *result_pool)
+{
+ return svn_fs__path_change_create_internal2(change_kind, result_pool);
+}
+
+svn_fs_path_change3_t *
+svn_fs_path_change3_dup(svn_fs_path_change3_t *change,
+ apr_pool_t *result_pool)
+{
+ svn_fs_path_change3_t *copy = apr_pmemdup(result_pool, change,
+ sizeof(*copy));
+
+ copy->path.data = apr_pstrmemdup(result_pool, copy->path.data,
+ copy->path.len);
+ if (copy->copyfrom_path)
+ copy->copyfrom_path = apr_pstrdup(result_pool, change->copyfrom_path);
+
+ return copy;
+}
+
/* Return the library version number. */
const svn_version_t *
svn_fs_version(void)
Modified: subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs/fs-loader.h Tue Oct 11 09:11:50 2016
@@ -302,6 +302,10 @@ typedef struct root_vtable_t
svn_error_t *(*paths_changed)(apr_hash_t **changed_paths_p,
svn_fs_root_t *root,
apr_pool_t *pool);
+ svn_error_t *(*report_changes)(svn_fs_path_change_iterator_t **iterator,
+ svn_fs_root_t *root,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
/* Generic node operations */
svn_error_t *(*check_path)(svn_node_kind_t *kind_p, svn_fs_root_t *root,
@@ -427,6 +431,13 @@ typedef struct root_vtable_t
} root_vtable_t;
+typedef struct changes_iterator_vtable_t
+{
+ svn_error_t *(*get)(svn_fs_path_change3_t **change,
+ svn_fs_path_change_iterator_t *iterator);
+} changes_iterator_vtable_t;
+
+
typedef struct history_vtable_t
{
svn_error_t *(*prev)(svn_fs_history_t **prev_history_p,
@@ -529,6 +540,12 @@ struct svn_fs_root_t
void *fsap_data;
};
+struct svn_fs_path_change_iterator_t
+{
+ /* FSAP-specific vtable and private data */
+ const changes_iterator_vtable_t *vtable;
+ void *fsap_data;
+};
struct svn_fs_history_t
{
Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c Tue Oct 11 09:11:50 2016
@@ -2661,7 +2661,7 @@ txn_body_commit(void *baton, trail_t *tr
svn_revnum_t youngest_rev;
const svn_fs_id_t *y_rev_root_id;
- dag_node_t *txn_base_root_node;
+ dag_node_t *txn_base_root_node, *txn_root_node;
/* Getting the youngest revision locks the revisions table until
this trail is done. */
@@ -2694,6 +2694,19 @@ txn_body_commit(void *baton, trail_t *tr
discovered locks. */
SVN_ERR(verify_locks(txn_name, trail, trail->pool));
+ /* Ensure every txn has a mutable root as then the new revision will
+ have a distinct root node-revision-id. This is necessary as
+ future transactions use the root node-revision-id as a proxy for
+ the transaction base revision. */
+ SVN_ERR(svn_fs_base__dag_txn_root(&txn_root_node, fs, txn_name,
+ trail, trail->pool));
+ if (!svn_fs_base__dag_check_mutable(txn_root_node, txn->id))
+ {
+ dag_node_t *clone;
+ SVN_ERR(svn_fs_base__dag_clone_root(&clone, fs, txn->id,
+ trail, trail->pool));
+ }
+
/* Else, commit the txn. */
return svn_fs_base__dag_commit_txn(&(args->new_rev), txn, trail,
trail->pool);
@@ -5493,6 +5506,7 @@ base_get_mergeinfo(svn_mergeinfo_catalog
static root_vtable_t root_vtable = {
base_paths_changed,
+ NULL,
base_check_path,
base_node_history,
base_node_id,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c Tue Oct 11 09:11:50 2016
@@ -2042,7 +2042,7 @@ skip_contents(struct rep_read_baton *bat
else if (len > 0)
{
/* Simply drain LEN bytes from the window stream. */
- apr_pool_t *subpool = subpool = svn_pool_create(baton->pool);
+ apr_pool_t *subpool = svn_pool_create(baton->pool);
char *buffer = apr_palloc(subpool, SVN__STREAM_CHUNK_SIZE);
while (len > 0 && !err)
@@ -2453,8 +2453,11 @@ read_dir_entries(apr_array_header_t **en
char *str;
svn_pool_clear(iterpool);
- SVN_ERR(svn_hash__read_entry(&entry, stream, terminator,
- incremental, iterpool));
+ SVN_ERR_W(svn_hash__read_entry(&entry, stream, terminator,
+ incremental, iterpool),
+ apr_psprintf(iterpool,
+ _("Directory representation corrupt in '%s'"),
+ svn_fs_fs__id_unparse(id, scratch_pool)->data));
/* End of directory? */
if (entry.key == NULL)
@@ -2715,8 +2718,12 @@ svn_fs_fs__rep_contents_dir(apr_array_he
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. */
- if (cache)
+ /* 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));
return SVN_NO_ERROR;
@@ -2740,6 +2747,7 @@ svn_fs_fs__rep_contents_dir_entry(svn_fs
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ extract_dir_entry_baton_t baton;
svn_boolean_t found = FALSE;
/* find the cache we may use */
@@ -2749,8 +2757,6 @@ svn_fs_fs__rep_contents_dir_entry(svn_fs
scratch_pool);
if (cache)
{
- extract_dir_entry_baton_t baton;
-
svn_filesize_t filesize;
SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
@@ -2767,7 +2773,7 @@ svn_fs_fs__rep_contents_dir_entry(svn_fs
}
/* fetch data from disk if we did not find it in the cache */
- if (! found)
+ if (! found || baton.out_of_date)
{
svn_fs_dirent_t *entry;
svn_fs_dirent_t *entry_copy = NULL;
@@ -2777,8 +2783,12 @@ svn_fs_fs__rep_contents_dir_entry(svn_fs
SVN_ERR(get_dir_contents(&dir, fs, noderev, scratch_pool,
scratch_pool));
- /* Update the cache, if we are to use one. */
- if (cache)
+ /* 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 */
@@ -2874,23 +2884,42 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
}
svn_error_t *
+svn_fs_fs__create_changes_context(svn_fs_fs__changes_context_t **context,
+ svn_fs_t *fs,
+ svn_revnum_t rev,
+ apr_pool_t *result_pool)
+{
+ svn_fs_fs__changes_context_t *result = apr_pcalloc(result_pool,
+ sizeof(*result));
+ result->fs = fs;
+ result->revision = rev;
+ result->rev_file_pool = result_pool;
+
+ *context = result;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_fs_fs__get_changes(apr_array_header_t **changes,
- svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *result_pool)
+ svn_fs_fs__changes_context_t *context,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
apr_off_t item_index = SVN_FS_FS__ITEM_INDEX_CHANGES;
- svn_fs_fs__revision_file_t *revision_file;
svn_boolean_t found;
- fs_fs_data_t *ffd = fs->fsap_data;
- apr_pool_t *scratch_pool = svn_pool_create(result_pool);
+ fs_fs_data_t *ffd = context->fs->fsap_data;
+ svn_fs_fs__changes_list_t *changes_list;
+
+ pair_cache_key_t key;
+ key.revision = context->revision;
+ key.second = context->next;
/* try cache lookup first */
if (ffd->changes_cache)
{
- SVN_ERR(svn_cache__get((void **) changes, &found, ffd->changes_cache,
- &rev, result_pool));
+ SVN_ERR(svn_cache__get((void **)&changes_list, &found,
+ ffd->changes_cache, &key, result_pool));
}
else
{
@@ -2901,34 +2930,54 @@ svn_fs_fs__get_changes(apr_array_header_
{
/* read changes from revision file */
- SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, scratch_pool));
- SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&revision_file, fs, rev,
- scratch_pool, scratch_pool));
-
- if (use_block_read(fs))
- {
- /* 'block-read' will also provide us with the desired data */
- SVN_ERR(block_read((void **)changes, fs,
- rev, SVN_FS_FS__ITEM_INDEX_CHANGES,
- revision_file, result_pool, scratch_pool));
+ if (!context->revision_file)
+ {
+ SVN_ERR(svn_fs_fs__ensure_revision_exists(context->revision,
+ context->fs,
+ scratch_pool));
+ SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&context->revision_file,
+ context->fs,
+ context->revision,
+ context->rev_file_pool,
+ scratch_pool));
+ }
+
+ if (use_block_read(context->fs))
+ {
+ /* 'block-read' will probably populate the cache with the data
+ * that we want. However, we won't want to force it to process
+ * very large change lists as part of this prefetching mechanism.
+ * Those would be better handled by the iterative code below. */
+ SVN_ERR(block_read(NULL, context->fs,
+ context->revision, SVN_FS_FS__ITEM_INDEX_CHANGES,
+ context->revision_file, scratch_pool,
+ scratch_pool));
+
+ /* This may succeed now ... */
+ SVN_ERR(svn_cache__get((void **)&changes_list, &found,
+ ffd->changes_cache, &key, result_pool));
}
- else
+
+ /* If we still have no data, read it here. */
+ if (!found)
{
apr_off_t changes_offset;
/* Addressing is very different for old formats
* (needs to read the revision trailer). */
- if (svn_fs_fs__use_log_addressing(fs))
+ if (svn_fs_fs__use_log_addressing(context->fs))
{
- SVN_ERR(svn_fs_fs__item_offset(&changes_offset, fs,
- revision_file, rev, NULL,
+ SVN_ERR(svn_fs_fs__item_offset(&changes_offset, context->fs,
+ context->revision_file,
+ context->revision, NULL,
SVN_FS_FS__ITEM_INDEX_CHANGES,
scratch_pool));
}
else
{
SVN_ERR(get_root_changes_offset(NULL, &changes_offset,
- revision_file, fs, rev,
+ context->revision_file,
+ context->fs, context->revision,
scratch_pool));
/* This variable will be used for debug logging only. */
@@ -2936,35 +2985,58 @@ svn_fs_fs__get_changes(apr_array_header_
}
/* Actual reading and parsing are the same, though. */
- SVN_ERR(aligned_seek(fs, revision_file->file, NULL, changes_offset,
+ SVN_ERR(aligned_seek(context->fs, context->revision_file->file,
+ NULL, changes_offset + context->next_offset,
scratch_pool));
- SVN_ERR(svn_fs_fs__read_changes(changes, revision_file->stream,
+
+ SVN_ERR(svn_fs_fs__read_changes(changes,
+ context->revision_file->stream,
+ SVN_FS_FS__CHANGES_BLOCK_SIZE,
result_pool, scratch_pool));
+ /* Construct the info object for the entries block we just read. */
+ changes_list = apr_pcalloc(scratch_pool, sizeof(*changes_list));
+ SVN_ERR(svn_io_file_get_offset(&changes_list->end_offset,
+ context->revision_file->file,
+ scratch_pool));
+ changes_list->end_offset -= changes_offset;
+ changes_list->start_offset = context->next_offset;
+ changes_list->count = (*changes)->nelts;
+ changes_list->changes = (change_t **)(*changes)->elts;
+ changes_list->eol = changes_list->count < SVN_FS_FS__CHANGES_BLOCK_SIZE;
+
/* cache for future reference */
if (ffd->changes_cache)
- {
- /* Guesstimate for the size of the in-cache representation. */
- apr_size_t estimated_size = (apr_size_t)250 * (*changes)->nelts;
-
- /* Don't even serialize data that probably won't fit into the
- * cache. This often implies that either CHANGES is very
- * large, memory is scarce or both. Having a huge temporary
- * copy would not be a good thing in either case. */
- if (svn_cache__is_cachable(ffd->changes_cache, estimated_size))
- SVN_ERR(svn_cache__set(ffd->changes_cache, &rev, *changes,
- scratch_pool));
- }
+ SVN_ERR(svn_cache__set(ffd->changes_cache, &key, changes_list,
+ scratch_pool));
}
+ }
+
+ if (found)
+ {
+ /* Return the block as a "proper" APR array. */
+ (*changes) = apr_array_make(result_pool, 0, sizeof(void *));
+ (*changes)->elts = (char *)changes_list->changes;
+ (*changes)->nelts = changes_list->count;
+ (*changes)->nalloc = changes_list->count;
+ }
+
+ /* Where to look next - if there is more data. */
+ context->next += (*changes)->nelts;
+ context->next_offset = changes_list->end_offset;
+ context->eol = changes_list->eol;
- SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
+ /* Close the revision file after we read all data. */
+ if (context->eol && context->revision_file)
+ {
+ SVN_ERR(svn_fs_fs__close_revision_file(context->revision_file));
+ context->revision_file = NULL;
}
- SVN_ERR(dbg_log_access(fs, rev, item_index, *changes,
+ SVN_ERR(dbg_log_access(context->fs, context->revision, item_index, *changes,
SVN_FS_FS__ITEM_TYPE_CHANGES, scratch_pool));
- svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
@@ -3238,9 +3310,8 @@ read_rep_header(svn_fs_fs__rep_header_t
/* 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
- * at or beyond that offset.
+ * 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 *
@@ -3248,7 +3319,6 @@ block_read_contents(svn_fs_t *fs,
svn_fs_fs__revision_file_t *rev_file,
svn_fs_fs__p2l_entry_t* entry,
apr_off_t max_offset,
- apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
pair_cache_key_t header_key = { 0 };
@@ -3258,9 +3328,9 @@ block_read_contents(svn_fs_t *fs,
header_key.second = entry->item.number;
SVN_ERR(read_rep_header(&rep_header, fs, rev_file->stream, &header_key,
- result_pool, scratch_pool));
+ scratch_pool, scratch_pool));
SVN_ERR(block_read_windows(rep_header, fs, rev_file, entry, max_offset,
- result_pool, scratch_pool));
+ scratch_pool, scratch_pool));
return SVN_NO_ERROR;
}
@@ -3309,37 +3379,39 @@ read_item(svn_stream_t **stream,
_("Low-level checksum mismatch while reading\n"
"%s bytes of meta data at offset %s "
"for item %s in revision %ld"),
- apr_psprintf(pool, "%" APR_OFF_T_FMT, entry->size),
- apr_psprintf(pool, "%" APR_OFF_T_FMT, entry->offset),
+ apr_off_t_toa(pool, entry->size),
+ apr_off_t_toa(pool, entry->offset),
apr_psprintf(pool, "%" APR_UINT64_T_FMT, entry->item.number),
entry->item.revision);
}
-/* 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 the already open
- * FILE and wrapping FILE_STREAM. Use POOL for allocations.
+/* If not already cached, read the changed paths list addressed by ENTRY in
+ * FS and cache it if it has no more than SVN_FS_FS__CHANGES_BLOCK_SIZE
+ * entries and caching is enabled. Read the data from REV_FILE.
+ * Allocate temporaries in SCRATCH_POOL.
*/
static svn_error_t *
-block_read_changes(apr_array_header_t **changes,
- svn_fs_t *fs,
+block_read_changes(svn_fs_t *fs,
svn_fs_fs__revision_file_t *rev_file,
svn_fs_fs__p2l_entry_t *entry,
- svn_boolean_t must_read,
- apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
svn_stream_t *stream;
- if (!must_read && !ffd->changes_cache)
+ apr_array_header_t *changes;
+
+ pair_cache_key_t key;
+ key.revision = entry->item.revision;
+ key.second = 0;
+
+ if (!ffd->changes_cache)
return SVN_NO_ERROR;
/* already in cache? */
- if (!must_read && ffd->changes_cache)
+ if (ffd->changes_cache)
{
svn_boolean_t is_cached;
- SVN_ERR(svn_cache__has_key(&is_cached, ffd->changes_cache,
- &entry->item.revision,
+ SVN_ERR(svn_cache__has_key(&is_cached, ffd->changes_cache, &key,
scratch_pool));
if (is_cached)
return SVN_NO_ERROR;
@@ -3347,22 +3419,40 @@ block_read_changes(apr_array_header_t **
SVN_ERR(read_item(&stream, fs, rev_file, entry, scratch_pool));
- /* read changes from revision file */
- SVN_ERR(svn_fs_fs__read_changes(changes, stream, result_pool,
- scratch_pool));
+ /* Read changes from revision file. But read just past the first block to
+ enable us to determine whether the first block already hit the EOL.
- /* cache for future reference */
- if (ffd->changes_cache)
- SVN_ERR(svn_cache__set(ffd->changes_cache, &entry->item.revision,
- *changes, scratch_pool));
+ Note: A 100 entries block is already > 10kB on disk. With a 4kB default
+ disk block size, this function won't even be called for larger
+ changed paths lists. */
+ SVN_ERR(svn_fs_fs__read_changes(&changes, stream,
+ SVN_FS_FS__CHANGES_BLOCK_SIZE + 1,
+ scratch_pool, scratch_pool));
+
+ /* We can only cache small lists that don't need to be split up.
+ For longer lists, we miss the file offset info for the respective */
+ if (changes->nelts <= SVN_FS_FS__CHANGES_BLOCK_SIZE)
+ {
+ svn_fs_fs__changes_list_t changes_list;
+
+ /* Construct the info object for the entries block we just read. */
+ changes_list.end_offset = entry->size;
+ changes_list.start_offset = 0;
+ changes_list.count = changes->nelts;
+ changes_list.changes = (change_t **)changes->elts;
+ changes_list.eol = TRUE;
+
+ SVN_ERR(svn_cache__set(ffd->changes_cache, &key, &changes_list,
+ scratch_pool));
+ }
return SVN_NO_ERROR;
}
-/* If not already cached or if MUST_READ is set, read the nod revision
+/* If not already cached or if MUST_READ is set, read the node revision
* addressed by ENTRY in FS and retúrn it in *NODEREV_P. Cache the
- * result if caching is enabled. Read the data from the already open
- * FILE and wrapping FILE_STREAM. Use SCRATCH_POOL for temporary allocations.
+ * result 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(node_revision_t **noderev_p,
@@ -3512,7 +3602,7 @@ block_read(void **result,
is_wanted
? -1
: block_start + ffd->block_size,
- pool, iterpool));
+ iterpool));
break;
case SVN_FS_FS__ITEM_TYPE_NODEREV:
@@ -3524,10 +3614,8 @@ block_read(void **result,
break;
case SVN_FS_FS__ITEM_TYPE_CHANGES:
- SVN_ERR(block_read_changes((apr_array_header_t **)&item,
- fs, revision_file,
- entry, is_result,
- pool, iterpool));
+ SVN_ERR(block_read_changes(fs, revision_file,
+ entry, iterpool));
break;
default:
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h Tue Oct 11 09:11:50 2016
@@ -158,13 +158,22 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
node_revision_t *noderev,
apr_pool_t *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. */
+svn_error_t *
+svn_fs_fs__create_changes_context(svn_fs_fs__changes_context_t **context,
+ svn_fs_t *fs,
+ svn_revnum_t rev,
+ apr_pool_t *result_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_fs__get_changes(apr_array_header_t **changes,
- svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *pool);
+ svn_fs_fs__changes_context_t *context,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
#endif
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c Tue Oct 11 09:11:50 2016
@@ -66,8 +66,9 @@ normalize_key_part(const char *original,
return normalized->data;
}
-/* *CACHE_TXDELTAS, *CACHE_FULLTEXTS flags will be set according to
- FS->CONFIG. *CACHE_NAMESPACE receives the cache prefix to use.
+/* *CACHE_TXDELTAS, *CACHE_FULLTEXTS, *CACHE_NODEPROPS flags will be set
+ according to FS->CONFIG. *CACHE_NAMESPACE receives the cache prefix to
+ use.
Use FS->pool for allocating the memcache and CACHE_NAMESPACE, and POOL
for temporary allocations. */
@@ -75,6 +76,7 @@ static svn_error_t *
read_config(const char **cache_namespace,
svn_boolean_t *cache_txdeltas,
svn_boolean_t *cache_fulltexts,
+ svn_boolean_t *cache_nodeprops,
svn_fs_t *fs,
apr_pool_t *pool)
{
@@ -117,6 +119,14 @@ read_config(const char **cache_namespace
SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
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;
}
@@ -353,6 +363,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
svn_boolean_t no_handler = ffd->fail_stop;
svn_boolean_t cache_txdeltas;
svn_boolean_t cache_fulltexts;
+ svn_boolean_t cache_nodeprops;
const char *cache_namespace;
svn_boolean_t has_namespace;
@@ -360,6 +371,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(read_config(&cache_namespace,
&cache_txdeltas,
&cache_fulltexts,
+ &cache_nodeprops,
fs,
pool));
@@ -438,7 +450,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
svn_fs_fs__deserialize_dir_entries,
sizeof(pair_cache_key_t),
apr_pstrcat(pool, prefix, "DIR", SVN_VA_NULL),
- SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
has_namespace,
fs,
no_handler,
@@ -498,7 +510,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
1, 8, /* 1k / entry; 8 entries total, rarely used */
svn_fs_fs__serialize_changes,
svn_fs_fs__deserialize_changes,
- sizeof(svn_revnum_t),
+ sizeof(pair_cache_key_t),
apr_pstrcat(pool, prefix, "CHANGES", SVN_VA_NULL),
0,
has_namespace,
@@ -538,21 +550,6 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
no_handler,
fs->pool, pool));
- SVN_ERR(create_cache(&(ffd->properties_cache),
- NULL,
- membuffer,
- 0, 0, /* Do not use the inprocess cache */
- svn_fs_fs__serialize_properties,
- svn_fs_fs__deserialize_properties,
- sizeof(pair_cache_key_t),
- apr_pstrcat(pool, prefix, "PROP",
- SVN_VA_NULL),
- SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
- has_namespace,
- fs,
- no_handler,
- fs->pool, pool));
-
SVN_ERR(create_cache(&(ffd->mergeinfo_cache),
NULL,
membuffer,
@@ -586,11 +583,33 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
else
{
ffd->fulltext_cache = NULL;
- ffd->properties_cache = NULL;
ffd->mergeinfo_cache = NULL;
ffd->mergeinfo_existence_cache = NULL;
}
+ /* if enabled, cache node properties */
+ if (cache_nodeprops)
+ {
+ SVN_ERR(create_cache(&(ffd->properties_cache),
+ NULL,
+ membuffer,
+ 0, 0, /* Do not use the inprocess cache */
+ svn_fs_fs__serialize_properties,
+ svn_fs_fs__deserialize_properties,
+ sizeof(pair_cache_key_t),
+ apr_pstrcat(pool, prefix, "PROP",
+ SVN_VA_NULL),
+ SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ has_namespace,
+ fs,
+ no_handler,
+ fs->pool, pool));
+ }
+ else
+ {
+ ffd->properties_cache = NULL;
+ }
+
/* if enabled, cache text deltas and their combinations */
if (cache_txdeltas)
{
@@ -830,27 +849,37 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
/* Transaction content needs to be carefully prefixed to virtually
eliminate any chance for conflicts. The (repo, txn_id) pair
- should be unique but if a transaction fails, it might be possible
- to start a new transaction later that receives the same id.
- Therefore, throw in a uuid as well - just to be sure. */
- prefix = apr_pstrcat(pool,
- "fsfs:", fs->uuid,
- "/", fs->path,
- ":", txn_id,
- ":", svn_uuid_generate(pool),
- ":", "TXNDIR",
- SVN_VA_NULL);
+ should be unique but if the filesystem format doesn't store the
+ global transaction ID via the txn-current file, and a transaction
+ fails, it might be possible to start a new transaction later that
+ receives the same id. For such older formats, throw in an uuid as
+ well -- just to be sure. */
+ if (ffd->format >= SVN_FS_FS__MIN_TXN_CURRENT_FORMAT)
+ prefix = apr_pstrcat(pool,
+ "fsfs:", fs->uuid,
+ "/", fs->path,
+ ":", txn_id,
+ ":", "TXNDIR",
+ SVN_VA_NULL);
+ else
+ prefix = apr_pstrcat(pool,
+ "fsfs:", fs->uuid,
+ "/", fs->path,
+ ":", txn_id,
+ ":", svn_uuid_generate(pool),
+ ":", "TXNDIR",
+ SVN_VA_NULL);
/* create a txn-local directory cache */
SVN_ERR(create_cache(&ffd->txn_dir_cache,
NULL,
svn_cache__get_global_membuffer_cache(),
1024, 8,
- svn_fs_fs__serialize_dir_entries,
+ svn_fs_fs__serialize_txndir_entries,
svn_fs_fs__deserialize_dir_entries,
APR_HASH_KEY_STRING,
prefix,
- 0,
+ SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
TRUE, /* The TXN-ID is our namespace. */
fs,
TRUE,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c Tue Oct 11 09:11:50 2016
@@ -753,8 +753,7 @@ svn_fs_fs__dag_clone_child(dag_node_t **
noderev->copyfrom_rev = SVN_INVALID_REVNUM;
noderev->predecessor_id = svn_fs_fs__id_copy(cur_entry->id, pool);
- if (noderev->predecessor_count != -1)
- noderev->predecessor_count++;
+ noderev->predecessor_count++;
noderev->created_path = svn_fspath__join(parent_path, name, pool);
SVN_ERR(svn_fs_fs__create_successor(&new_node_id, fs, cur_entry->id,
@@ -1267,8 +1266,7 @@ svn_fs_fs__dag_copy(dag_node_t *to_node,
/* Create a successor with its predecessor pointing at the copy
source. */
to_noderev->predecessor_id = svn_fs_fs__id_copy(src_id, pool);
- if (to_noderev->predecessor_count != -1)
- to_noderev->predecessor_count++;
+ to_noderev->predecessor_count++;
to_noderev->created_path =
svn_fspath__join(svn_fs_fs__dag_get_created_path(to_node), entry,
pool);
@@ -1423,8 +1421,7 @@ svn_fs_fs__dag_update_ancestry(dag_node_
target_noderev->predecessor_id = source->id;
target_noderev->predecessor_count = source_noderev->predecessor_count;
- if (target_noderev->predecessor_count != -1)
- target_noderev->predecessor_count++;
+ target_noderev->predecessor_count++;
return svn_fs_fs__put_node_revision(target->fs, target->id, target_noderev,
FALSE, pool);
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c Tue Oct 11 09:11:50 2016
@@ -292,6 +292,7 @@ initialize_fs_struct(svn_fs_t *fs)
fs_fs_data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
ffd->use_log_addressing = FALSE;
ffd->revprop_prefix = 0;
+ ffd->flush_to_disk = TRUE;
fs->vtable = &fs_vtable;
fs->fsap_data = ffd;
@@ -474,7 +475,7 @@ fs_pack(svn_fs_t *fs,
apr_pool_t *common_pool)
{
SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
- return svn_fs_fs__pack(fs, notify_func, notify_baton,
+ return svn_fs_fs__pack(fs, 0, notify_func, notify_baton,
cancel_func, cancel_baton, pool);
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h Tue Oct 11 09:11:50 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" {
@@ -193,6 +193,11 @@ extern "C" {
#define SVN_FS_FS__USE_LOCK_MUTEX 0
#endif
+/* Maximum number of changes we deliver per request when listing the
+ changed paths for a given revision. Anything > 0 will do.
+ At 100..300 bytes per entry, this limits the allocation to ~30kB. */
+#define SVN_FS_FS__CHANGES_BLOCK_SIZE 100
+
/* Private FSFS-specific data shared between all svn_txn_t objects that
relate to a particular transaction in a filesystem (as identified
by transaction id and filesystem UUID). Objects of this type are
@@ -383,8 +388,8 @@ typedef struct fs_fs_data_t
/* Cache for node_revision_t objects; the key is (revision, item_index) */
svn_cache__t *node_revision_cache;
- /* Cache for change lists as APR arrays of change_t * objects; the key
- is the revision */
+ /* Cache for change lists n blocks as svn_fs_fs__changes_list_t * objects;
+ the key is the (revision, first-element-in-block) pair. */
svn_cache__t *changes_cache;
/* Cache for svn_fs_fs__rep_header_t objects; the key is a
@@ -476,6 +481,9 @@ typedef struct fs_fs_data_t
or dump / load cycles). */
const char *instance_id;
+ /* Ensure that all filesystem changes are written to disk. */
+ svn_boolean_t flush_to_disk;
+
/* Pointer to svn_fs_open. */
svn_error_t *(*svn_fs_open_)(svn_fs_t **, const char *, apr_hash_t *,
apr_pool_t *, apr_pool_t *);
@@ -582,8 +590,8 @@ typedef struct node_revision_t
svn_revnum_t copyroot_rev;
const char *copyroot_path;
- /* number of predecessors this node revision has (recursively), or
- -1 if not known (for backward compatibility). */
+ /* Number of predecessors this node revision has (recursively).
+ A difference from the BDB backend is that it cannot be -1. */
int predecessor_count;
/* representation key for this node's properties. may be NULL if
@@ -621,6 +629,33 @@ typedef struct change_t
} change_t;
+/*** Context for reading changed paths lists iteratively. */
+typedef struct svn_fs_fs__changes_context_t
+{
+ /* Repository to fetch from. */
+ svn_fs_t *fs;
+
+ /* Revision that we read from. */
+ svn_revnum_t revision;
+
+ /* Revision file object to use when needed. NULL until the first access. */
+ svn_fs_fs__revision_file_t *revision_file;
+
+ /* Pool to create REVISION_FILE in. */
+ apr_pool_t *rev_file_pool;
+
+ /* Index of the next change to fetch. */
+ apr_size_t next;
+
+ /* Offset, within the changed paths list on disk, of the next change to
+ fetch. */
+ apr_off_t next_offset;
+
+ /* Has the end of the list been reached? */
+ svn_boolean_t eol;
+
+} svn_fs_fs__changes_context_t;
+
/*** Directory (only used at the cache interface) ***/
typedef struct svn_fs_fs__dir_data_t
{
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.c Tue Oct 11 09:11:50 2016
@@ -492,6 +492,7 @@ read_format(int *pformat,
svn_error_clear(err);
*pformat = 1;
*max_files_per_dir = 0;
+ *use_log_addressing = FALSE;
return SVN_NO_ERROR;
}
@@ -623,7 +624,8 @@ svn_fs_fs__write_format(svn_fs_t *fs,
else
{
SVN_ERR(svn_io_write_atomic2(path, sb->data, sb->len,
- NULL /* copy_perms_path */, TRUE, pool));
+ NULL /* copy_perms_path */,
+ ffd->flush_to_disk, pool));
}
/* And set the perms to make it read only */
@@ -1031,13 +1033,12 @@ read_global_config(svn_fs_t *fs)
{
fs_fs_data_t *ffd = fs->fsap_data;
- /* Providing a config hash is optional. */
- if (fs->config)
- ffd->use_block_read = svn_hash__get_bool(fs->config,
- SVN_FS_CONFIG_FSFS_BLOCK_READ,
- FALSE);
- else
- ffd->use_block_read = FALSE;
+ ffd->use_block_read = svn_hash__get_bool(fs->config,
+ SVN_FS_CONFIG_FSFS_BLOCK_READ,
+ FALSE);
+ ffd->flush_to_disk = !svn_hash__get_bool(fs->config,
+ SVN_FS_CONFIG_NO_FLUSH_TO_DISK,
+ FALSE);
/* Ignore the user-specified larger block size if we don't use block-read.
Defaulting to 4k gives us the same access granularity in format 7 as in
@@ -1868,7 +1869,7 @@ svn_fs_fs__set_uuid(svn_fs_t *fs,
file does not exist during repository creation. */
SVN_ERR(svn_io_write_atomic2(uuid_path, contents->data, contents->len,
svn_fs_fs__path_current(fs, pool) /* perms */,
- TRUE, pool));
+ ffd->flush_to_disk, pool));
fs->uuid = apr_pstrdup(fs->pool, uuid);
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.c Tue Oct 11 09:11:50 2016
@@ -795,7 +795,7 @@ struct hotcopy_body_baton {
* An incremental hotcopy copies only changed or new files to the destination,
* and removes files from the destination no longer present in the source.
* While the incremental hotcopy is running, readers should still be able
- * to access the destintation repository without error and should not see
+ * to access the destination repository without error and should not see
* revisions currently in progress of being copied. Readers are able to see
* new fully copied revisions even if the entire incremental hotcopy procedure
* has not yet completed.
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/id.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/id.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/id.c Tue Oct 11 09:11:50 2016
@@ -82,9 +82,11 @@ locale_independent_strtol(long *result_p
next = result * 10 + c;
- /* Overflow check. In case of an overflow, NEXT is 0..9.
- * In the non-overflow case, RESULT is either >= 10 or RESULT and NEXT
- * are both 0. */
+ /* Overflow check. In case of an overflow, NEXT is 0..9 and RESULT
+ * is much larger than 10. We will then return FALSE.
+ *
+ * In the non-overflow case, NEXT is >= 10 * RESULT but never smaller.
+ * We will continue the loop in that case. */
if (next < result)
return FALSE;
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.c Tue Oct 11 09:11:50 2016
@@ -482,10 +482,10 @@ read_change(change_t **change_p,
svn_error_t *
svn_fs_fs__read_changes(apr_array_header_t **changes,
svn_stream_t *stream,
+ int max_count,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- change_t *change;
apr_pool_t *iterpool;
/* Pre-allocate enough room for most change lists.
@@ -498,13 +498,16 @@ svn_fs_fs__read_changes(apr_array_header
*/
*changes = apr_array_make(result_pool, 63, sizeof(change_t *));
- SVN_ERR(read_change(&change, stream, result_pool, scratch_pool));
iterpool = svn_pool_create(scratch_pool);
- while (change)
+ for (; max_count > 0; --max_count)
{
- APR_ARRAY_PUSH(*changes, change_t*) = change;
- SVN_ERR(read_change(&change, stream, result_pool, iterpool));
+ change_t *change;
svn_pool_clear(iterpool);
+ SVN_ERR(read_change(&change, stream, result_pool, iterpool));
+ if (!change)
+ break;
+
+ APR_ARRAY_PUSH(*changes, change_t*) = change;
}
svn_pool_destroy(iterpool);
@@ -797,7 +800,11 @@ svn_fs_fs__parse_representation(represen
SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, str,
scratch_pool));
- memcpy(rep->md5_digest, checksum->digest, sizeof(rep->md5_digest));
+
+ /* If STR is a all-zero checksum, CHECKSUM will be NULL and REP already
+ contains the correct value. */
+ if (checksum)
+ memcpy(rep->md5_digest, checksum->digest, sizeof(rep->md5_digest));
/* The remaining fields are only used for formats >= 4, so check that. */
str = svn_cstring_tokenize(" ", &string);
@@ -811,8 +818,16 @@ svn_fs_fs__parse_representation(represen
SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, str,
scratch_pool));
+
+ /* We do have a valid SHA1 but it might be all 0.
+ We cannot be sure where that came from (Alas! legacy), so let's not
+ claim we know the SHA1 in that case. */
rep->has_sha1 = checksum != NULL;
- memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest));
+
+ /* If STR is a all-zero checksum, CHECKSUM will be NULL and REP already
+ contains the correct value. */
+ if (checksum)
+ memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest));
/* Read the uniquifier. */
str = svn_cstring_tokenize("/", &string);
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.h Tue Oct 11 09:11:50 2016
@@ -97,11 +97,13 @@ svn_fs_fs__unparse_footer(apr_off_t l2p_
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-/* Read all the changes from STREAM and store them in *CHANGES,
- allocated in RESULT_POOL. Do temporary allocations in SCRATCH_POOL. */
+/* Read up to MAX_COUNT of the changes from STREAM and store them in
+ *CHANGES, allocated in RESULT_POOL. Do temporary allocations in
+ SCRATCH_POOL. */
svn_error_t *
svn_fs_fs__read_changes(apr_array_header_t **changes,
svn_stream_t *stream,
+ int max_count,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);