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 2018/11/07 12:30:11 UTC
svn commit: r1846002 [12/44] - in /subversion/branches/ra-git: ./ build/
build/ac-macros/ build/generator/ build/generator/swig/
build/generator/templates/ build/generator/util/ build/win32/
contrib/client-side/ contrib/client-side/svn_load_dirs/ contr...
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.c Wed Nov 7 12:30:06 2018
@@ -29,6 +29,7 @@
#include "svn_dirent_uri.h"
#include "svn_private_config.h"
+#include "private/svn_atomic.h"
#include "private/svn_dep_compat.h"
#include "private/svn_mutex.h"
#include "private/svn_subr_private.h"
@@ -230,28 +231,38 @@ static apr_thread_pool_t *thread_pool =
#endif
+/* Keep track on whether we already created the THREAD_POOL . */
+static svn_atomic_t thread_pool_initialized = FALSE;
+
/* We open non-directory files with these flags. */
#define FILE_FLAGS (APR_READ | APR_WRITE | APR_BUFFERED | APR_CREATE)
#if APR_HAS_THREADS
/* Destructor function that implicitly cleans up any running threads
- in the thread_pool given as DATA and releases their memory pools
- before they get destroyed themselves.
+ in the TRHEAD_POOL *once*.
Must be run as a pre-cleanup hook.
*/
static apr_status_t
thread_pool_pre_cleanup(void *data)
{
- apr_thread_pool_t *tp = data;
+ apr_thread_pool_t *tp = thread_pool;
+ if (!thread_pool)
+ return APR_SUCCESS;
+
+ thread_pool = NULL;
+ thread_pool_initialized = FALSE;
+
return apr_thread_pool_destroy(tp);
}
#endif
-svn_error_t *
-svn_fs_x__batch_fsync_init(void)
+/* Core implementation of svn_fs_x__batch_fsync_init. */
+static svn_error_t *
+create_thread_pool(void *baton,
+ apr_pool_t *owning_pool)
{
#if APR_HAS_THREADS
/* The thread-pool must be allocated from a thread-safe pool.
@@ -266,7 +277,8 @@ svn_fs_x__batch_fsync_init(void)
/* Work around an APR bug: The cleanup must happen in the pre-cleanup
hook instead of the normal cleanup hook. Otherwise, the sub-pools
containing the thread objects would already be invalid. */
- apr_pool_pre_cleanup_register(pool, thread_pool, thread_pool_pre_cleanup);
+ apr_pool_pre_cleanup_register(pool, NULL, thread_pool_pre_cleanup);
+ apr_pool_pre_cleanup_register(owning_pool, NULL, thread_pool_pre_cleanup);
/* let idle threads linger for a while in case more requests are
coming in */
@@ -280,6 +292,15 @@ svn_fs_x__batch_fsync_init(void)
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_x__batch_fsync_init(apr_pool_t *owning_pool)
+{
+ /* Protect against multiple calls. */
+ return svn_error_trace(svn_atomic__init_once(&thread_pool_initialized,
+ create_thread_pool,
+ NULL, owning_pool));
+}
+
/* Destructor for svn_fs_x__batch_fsync_t. Releases all global pool memory
* and closes all open file handles. */
static apr_status_t
@@ -510,6 +531,10 @@ svn_fs_x__batch_fsync_run(svn_fs_x__batc
#if APR_HAS_THREADS
+ /* Forgot to call _init() or cleaned up the owning pool too early?
+ */
+ SVN_ERR_ASSERT(thread_pool);
+
/* If there are multiple fsyncs to perform, run them in parallel.
* Otherwise, skip the thread-pool and synchronization overhead. */
if (apr_hash_count(batch->files) > 1)
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.h Wed Nov 7 12:30:06 2018
@@ -44,13 +44,14 @@
*/
typedef struct svn_fs_x__batch_fsync_t svn_fs_x__batch_fsync_t;
-/* Initialize the concurrent fsync infrastructure.
+/* Initialize the concurrent fsync infrastructure. Clean it up when
+ * OWNING_POOL gets cleared.
*
* This function must be called before using any of the other functions in
* in this module. It should only be called once.
*/
svn_error_t *
-svn_fs_x__batch_fsync_init(void);
+svn_fs_x__batch_fsync_init(apr_pool_t *owning_pool);
/* Set *RESULT_P to a new batch fsync structure, allocated in RESULT_POOL.
* If FLUSH_TO_DISK is not set, the resulting struct will not actually use
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.c Wed Nov 7 12:30:06 2018
@@ -69,7 +69,7 @@ block_read(void **result,
* contents if not NULL. Use SCRATCH_POOL for temporary allocations.
*/
static svn_error_t *
-dgb__log_access(svn_fs_t *fs,
+dbg__log_access(svn_fs_t *fs,
const svn_fs_x__id_t *id,
void *item,
apr_uint32_t item_type,
@@ -379,7 +379,7 @@ svn_fs_x__get_node_revision(svn_fs_x__no
id_string->data);
}
- SVN_ERR(dgb__log_access(fs, id, *noderev_p,
+ SVN_ERR(dbg__log_access(fs, id, *noderev_p,
SVN_FS_X__ITEM_TYPE_NODEREV, scratch_pool));
return svn_error_trace(err);
@@ -708,7 +708,7 @@ create_rep_state_body(rep_state_t **rep_
}
/* finalize */
- SVN_ERR(dgb__log_access(fs, &rs->rep_id, rh, SVN_FS_X__ITEM_TYPE_ANY_REP,
+ SVN_ERR(dbg__log_access(fs, &rs->rep_id, rh, SVN_FS_X__ITEM_TYPE_ANY_REP,
scratch_pool));
rs->header_size = rh->header_size;
@@ -1187,7 +1187,8 @@ build_rep_list(apr_array_header_t **list
/* for txn reps and containered reps, there won't be a cached
* combined window */
if (svn_fs_x__is_revision(rep.id.change_set)
- && rep_header->type != svn_fs_x__rep_container)
+ && rep_header->type != svn_fs_x__rep_container
+ && rs->combined_cache)
SVN_ERR(get_cached_combined_window(window_p, rs, &is_cached,
result_pool));
@@ -1289,17 +1290,23 @@ read_delta_window(svn_txdelta_window_t *
apr_pool_t *iterpool;
svn_stream_t *stream;
svn_fs_x__revision_file_t *file;
+ svn_boolean_t cacheable = rs->chunk_index == 0
+ && svn_fs_x__is_revision(rs->rep_id.change_set)
+ && rs->window_cache;
SVN_ERR_ASSERT(rs->chunk_index <= this_chunk);
- SVN_ERR(dgb__log_access(rs->sfile->fs, &rs->rep_id, NULL,
+ SVN_ERR(dbg__log_access(rs->sfile->fs, &rs->rep_id, NULL,
SVN_FS_X__ITEM_TYPE_ANY_REP, scratch_pool));
/* Read the next window. But first, try to find it in the cache. */
- SVN_ERR(get_cached_window(nwin, rs, this_chunk, &is_cached,
- result_pool, scratch_pool));
- if (is_cached)
- return SVN_NO_ERROR;
+ if (cacheable)
+ {
+ SVN_ERR(get_cached_window(nwin, rs, this_chunk, &is_cached,
+ result_pool, scratch_pool));
+ if (is_cached)
+ return SVN_NO_ERROR;
+ }
/* someone has to actually read the data from file. Open it */
SVN_ERR(auto_open_shared_file(rs->sfile));
@@ -1308,9 +1315,7 @@ read_delta_window(svn_txdelta_window_t *
/* invoke the 'block-read' feature for non-txn data.
However, don't do that if we are in the middle of some representation,
because the block is unlikely to contain other data. */
- if ( rs->chunk_index == 0
- && svn_fs_x__is_revision(rs->rep_id.change_set)
- && rs->window_cache)
+ if (cacheable)
{
SVN_ERR(block_read(NULL, rs->sfile->fs, &rs->rep_id, file, NULL,
result_pool, scratch_pool));
@@ -1367,7 +1372,7 @@ read_delta_window(svn_txdelta_window_t *
/* the window has not been cached before, thus cache it now
* (if caching is used for them at all) */
- if (svn_fs_x__is_revision(rs->rep_id.change_set))
+ if (cacheable)
SVN_ERR(set_cached_window(*nwin, rs, start_offset, scratch_pool));
return SVN_NO_ERROR;
@@ -1495,7 +1500,8 @@ get_combined_window(svn_stringbuf_t **re
single chunk. Only then will no other chunk need a deeper RS
list than the cached chunk. */
if ( (rb->chunk_index == 0) && (rs->current == rs->size)
- && svn_fs_x__is_revision(rs->rep_id.change_set))
+ && svn_fs_x__is_revision(rs->rep_id.change_set)
+ && rs->combined_cache)
SVN_ERR(set_cached_combined_window(buf, rs, new_pool));
rs->chunk_index++;
@@ -1974,6 +1980,16 @@ skip_contents(rep_read_baton_t *baton,
len -= to_read;
buffer += to_read;
}
+
+ /* Make the MD5 calculation catch up with the data delivered
+ * (we did not run MD5 on the data that we took from the cache). */
+ if (!err)
+ {
+ SVN_ERR(svn_checksum_update(baton->md5_checksum_ctx,
+ baton->current_fulltext->data,
+ baton->current_fulltext->len));
+ baton->off += baton->current_fulltext->len;
+ }
}
else if (len > 0)
{
@@ -1989,6 +2005,15 @@ skip_contents(rep_read_baton_t *baton,
err = get_contents_from_windows(baton, buffer, &to_read);
len -= to_read;
+
+ /* Make the MD5 calculation catch up with the data delivered
+ * (we did not run MD5 on the data that we took from the cache). */
+ if (!err)
+ {
+ SVN_ERR(svn_checksum_update(baton->md5_checksum_ctx,
+ buffer, to_read));
+ baton->off += to_read;
+ }
}
svn_pool_destroy(subpool);
@@ -2034,8 +2059,13 @@ rep_read_contents(void *baton,
SVN_ERR(skip_contents(rb, rb->fulltext_delivered));
}
- /* Get the next block of data. */
- SVN_ERR(get_contents_from_windows(rb, buf, len));
+ /* Get the next block of data.
+ * Keep in mind that the representation might be empty and leave us
+ * already positioned at the end of the rep. */
+ if (rb->off == rb->len)
+ *len = 0;
+ else
+ SVN_ERR(get_contents_from_windows(rb, buf, len));
if (rb->current_fulltext)
svn_stringbuf_appendbytes(rb->current_fulltext, buf, *len);
@@ -2130,6 +2160,86 @@ svn_fs_x__get_contents(svn_stream_t **co
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_x__get_contents_from_file(svn_stream_t **contents_p,
+ svn_fs_t *fs,
+ svn_fs_x__representation_t *rep,
+ apr_file_t *file,
+ apr_off_t offset,
+ apr_pool_t *pool)
+{
+ rep_read_baton_t *rb;
+ svn_fs_x__pair_cache_key_t fulltext_cache_key = { SVN_INVALID_REVNUM, 0 };
+ rep_state_t *rs = apr_pcalloc(pool, sizeof(*rs));
+ svn_fs_x__rep_header_t *rh;
+ svn_stream_t *stream;
+
+ /* Initialize the reader baton. Some members may added lazily
+ * while reading from the stream. */
+ SVN_ERR(rep_read_get_baton(&rb, fs, rep, fulltext_cache_key, pool));
+
+ /* Continue constructing RS. Leave caches as NULL. */
+ rs->size = rep->size;
+ rs->rep_id = rep->id;
+ rs->ver = -1;
+ rs->start = -1;
+
+ /* Provide just enough file access info to allow for a basic read from
+ * FILE but leave all index / footer info with empty values b/c FILE
+ * probably is not a complete revision file. */
+ rs->sfile = apr_pcalloc(pool, sizeof(*rs->sfile));
+ rs->sfile->revision = SVN_INVALID_REVNUM;
+ rs->sfile->pool = pool;
+ rs->sfile->fs = fs;
+ SVN_ERR(svn_fs_x__rev_file_wrap_temp(&rs->sfile->rfile, fs, file, pool));
+
+ /* Read the rep header. */
+ SVN_ERR(svn_fs_x__rev_file_seek(rs->sfile->rfile, NULL, offset));
+ SVN_ERR(svn_fs_x__rev_file_stream(&stream, rs->sfile->rfile));
+ SVN_ERR(svn_fs_x__read_rep_header(&rh, stream, pool, pool));
+ SVN_ERR(svn_fs_x__rev_file_offset(&rs->start, rs->sfile->rfile));
+ rs->header_size = rh->header_size;
+
+ /* Log the access. */
+ SVN_ERR(dbg__log_access(fs, &rep->id, rh,
+ SVN_FS_X__ITEM_TYPE_ANY_REP, pool));
+
+ /* Build the representation list (delta chain). */
+ if (rh->type == svn_fs_x__rep_self_delta)
+ {
+ rb->rs_list = apr_array_make(pool, 1, sizeof(rep_state_t *));
+ APR_ARRAY_PUSH(rb->rs_list, rep_state_t *) = rs;
+ rb->src_state = NULL;
+ }
+ else
+ {
+ svn_fs_x__representation_t next_rep = { 0 };
+
+ /* skip "SVNx" diff marker */
+ rs->current = 4;
+
+ /* REP's base rep is inside a proper revision.
+ * It can be reconstructed in the usual way. */
+ next_rep.id.change_set = svn_fs_x__change_set_by_rev(rh->base_revision);
+ next_rep.id.number = rh->base_item_index;
+ next_rep.size = rh->base_length;
+
+ SVN_ERR(build_rep_list(&rb->rs_list, &rb->base_window,
+ &rb->src_state, rb->fs, &next_rep,
+ rb->filehandle_pool, rb->scratch_pool));
+
+ /* Insert the access to REP as the first element of the delta chain. */
+ svn_sort__array_insert(rb->rs_list, &rs, 0);
+ }
+
+ /* Now, the baton is complete and we can assemble the stream around it. */
+ *contents_p = svn_stream_create(rb, pool);
+ svn_stream_set_read2(*contents_p, NULL /* only full read support */,
+ rep_read_contents);
+ svn_stream_set_close(*contents_p, rep_read_contents_close);
+
+ return SVN_NO_ERROR;
+}
/* Baton for cache_access_wrapper. Wraps the original parameters of
* svn_fs_x__try_process_file_content().
@@ -2893,7 +3003,7 @@ svn_fs_x__get_changes(apr_array_header_t
context->next += (*changes)->nelts;
- SVN_ERR(dgb__log_access(context->fs, &id, *changes,
+ SVN_ERR(dbg__log_access(context->fs, &id, *changes,
SVN_FS_X__ITEM_TYPE_CHANGES, scratch_pool));
return SVN_NO_ERROR;
@@ -2972,8 +3082,8 @@ read_item(svn_stream_t **stream,
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(result_pool, "%" APR_OFF_T_FMT, entry->size),
- apr_psprintf(result_pool, "%" APR_OFF_T_FMT, entry->offset));
+ apr_off_t_toa(result_pool, entry->size),
+ apr_off_t_toa(result_pool, entry->offset));
}
/* If not already cached or if MUST_READ is set, read the changed paths
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.h Wed Nov 7 12:30:06 2018
@@ -67,7 +67,7 @@ svn_fs_x__rep_chain_length(int *chain_le
svn_fs_t *fs,
apr_pool_t *scratch_pool);
-/* Set *CONTENTS to be a readable svn_stream_t that receives the text
+/* Set *CONTENTS_P to be a readable svn_stream_t that receives the text
representation REP as seen in filesystem FS. If CACHE_FULLTEXT is
not set, bypass fulltext cache lookup for this rep and don't put the
reconstructed fulltext into cache.
@@ -79,6 +79,18 @@ svn_fs_x__get_contents(svn_stream_t **co
svn_boolean_t cache_fulltext,
apr_pool_t *result_pool);
+/* Set *CONTENTS_P to be a readable svn_stream_t that receives the text
+ representation REP as seen in filesystem FS. Read the latest element
+ of the delta chain from FILE at offset OFFSET.
+ Use POOL for allocations. */
+svn_error_t *
+svn_fs_x__get_contents_from_file(svn_stream_t **contents_p,
+ svn_fs_t *fs,
+ svn_fs_x__representation_t *rep,
+ apr_file_t *file,
+ apr_off_t offset,
+ apr_pool_t *pool);
+
/* Determine on-disk and expanded sizes of the representation identified
* by ENTRY in FS and return the result in PACKED_LEN and EXPANDED_LEN,
* respectively. FILE must point to the start of the representation and
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/caching.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/caching.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/caching.c Wed Nov 7 12:30:06 2018
@@ -412,7 +412,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs
/* General rules for assigning cache priorities:
*
* - Data that can be reconstructed from other elements has low prio
- * (e.g. fulltexts, directories etc.)
+ * (e.g. fulltexts etc.)
* - Index data required to find any of the other data has high prio
* (e.g. noderevs, L2P and P2L index pages)
* - everthing else should use default prio
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/changes.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/changes.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/changes.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/changes.c Wed Nov 7 12:30:06 2018
@@ -184,7 +184,7 @@ svn_fs_x__changes_append_list(apr_size_t
/* simply append the list and all changes */
for (i = 0; i < list->nelts; ++i)
- append_change(changes, APR_ARRAY_IDX(list, i, svn_fs_x__change_t *));
+ SVN_ERR(append_change(changes, APR_ARRAY_IDX(list, i, svn_fs_x__change_t *)));
/* terminate the list by storing the next changes offset */
APR_ARRAY_PUSH(changes->offsets, int) = changes->changes->nelts;
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/dag_cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/dag_cache.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/dag_cache.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/dag_cache.c Wed Nov 7 12:30:06 2018
@@ -890,6 +890,16 @@ svn_fs_x__get_dag_path(svn_fs_x__dag_pat
{
svn_pool_clear(iterpool);
+ /* If the current node is not a directory and we are just here to
+ * check for the path's existence, then that's o.k.
+ * Otherwise, non-dir nodes will cause an error in dag_step. */
+ if ( (flags & svn_fs_x__dag_path_allow_null)
+ && (svn_fs_x__dag_node_kind(dag_path->node) != svn_node_dir))
+ {
+ dag_path = NULL;
+ break;
+ }
+
/* Find the sub-node. */
SVN_ERR(dag_step(&here, root, dag_path->node, entry, &path, change_set,
TRUE, iterpool));
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c Wed Nov 7 12:30:06 2018
@@ -508,7 +508,7 @@ x_pack(svn_fs_t *fs,
apr_pool_t *common_pool)
{
SVN_ERR(x_open(fs, path, common_pool_lock, scratch_pool, common_pool));
- return svn_fs_x__pack(fs, notify_func, notify_baton,
+ return svn_fs_x__pack(fs, 0, notify_func, notify_baton,
cancel_func, cancel_baton, scratch_pool);
}
@@ -665,7 +665,7 @@ svn_fs_x__init(const svn_version_t *load
loader_version->major);
SVN_ERR(svn_ver_check_list2(x_version(), checklist, svn_ver_equal));
- SVN_ERR(svn_fs_x__batch_fsync_init());
+ SVN_ERR(svn_fs_x__batch_fsync_init(common_pool));
*vtable = &library_vtable;
return SVN_NO_ERROR;
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c Wed Nov 7 12:30:06 2018
@@ -1131,7 +1131,7 @@ svn_fs_x__write_changes(svn_stream_t *st
}
if (terminate_list)
- svn_stream_puts(stream, "\n");
+ SVN_ERR(svn_stream_puts(stream, "\n"));
svn_pool_destroy(iterpool);
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c Wed Nov 7 12:30:06 2018
@@ -216,7 +216,7 @@ typedef struct pack_context_t
* to NULL that we already processed. */
apr_array_header_t *reps;
- /* array of int, marking for each revision, the which offset their items
+ /* array of int, marking for each revision, at which offset their items
* begin in REPS. Will be filled in phase 2 and be cleared after
* each revision range. */
apr_array_header_t *rev_offsets;
@@ -344,6 +344,7 @@ reset_pack_context(pack_context_t *conte
SVN_ERR(svn_io_file_trunc(context->reps_file, 0, scratch_pool));
svn_pool_clear(context->info_pool);
+ context->paths = svn_prefix_tree__create(context->info_pool);
return SVN_NO_ERROR;
}
@@ -1839,15 +1840,17 @@ append_revision(pack_context_t *context,
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_fs_x__revision_file_t *rev_file;
apr_file_t *file;
- svn_filesize_t revfile_size;
+ svn_filesize_t revdata_size;
- /* Copy all the bits from the rev file to the end of the pack file. */
+ /* Copy all non-index contents the rev file to the end of the pack file. */
SVN_ERR(svn_fs_x__rev_file_init(&rev_file, context->fs, context->start_rev,
scratch_pool));
- SVN_ERR(svn_fs_x__rev_file_get(&file, rev_file));
+ SVN_ERR(svn_fs_x__rev_file_data_size(&revdata_size, rev_file));
- SVN_ERR(svn_io_file_size_get(&revfile_size, file, scratch_pool));
- SVN_ERR(copy_file_data(context, context->pack_file, file, revfile_size,
+ SVN_ERR(svn_fs_x__rev_file_get(&file, rev_file));
+ SVN_ERR(svn_io_file_aligned_seek(file, ffd->block_size, NULL, 0,
+ iterpool));
+ SVN_ERR(copy_file_data(context, context->pack_file, file, revdata_size,
iterpool));
/* mark the start of a new revision */
@@ -1856,7 +1859,7 @@ append_revision(pack_context_t *context,
/* read the phys-to-log index file until we covered the whole rev file.
* That index contains enough info to build both target indexes from it. */
- while (offset < revfile_size)
+ while (offset < revdata_size)
{
/* read one cluster */
int i;
@@ -1878,7 +1881,7 @@ append_revision(pack_context_t *context,
/* process entry while inside the rev file */
offset = entry->offset;
- if (offset < revfile_size)
+ if (offset < revdata_size)
{
/* there should be true containers */
SVN_ERR_ASSERT(entry->item_count == 1);
@@ -1897,7 +1900,7 @@ append_revision(pack_context_t *context,
}
svn_pool_destroy(iterpool);
- context->pack_offset += revfile_size;
+ context->pack_offset += revdata_size;
return SVN_NO_ERROR;
}
@@ -1956,6 +1959,7 @@ pack_log_addressed(svn_fs_t *fs,
if ( APR_ARRAY_IDX(max_ids, i, apr_uint64_t)
<= (apr_uint64_t)max_items - item_count)
{
+ item_count += APR_ARRAY_IDX(max_ids, i, apr_uint64_t);
context.end_rev++;
}
else
@@ -2048,6 +2052,7 @@ pack_rev_shard(svn_fs_t *fs,
/* In the file system at FS_PATH, pack the SHARD in DIR containing exactly
* MAX_FILES_PER_DIR revisions, using SCRATCH_POOL temporary for allocations.
* COMPRESSION_LEVEL and MAX_PACK_SIZE will be ignored in that case.
+ * An attempt will be made to keep memory usage below MAX_MEM.
*
* CANCEL_FUNC and CANCEL_BATON are what you think they are; similarly
* NOTIFY_FUNC and NOTIFY_BATON.
@@ -2062,6 +2067,7 @@ pack_shard(const char *dir,
int max_files_per_dir,
apr_off_t max_pack_size,
int compression_level,
+ apr_size_t max_mem,
svn_fs_pack_notify_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
@@ -2093,7 +2099,7 @@ pack_shard(const char *dir,
/* pack the revision content */
SVN_ERR(pack_rev_shard(fs, pack_file_dir, shard_path,
- shard, max_files_per_dir, DEFAULT_MAX_MEM, batch,
+ shard, max_files_per_dir, max_mem, batch,
cancel_func, cancel_baton, scratch_pool));
/* pack the revprops in an equivalent way */
@@ -2158,6 +2164,7 @@ get_pack_status(svn_boolean_t *fully_pac
typedef struct pack_baton_t
{
svn_fs_t *fs;
+ apr_size_t max_mem;
svn_fs_pack_notify_t notify_func;
void *notify_baton;
svn_cancel_func_t cancel_func;
@@ -2197,9 +2204,9 @@ pack_body(void *baton,
if (fully_packed)
{
if (pb->notify_func)
- (*pb->notify_func)(pb->notify_baton,
- ffd->min_unpacked_rev / ffd->max_files_per_dir,
- svn_fs_pack_notify_noop, scratch_pool);
+ SVN_ERR(pb->notify_func(pb->notify_baton,
+ ffd->min_unpacked_rev / ffd->max_files_per_dir,
+ svn_fs_pack_notify_noop, scratch_pool));
return SVN_NO_ERROR;
}
@@ -2223,6 +2230,7 @@ pack_body(void *baton,
ffd->compress_packed_revprops
? SVN__COMPRESSION_ZLIB_DEFAULT
: SVN__COMPRESSION_NONE,
+ pb->max_mem,
pb->notify_func, pb->notify_baton,
pb->cancel_func, pb->cancel_baton, iterpool));
}
@@ -2233,6 +2241,7 @@ pack_body(void *baton,
svn_error_t *
svn_fs_x__pack(svn_fs_t *fs,
+ apr_size_t max_mem,
svn_fs_pack_notify_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
@@ -2249,9 +2258,9 @@ svn_fs_x__pack(svn_fs_t *fs,
svn_fs_x__data_t *ffd = fs->fsap_data;
if (notify_func)
- (*notify_func)(notify_baton,
- ffd->min_unpacked_rev / ffd->max_files_per_dir,
- svn_fs_pack_notify_noop, scratch_pool);
+ SVN_ERR(notify_func(notify_baton,
+ ffd->min_unpacked_rev / ffd->max_files_per_dir,
+ svn_fs_pack_notify_noop, scratch_pool));
return SVN_NO_ERROR;
}
@@ -2262,5 +2271,7 @@ svn_fs_x__pack(svn_fs_t *fs,
pb.notify_baton = notify_baton;
pb.cancel_func = cancel_func;
pb.cancel_baton = cancel_baton;
+ pb.max_mem = max_mem ? max_mem : DEFAULT_MAX_MEM;
+
return svn_fs_x__with_pack_lock(fs, pack_body, &pb, scratch_pool);
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/pack.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/pack.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/pack.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/pack.h Wed Nov 7 12:30:06 2018
@@ -26,13 +26,19 @@
#include "fs.h"
/* Possibly pack the repository at PATH. This just take full shards, and
- combines all the revision files into a single one, with a manifest header.
+ combines all the revision files into a single one, with a manifest header
+ when required by the repository format.
+
+ MAX_MEM limits the size of in-memory data structures needed for reordering
+ items. 0 means use the built-in default.
+
Use optional CANCEL_FUNC/CANCEL_BATON for cancellation support.
Use SCRATCH_POOL for temporary allocations.
Existing filesystem references need not change. */
svn_error_t *
svn_fs_x__pack(svn_fs_t *fs,
+ apr_size_t max_mem,
svn_fs_pack_notify_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c Wed Nov 7 12:30:06 2018
@@ -126,7 +126,11 @@ svn_fs_x__open_rep_cache(svn_fs_t *fs,
svn_fs_x__data_t *ffd = fs->fsap_data;
svn_error_t *err = svn_atomic__init_once(&ffd->rep_cache_db_opened,
open_rep_cache, fs, scratch_pool);
- return svn_error_quick_wrap(err, _("Couldn't open rep-cache database"));
+ return svn_error_quick_wrapf(err,
+ _("Couldn't open rep-cache database '%s'"),
+ svn_dirent_local_style(
+ path_rep_cache_db(fs->path, scratch_pool),
+ scratch_pool));
}
svn_error_t *
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c Wed Nov 7 12:30:06 2018
@@ -474,6 +474,16 @@ svn_fs_x__rev_file_p2l_info(svn_fs_x__in
}
svn_error_t *
+svn_fs_x__rev_file_data_size(svn_filesize_t *size,
+ svn_fs_x__revision_file_t *file)
+{
+ SVN_ERR(auto_read_footer(file));
+ *size = file->l2p_info.start;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_fs_x__rev_file_seek(svn_fs_x__revision_file_t *file,
apr_off_t *buffer_start,
apr_off_t offset)
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.h Wed Nov 7 12:30:06 2018
@@ -166,6 +166,12 @@ svn_error_t *
svn_fs_x__rev_file_p2l_info(svn_fs_x__index_info_t *info,
svn_fs_x__revision_file_t *file);
+/* Set *SIZE to the length of the revision data in FILE.
+ */
+svn_error_t *
+svn_fs_x__rev_file_data_size(svn_filesize_t *size,
+ svn_fs_x__revision_file_t *file);
+
/* File manipulation. */
/* Convenience wrapper around svn_io_file_aligned_seek. */
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c Wed Nov 7 12:30:06 2018
@@ -721,7 +721,8 @@ get_writable_proto_rev(apr_file_t **file
/* Now open the prototype revision file and seek to the end. */
err = svn_io_file_open(file,
svn_fs_x__path_txn_proto_rev(fs, txn_id, pool),
- APR_WRITE | APR_BUFFERED, APR_OS_DEFAULT, pool);
+ APR_READ | APR_WRITE | APR_BUFFERED, APR_OS_DEFAULT,
+ pool);
/* You might expect that we could dispense with the following seek
and achieve the same thing by opening the file using APR_APPEND.
@@ -1258,7 +1259,7 @@ get_and_increment_txn_key_body(void *bat
SVN_ERR(svn_io_check_path(txn_dir, &kind, iterpool));
if (kind == svn_node_none)
{
- svn_io_dir_make(txn_dir, APR_OS_DEFAULT, iterpool);
+ SVN_ERR(svn_io_dir_make(txn_dir, APR_OS_DEFAULT, iterpool));
break;
}
@@ -1538,7 +1539,7 @@ store_l2p_index_entry(svn_fs_t *fs,
static svn_error_t *
store_p2l_index_entry(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
- svn_fs_x__p2l_entry_t *entry,
+ const svn_fs_x__p2l_entry_t *entry,
apr_pool_t *scratch_pool)
{
const char *path = svn_fs_x__path_p2l_proto_index(fs, txn_id, scratch_pool);
@@ -2329,13 +2330,21 @@ rep_write_get_baton(rep_write_baton_t **
there may be new duplicate representations within the same uncommitted
revision, those can be passed in REPS_HASH (maps a sha1 digest onto
svn_fs_x__representation_t*), otherwise pass in NULL for REPS_HASH.
+
+ The content of both representations will be compared, taking REP's content
+ from FILE at OFFSET. Only if they actually match, will *OLD_REP not be
+ NULL.
+
Use RESULT_POOL for *OLD_REP allocations and SCRATCH_POOL for temporaries.
The lifetime of *OLD_REP is limited by both, RESULT_POOL and REP lifetime.
*/
static svn_error_t *
get_shared_rep(svn_fs_x__representation_t **old_rep,
svn_fs_t *fs,
+ svn_fs_x__txn_id_t txn_id,
svn_fs_x__representation_t *rep,
+ apr_file_t *file,
+ apr_off_t offset,
apr_hash_t *reps_hash,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -2343,6 +2352,10 @@ get_shared_rep(svn_fs_x__representation_
svn_error_t *err;
svn_fs_x__data_t *ffd = fs->fsap_data;
+ svn_checksum_t checksum;
+ checksum.digest = rep->sha1_digest;
+ checksum.kind = svn_checksum_sha1;
+
/* Return NULL, if rep sharing has been disabled. */
*old_rep = NULL;
if (!ffd->rep_sharing_allowed)
@@ -2363,9 +2376,6 @@ get_shared_rep(svn_fs_x__representation_
/* If we haven't found anything yet, try harder and consult our DB. */
if (*old_rep == NULL)
{
- svn_checksum_t checksum;
- checksum.digest = rep->sha1_digest;
- checksum.kind = svn_checksum_sha1;
err = svn_fs_x__get_rep_reference(old_rep, fs, &checksum, result_pool,
scratch_pool);
@@ -2435,10 +2445,6 @@ get_shared_rep(svn_fs_x__representation_
Because not sharing reps is always a safe option,
terminating the request would be inappropriate.
*/
- svn_checksum_t checksum;
- checksum.digest = rep->sha1_digest;
- checksum.kind = svn_checksum_sha1;
-
err = svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
"Rep size %s mismatches rep-cache.db value %s "
"for SHA1 %s.\n"
@@ -2467,6 +2473,81 @@ get_shared_rep(svn_fs_x__representation_
memcpy((*old_rep)->md5_digest, rep->md5_digest, sizeof(rep->md5_digest));
}
+ /* If we (very likely) found a matching representation, compare the actual
+ * contents such that we can be sure that no rep-cache.db corruption or
+ * hash collision produced a false positive. */
+ if (*old_rep)
+ {
+ apr_off_t old_position;
+ svn_stream_t *contents;
+ svn_stream_t *old_contents;
+ svn_boolean_t same;
+
+ /* Make sure we can later restore FILE's current position. */
+ SVN_ERR(svn_io_file_get_offset(&old_position, file, scratch_pool));
+
+ /* Compare the two representations.
+ * Note that the stream comparison might also produce MD5 checksum
+ * errors or other failures in case of SHA1 collisions. */
+ SVN_ERR(svn_fs_x__get_contents_from_file(&contents, fs, rep, file,
+ offset, scratch_pool));
+ if ((*old_rep)->id.change_set == rep->id.change_set)
+ {
+ /* Comparing with contents from the same transaction means
+ * reading the same prote-rev FILE. In the commit stage,
+ * the file will already have been moved and the IDs already
+ * bumped to the final revision. Hence, we must determine
+ * the OFFSET "manually". */
+ svn_fs_x__revision_file_t *rev_file;
+ apr_uint32_t sub_item = 0;
+ svn_fs_x__id_t id;
+ id.change_set = svn_fs_x__change_set_by_txn(txn_id);
+ id.number = (*old_rep)->id.number;
+
+ SVN_ERR(svn_fs_x__rev_file_wrap_temp(&rev_file, fs, file,
+ scratch_pool));
+ SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, rev_file,
+ &id, scratch_pool));
+
+ SVN_ERR(svn_fs_x__get_contents_from_file(&old_contents, fs,
+ *old_rep, file,
+ offset, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(svn_fs_x__get_contents(&old_contents, fs, *old_rep,
+ FALSE, scratch_pool));
+ }
+ err = svn_stream_contents_same2(&same, contents, old_contents,
+ scratch_pool);
+
+ /* A mismatch should be extremely rare.
+ * If it does happen, reject the commit. */
+ if (!same || err)
+ {
+ /* SHA1 collision or worse. */
+ svn_stringbuf_t *old_rep_str
+ = svn_fs_x__unparse_representation(*old_rep, FALSE,
+ scratch_pool,
+ scratch_pool);
+ svn_stringbuf_t *rep_str
+ = svn_fs_x__unparse_representation(rep, FALSE,
+ scratch_pool,
+ scratch_pool);
+ const char *checksum__str
+ = svn_checksum_to_cstring_display(&checksum, scratch_pool);
+
+ return svn_error_createf(SVN_ERR_FS_AMBIGUOUS_CHECKSUM_REP,
+ err, "SHA1 of reps '%s' and '%s' "
+ "matches (%s) but contents differ",
+ old_rep_str->data, rep_str->data,
+ checksum__str);
+ }
+
+ /* Restore FILE's read / write position. */
+ SVN_ERR(svn_io_file_seek(file, APR_SET, &old_position, scratch_pool));
+ }
+
return SVN_NO_ERROR;
}
@@ -2527,8 +2608,8 @@ rep_write_contents_close(void *baton)
/* Check and see if we already have a representation somewhere that's
identical to the one we just wrote out. */
- SVN_ERR(get_shared_rep(&old_rep, b->fs, rep, NULL, b->result_pool,
- b->local_pool));
+ SVN_ERR(get_shared_rep(&old_rep, b->fs, txn_id, rep, b->file, b->rep_offset,
+ NULL, b->result_pool, b->local_pool));
if (old_rep)
{
@@ -2572,11 +2653,16 @@ rep_write_contents_close(void *baton)
entry.items = &noderev_id;
entry.fnv1_checksum = b->fnv1a_checksum;
- SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->local_pool));
SVN_ERR(store_p2l_index_entry(b->fs, txn_id, &entry, b->local_pool));
}
SVN_ERR(svn_io_file_close(b->file, b->local_pool));
+
+ /* Write the sha1->rep mapping *after* we successfully written node
+ * revision to disk. */
+ if (!old_rep)
+ SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->local_pool));
+
SVN_ERR(unlock_proto_rev(b->fs, txn_id, b->lockcookie, b->local_pool));
svn_pool_destroy(b->local_pool);
@@ -2754,11 +2840,14 @@ write_directory_to_stream(svn_stream_t *
/* Write out the COLLECTION pertaining to the NODEREV in FS as a deltified
text representation to file FILE using WRITER. In the process, record the
total size and the md5 digest in REP and add the representation of type
- ITEM_TYPE to the indexes if necessary. If rep sharing has been enabled and
- REPS_HASH is not NULL, it will be used in addition to the on-disk cache to
- find earlier reps with the same content. When such existing reps can be
- found, we will truncate the one just written from the file and return the
- existing rep.
+ ITEM_TYPE to the indexes if necessary.
+
+ If ALLOW_REP_SHARING is FALSE, rep-sharing will not be used, regardless
+ of any other option and rep-sharing settings. If rep sharing has been
+ enabled and REPS_HASH is not NULL, it will be used in addition to the
+ on-disk cache to find earlier reps with the same content. If such
+ existing reps can be found, we will truncate the one just written from
+ the file and return the existing rep.
If ITEM_TYPE is IS_PROPS equals SVN_FS_FS__ITEM_TYPE_*_PROPS, assume
that we want to a props representation as the base for our delta.
@@ -2775,6 +2864,7 @@ write_container_delta_rep(svn_fs_x__repr
svn_fs_x__txn_id_t txn_id,
svn_fs_x__noderev_t *noderev,
apr_hash_t *reps_hash,
+ svn_boolean_t allow_rep_sharing,
apr_uint32_t item_type,
svn_revnum_t final_revision,
apr_pool_t *scratch_pool)
@@ -2786,7 +2876,7 @@ write_container_delta_rep(svn_fs_x__repr
svn_stream_t *file_stream;
svn_stream_t *stream;
svn_fs_x__representation_t *base_rep;
- svn_fs_x__representation_t *old_rep;
+ svn_fs_x__representation_t *old_rep = NULL;
svn_fs_x__p2l_entry_t entry;
svn_stream_t *source;
svn_fs_x__rep_header_t header = { 0 };
@@ -2852,12 +2942,17 @@ write_container_delta_rep(svn_fs_x__repr
/* Store the results. */
SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, scratch_pool));
+
+ /* Update size info. */
+ SVN_ERR(svn_io_file_get_offset(&rep_end, file, scratch_pool));
+ rep->size = rep_end - delta_start;
rep->expanded_size = whb->size;
/* Check and see if we already have a representation somewhere that's
identical to the one we just wrote out. */
- SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, scratch_pool,
- scratch_pool));
+ if (allow_rep_sharing)
+ SVN_ERR(get_shared_rep(&old_rep, fs, txn_id, rep, file, offset, reps_hash,
+ scratch_pool, scratch_pool));
if (old_rep)
{
@@ -2874,7 +2969,6 @@ write_container_delta_rep(svn_fs_x__repr
svn_fs_x__id_t noderev_id;
/* Write out our cosmetic end marker. */
- SVN_ERR(svn_io_file_get_offset(&rep_end, file, scratch_pool));
SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n"));
SVN_ERR(svn_stream_close(file_stream));
@@ -3076,7 +3170,7 @@ write_final_rev(svn_fs_x__id_t *new_id_p
SVN_ERR(write_container_delta_rep(noderev->data_rep, file,
entries,
write_directory_to_stream,
- fs, txn_id, noderev, NULL,
+ fs, txn_id, noderev, NULL, FALSE,
SVN_FS_X__ITEM_TYPE_DIR_REP,
rev, scratch_pool));
@@ -3128,8 +3222,8 @@ write_final_rev(svn_fs_x__id_t *new_id_p
SVN_ERR(write_container_delta_rep(noderev->prop_rep, file, proplist,
write_hash_to_stream, fs, txn_id,
- noderev, reps_hash, item_type, rev,
- scratch_pool));
+ noderev, reps_hash, TRUE, item_type,
+ rev, scratch_pool));
}
/* Convert our temporary ID into a permanent revision one. */
@@ -3558,10 +3652,8 @@ get_writable_final_rev(apr_file_t **file
SVN_ERR(svn_io_file_seek(*file, APR_END, &end_offset, scratch_pool));
/* We don't want unused sections (such as leftovers from failed delta
- stream) in our file. If we use log addressing, we would need an
- index entry for the unused section and that section would need to
- be all NUL by convention. So, detect and fix those cases by truncating
- the protorev file. */
+ stream) in our file. Detect and fix those cases by truncating the
+ protorev file. */
SVN_ERR(auto_truncate_proto_rev(fs, *file, end_offset, txn_id,
scratch_pool));
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c Wed Nov 7 12:30:06 2018
@@ -1251,7 +1251,7 @@ svn_fs_x__commit_txn(const char **confli
if (ffd->pack_after_commit)
{
- SVN_ERR(svn_fs_x__pack(fs, NULL, NULL, NULL, NULL, pool));
+ SVN_ERR(svn_fs_x__pack(fs, 0, NULL, NULL, NULL, NULL, pool));
}
return SVN_NO_ERROR;
@@ -2060,7 +2060,7 @@ typedef struct text_baton_t
* svn_fs_apply_text() ==> ... ==> txn_body_fulltext_finalize_edits()
*/
-/* Write function for the publically returned stream. */
+/* Write function for the publicly returned stream. */
static svn_error_t *
text_stream_writer(void *baton,
const char *data,
@@ -2904,21 +2904,19 @@ assemble_history(svn_fs_t *fs,
/* DIR_DAG is a directory DAG node which has mergeinfo in its
descendants. This function iterates over its children. For each
- child with immediate mergeinfo, it adds its mergeinfo to
- RESULT_CATALOG. appropriate arguments. For each child with
- descendants with mergeinfo, it recurses. Note that it does *not*
- call the action on the path for DIR_DAG itself.
-
- POOL is used for temporary allocations, including the mergeinfo
- hashes passed to actions; RESULT_POOL is used for the mergeinfo added
- to RESULT_CATALOG.
+ child with immediate mergeinfo, call RECEIVER with it and BATON.
+ For each child with descendants with mergeinfo, it recurses. Note
+ that it does *not* call the action on the path for DIR_DAG itself.
+
+ SCRATCH_POOL is used for temporary allocations, including the mergeinfo
+ hashes passed to actions.
*/
static svn_error_t *
crawl_directory_dag_for_mergeinfo(svn_fs_root_t *root,
const char *this_path,
dag_node_t *dir_dag,
- svn_mergeinfo_catalog_t result_catalog,
- apr_pool_t *result_pool,
+ svn_fs_mergeinfo_receiver_t receiver,
+ void *baton,
apr_pool_t *scratch_pool)
{
apr_array_header_t *entries;
@@ -2966,7 +2964,7 @@ crawl_directory_dag_for_mergeinfo(svn_fs
error. */
err = svn_mergeinfo_parse(&kid_mergeinfo,
mergeinfo_string->data,
- result_pool);
+ iterpool);
if (err)
{
if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
@@ -2976,8 +2974,7 @@ crawl_directory_dag_for_mergeinfo(svn_fs
}
else
{
- svn_hash_sets(result_catalog, apr_pstrdup(result_pool, kid_path),
- kid_mergeinfo);
+ SVN_ERR(receiver(kid_path, kid_mergeinfo, baton, iterpool));
}
}
@@ -2985,8 +2982,8 @@ crawl_directory_dag_for_mergeinfo(svn_fs
SVN_ERR(crawl_directory_dag_for_mergeinfo(root,
kid_path,
kid_dag,
- result_catalog,
- result_pool,
+ receiver,
+ baton,
iterpool));
}
@@ -3095,14 +3092,13 @@ get_mergeinfo_for_path(svn_mergeinfo_t *
return SVN_NO_ERROR;
}
-/* Adds mergeinfo for each descendant of PATH (but not PATH itself)
- under ROOT to RESULT_CATALOG. Returned values are allocated in
- RESULT_POOL; temporary values in POOL. */
+/* Invoke RECEIVER with BATON for each mergeinfo found on descendants of
+ PATH (but not PATH itself). Use SCRATCH_POOL for temporary values. */
static svn_error_t *
-add_descendant_mergeinfo(svn_mergeinfo_catalog_t result_catalog,
- svn_fs_root_t *root,
+add_descendant_mergeinfo(svn_fs_root_t *root,
const char *path,
- apr_pool_t *result_pool,
+ svn_fs_mergeinfo_receiver_t receiver,
+ void *baton,
apr_pool_t *scratch_pool)
{
dag_node_t *this_dag;
@@ -3112,27 +3108,28 @@ add_descendant_mergeinfo(svn_mergeinfo_c
SVN_ERR(crawl_directory_dag_for_mergeinfo(root,
path,
this_dag,
- result_catalog,
- result_pool,
+ receiver,
+ baton,
scratch_pool));
return SVN_NO_ERROR;
}
-/* Get the mergeinfo for a set of paths, returned in
- *MERGEINFO_CATALOG. Returned values are allocated in
- POOL, while temporary values are allocated in a sub-pool. */
+/* Find all the mergeinfo for a set of PATHS under ROOT and report it
+ through RECEIVER with BATON. INHERITED, INCLUDE_DESCENDANTS and
+ ADJUST_INHERITED_MERGEINFO are the same as in the FS API.
+
+ Allocate temporary values are allocated in SCRATCH_POOL. */
static svn_error_t *
get_mergeinfos_for_paths(svn_fs_root_t *root,
- svn_mergeinfo_catalog_t *mergeinfo_catalog,
const apr_array_header_t *paths,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t include_descendants,
svn_boolean_t adjust_inherited_mergeinfo,
- apr_pool_t *result_pool,
+ svn_fs_mergeinfo_receiver_t receiver,
+ void *baton,
apr_pool_t *scratch_pool)
{
- svn_mergeinfo_catalog_t result_catalog = svn_hash__make(result_pool);
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int i;
@@ -3146,7 +3143,7 @@ get_mergeinfos_for_paths(svn_fs_root_t *
err = get_mergeinfo_for_path(&path_mergeinfo, root, path,
inherit, adjust_inherited_mergeinfo,
- result_pool, iterpool);
+ iterpool, iterpool);
if (err)
{
if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
@@ -3162,27 +3159,26 @@ get_mergeinfos_for_paths(svn_fs_root_t *
}
if (path_mergeinfo)
- svn_hash_sets(result_catalog, path, path_mergeinfo);
+ SVN_ERR(receiver(path, path_mergeinfo, baton, iterpool));
if (include_descendants)
- SVN_ERR(add_descendant_mergeinfo(result_catalog, root, path,
- result_pool, scratch_pool));
+ SVN_ERR(add_descendant_mergeinfo(root, path, receiver, baton,
+ iterpool));
}
svn_pool_destroy(iterpool);
- *mergeinfo_catalog = result_catalog;
return SVN_NO_ERROR;
}
/* Implements svn_fs_get_mergeinfo. */
static svn_error_t *
-x_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
- svn_fs_root_t *root,
+x_get_mergeinfo(svn_fs_root_t *root,
const apr_array_header_t *paths,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t include_descendants,
svn_boolean_t adjust_inherited_mergeinfo,
- apr_pool_t *result_pool,
+ svn_fs_mergeinfo_receiver_t receiver,
+ void *baton,
apr_pool_t *scratch_pool)
{
/* We require a revision root. */
@@ -3190,11 +3186,11 @@ x_get_mergeinfo(svn_mergeinfo_catalog_t
return svn_error_create(SVN_ERR_FS_NOT_REVISION_ROOT, NULL, NULL);
/* Retrieve a path -> mergeinfo hash mapping. */
- return get_mergeinfos_for_paths(root, catalog, paths,
- inherit,
+ return get_mergeinfos_for_paths(root, paths, inherit,
include_descendants,
adjust_inherited_mergeinfo,
- result_pool, scratch_pool);
+ receiver, baton,
+ scratch_pool);
}
Modified: subversion/branches/ra-git/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra/ra_loader.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra/ra_loader.c Wed Nov 7 12:30:06 2018
@@ -658,7 +658,7 @@ svn_error_t *
svn_ra_list(svn_ra_session_t *session,
const char *path,
svn_revnum_t revision,
- apr_array_header_t *patterns,
+ const apr_array_header_t *patterns,
svn_depth_t depth,
apr_uint32_t dirent_fields,
svn_ra_dirent_receiver_t receiver,
Modified: subversion/branches/ra-git/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra/ra_loader.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra/ra_loader.h Wed Nov 7 12:30:06 2018
@@ -336,7 +336,7 @@ typedef struct svn_ra__vtable_t {
svn_error_t *(*list)(svn_ra_session_t *session,
const char *path,
svn_revnum_t revision,
- apr_array_header_t *patterns,
+ const apr_array_header_t *patterns,
svn_depth_t depth,
apr_uint32_t dirent_fields,
svn_ra_dirent_receiver_t receiver,
Modified: subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c Wed Nov 7 12:30:06 2018
@@ -909,6 +909,28 @@ svn_ra_local__get_commit_editor(svn_ra_s
}
+/* Implements svn_repos_mergeinfo_receiver_t.
+ * It add MERGEINFO for PATH to the svn_mergeinfo_catalog_t BATON.
+ */
+static svn_error_t *
+mergeinfo_receiver(const char *path,
+ svn_mergeinfo_t mergeinfo,
+ void *baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_mergeinfo_catalog_t catalog = baton;
+ apr_pool_t *result_pool = apr_hash_pool_get(catalog);
+ apr_size_t len = strlen(path);
+
+ apr_hash_set(catalog,
+ apr_pstrmemdup(result_pool, path, len),
+ len,
+ svn_mergeinfo_dup(mergeinfo, result_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
static svn_error_t *
svn_ra_local__get_mergeinfo(svn_ra_session_t *session,
svn_mergeinfo_catalog_t *catalog,
@@ -919,7 +941,7 @@ svn_ra_local__get_mergeinfo(svn_ra_sessi
apr_pool_t *pool)
{
svn_ra_local__session_baton_t *sess = session->priv;
- svn_mergeinfo_catalog_t tmp_catalog;
+ svn_mergeinfo_catalog_t tmp_catalog = svn_hash__make(pool);
int i;
apr_array_header_t *abs_paths =
apr_array_make(pool, 0, sizeof(const char *));
@@ -931,9 +953,11 @@ svn_ra_local__get_mergeinfo(svn_ra_sessi
svn_fspath__join(sess->fs_path->data, relative_path, pool);
}
- SVN_ERR(svn_repos_fs_get_mergeinfo(&tmp_catalog, sess->repos, abs_paths,
- revision, inherit, include_descendants,
- NULL, NULL, pool));
+ SVN_ERR(svn_repos_fs_get_mergeinfo2(sess->repos, abs_paths, revision,
+ inherit, include_descendants,
+ NULL, NULL,
+ mergeinfo_receiver, tmp_catalog,
+ pool));
if (apr_hash_count(tmp_catalog) > 0)
SVN_ERR(svn_mergeinfo__remove_prefix_from_catalog(catalog,
tmp_catalog,
@@ -1363,7 +1387,7 @@ svn_ra_local__get_dir(svn_ra_session_t *
{
/* size */
if (fs_entry->kind == svn_node_dir)
- entry->size = 0;
+ entry->size = SVN_INVALID_FILESIZE;
else
SVN_ERR(svn_fs_file_length(&(entry->size), root,
fullpath, iterpool));
@@ -1813,7 +1837,7 @@ static svn_error_t *
svn_ra_local__list(svn_ra_session_t *session,
const char *path,
svn_revnum_t revision,
- apr_array_header_t *patterns,
+ const apr_array_header_t *patterns,
svn_depth_t depth,
apr_uint32_t dirent_fields,
svn_ra_dirent_receiver_t receiver,
Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/blame.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/blame.c Wed Nov 7 12:30:06 2018
@@ -81,6 +81,8 @@ typedef struct blame_context_t {
svn_stream_t *stream;
+ svn_ra_serf__session_t *session;
+
} blame_context_t;
@@ -318,6 +320,20 @@ create_file_revs_body(serf_bucket_t **bo
return SVN_NO_ERROR;
}
+/* Implements svn_ra_serf__request_header_delegate_t */
+static svn_error_t *
+setup_headers(serf_bucket_t *headers,
+ void *baton,
+ apr_pool_t *request_pool,
+ apr_pool_t *scratch_pool)
+{
+ blame_context_t *blame_ctx = baton;
+
+ svn_ra_serf__setup_svndiff_accept_encoding(headers, blame_ctx->session);
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_ra_serf__get_file_revs(svn_ra_session_t *ra_session,
const char *path,
@@ -343,6 +359,7 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
blame_ctx->start = start;
blame_ctx->end = end;
blame_ctx->include_merged_revisions = include_merged_revisions;
+ blame_ctx->session = session;
/* Since Subversion 1.8 we allow retrieving blames backwards. So we can't
just unconditionally use end_rev as the peg revision as before */
@@ -369,6 +386,9 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
handler->body_type = "text/xml";
handler->body_delegate = create_file_revs_body;
handler->body_delegate_baton = blame_ctx;
+ handler->custom_accept_encoding = TRUE;
+ handler->header_delegate = setup_headers;
+ handler->header_delegate_baton = blame_ctx;
SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/commit.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/commit.c Wed Nov 7 12:30:06 2018
@@ -176,12 +176,18 @@ typedef struct file_context_t {
/* Buffer holding the svndiff (can spill to disk). */
svn_ra_serf__request_body_t *svndiff;
+ /* Did we send the svndiff in apply_textdelta_stream()? */
+ svn_boolean_t svndiff_sent;
+
/* Our base checksum as reported by the WC. */
const char *base_checksum;
/* Our resulting checksum as reported by the WC. */
const char *result_checksum;
+ /* Our resulting checksum as reported by the server. */
+ svn_checksum_t *remote_result_checksum;
+
/* Changed properties (const char * -> svn_prop_t *) */
apr_hash_t *prop_changes;
@@ -305,7 +311,7 @@ checkout_node(const char **working_url,
fails due to an SVN_ERR_APMOD_BAD_BASELINE error return from the
server.
- See http://subversion.tigris.org/issues/show_bug.cgi?id=4127 for
+ See https://issues.apache.org/jira/browse/SVN-4127 for
details.
*/
static svn_error_t *
@@ -671,7 +677,7 @@ write_prop_xml(const proppatch_context_t
explicitly deleted in this commit already, then mod_dav removed its
lock token when it fielded the DELETE request, so we don't want to
set the lock precondition again. (See
- http://subversion.tigris.org/issues/show_bug.cgi?id=3674 for details.)
+ https://issues.apache.org/jira/browse/SVN-3674 for details.)
*/
static svn_error_t *
maybe_set_lock_token_header(serf_bucket_t *headers,
@@ -681,7 +687,7 @@ maybe_set_lock_token_header(serf_bucket_
{
const char *token;
- if (! (*relpath && commit_ctx->lock_tokens))
+ if (! commit_ctx->lock_tokens)
return SVN_NO_ERROR;
if (! svn_hash_gets(commit_ctx->deleted_entries, relpath))
@@ -1859,6 +1865,75 @@ open_file(const char *path,
return SVN_NO_ERROR;
}
+static void
+negotiate_put_encoding(int *svndiff_version_p,
+ int *svndiff_compression_level_p,
+ svn_ra_serf__session_t *session)
+{
+ int svndiff_version;
+ int compression_level;
+
+ if (session->using_compression == svn_tristate_unknown)
+ {
+ /* With http-compression=auto, prefer svndiff2 to svndiff1 with a
+ * low latency connection (assuming the underlying network has high
+ * bandwidth), as it is faster and in this case, we don't care about
+ * worse compression ratio.
+ *
+ * Note: For future compatibility, we also handle a theoretically
+ * possible case where the server has advertised only svndiff2 support.
+ */
+ if (session->supports_svndiff2 &&
+ svn_ra_serf__is_low_latency_connection(session))
+ svndiff_version = 2;
+ else if (session->supports_svndiff1)
+ svndiff_version = 1;
+ else if (session->supports_svndiff2)
+ svndiff_version = 2;
+ else
+ svndiff_version = 0;
+ }
+ else if (session->using_compression == svn_tristate_true)
+ {
+ /* Otherwise, prefer svndiff1, as svndiff2 is not a reasonable
+ * substitute for svndiff1 with default compression level. (It gives
+ * better speed and compression ratio comparable to svndiff1 with
+ * compression level 1, but not 5).
+ *
+ * Note: For future compatibility, we also handle a theoretically
+ * possible case where the server has advertised only svndiff2 support.
+ */
+ if (session->supports_svndiff1)
+ svndiff_version = 1;
+ else if (session->supports_svndiff2)
+ svndiff_version = 2;
+ else
+ svndiff_version = 0;
+ }
+ else
+ {
+ /* Difference between svndiff formats 0 and 1/2 that format 1/2 allows
+ * compression. Uncompressed svndiff0 should also be slightly more
+ * effective if the compression is not required at all.
+ *
+ * If the server cannot handle svndiff1/2, or compression is disabled
+ * with the 'http-compression = no' client configuration option, fall
+ * back to uncompressed svndiff0 format. As a bonus, users can force
+ * the usage of the uncompressed format by setting the corresponding
+ * client configuration option, if they want to.
+ */
+ svndiff_version = 0;
+ }
+
+ if (svndiff_version == 0)
+ compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
+ else
+ compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
+
+ *svndiff_version_p = svndiff_version;
+ *svndiff_compression_level_p = compression_level;
+}
+
static svn_error_t *
apply_textdelta(void *file_baton,
const char *base_checksum,
@@ -1873,49 +1948,21 @@ apply_textdelta(void *file_baton,
/* Construct a holder for the request body; we'll give it to serf when we
* close this file.
*
- * TODO: There should be a way we can stream the request body instead of
- * possibly writing to a temporary file (ugh). A special svn stream serf
- * bucket that returns EAGAIN until we receive the done call? But, when
- * would we run through the serf context? Grr.
- *
- * BH: If you wait to a specific event... why not use that event to
- * trigger the operation?
- * Having a request (body) bucket return EAGAIN until done stalls
- * the entire HTTP pipeline after writing the first part of the
- * request. It is not like we can interrupt some part of a request
- * and continue later. Or somebody else must use tempfiles and
- * always assume that clients work this bad... as it only knows
- * for sure after the request is completely available.
+ * Please note that if this callback is used, large request bodies will
+ * be spilled into temporary files (that requires disk space and prevents
+ * simultaneous processing by the server and the client). A better approach
+ * that streams the request body is implemented in apply_textdelta_stream().
+ * It will be used with most recent servers having the "send result checksum
+ * in response to a PUT" capability, and only if the editor driver uses the
+ * new callback.
*/
-
ctx->svndiff =
svn_ra_serf__request_body_create(SVN_RA_SERF__REQUEST_BODY_IN_MEM_SIZE,
ctx->pool);
ctx->stream = svn_ra_serf__request_body_get_stream(ctx->svndiff);
- if (ctx->commit_ctx->session->supports_svndiff1 &&
- ctx->commit_ctx->session->using_compression)
- {
- /* Use compressed svndiff1 format, if possible. */
- svndiff_version = 1;
- compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
- }
- else
- {
- /* Difference between svndiff formats 0 and 1 that format 1 allows
- * compression. Uncompressed svndiff0 should also be slightly more
- * effective if the compression is not required at all.
- *
- * If the server cannot handle svndiff1, or compression is disabled
- * with the 'http-compression = no' client configuration option, fall
- * back to uncompressed svndiff0 format. As a bonus, users can force
- * the usage of the uncompressed format by setting the corresponding
- * client configuration option, if they want to.
- */
- svndiff_version = 0;
- compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
- }
-
+ negotiate_put_encoding(&svndiff_version, &compression_level,
+ ctx->commit_ctx->session);
/* Disown the stream; we'll close it explicitly in close_file(). */
svn_txdelta_to_svndiff3(handler, handler_baton,
svn_stream_disown(ctx->stream, pool),
@@ -1927,6 +1974,146 @@ apply_textdelta(void *file_baton,
return SVN_NO_ERROR;
}
+typedef struct open_txdelta_baton_t
+{
+ svn_ra_serf__session_t *session;
+ svn_txdelta_stream_open_func_t open_func;
+ void *open_baton;
+ svn_error_t *err;
+} open_txdelta_baton_t;
+
+static void
+txdelta_stream_errfunc(void *baton, svn_error_t *err)
+{
+ open_txdelta_baton_t *b = baton;
+
+ /* Remember extended error info from the stream bucket. Note that
+ * theoretically this errfunc could be called multiple times -- say,
+ * if the request gets restarted after an error. Compose the errors
+ * so we don't leak one of them if this happens. */
+ b->err = svn_error_compose_create(b->err, svn_error_dup(err));
+}
+
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_body_from_txdelta_stream(serf_bucket_t **body_bkt,
+ void *baton,
+ serf_bucket_alloc_t *alloc,
+ apr_pool_t *pool /* request pool */,
+ apr_pool_t *scratch_pool)
+{
+ open_txdelta_baton_t *b = baton;
+ svn_txdelta_stream_t *txdelta_stream;
+ svn_stream_t *stream;
+ int svndiff_version;
+ int compression_level;
+
+ SVN_ERR(b->open_func(&txdelta_stream, b->open_baton, pool, scratch_pool));
+
+ negotiate_put_encoding(&svndiff_version, &compression_level, b->session);
+ stream = svn_txdelta_to_svndiff_stream(txdelta_stream, svndiff_version,
+ compression_level, pool);
+ *body_bkt = svn_ra_serf__create_stream_bucket(stream, alloc,
+ txdelta_stream_errfunc, b);
+
+ return SVN_NO_ERROR;
+}
+
+/* Handler baton for PUT request. */
+typedef struct put_response_ctx_t
+{
+ svn_ra_serf__handler_t *handler;
+ file_context_t *file_ctx;
+} put_response_ctx_t;
+
+/* Implements svn_ra_serf__response_handler_t */
+static svn_error_t *
+put_response_handler(serf_request_t *request,
+ serf_bucket_t *response,
+ void *baton,
+ apr_pool_t *scratch_pool)
+{
+ put_response_ctx_t *prc = baton;
+ serf_bucket_t *hdrs;
+ const char *val;
+
+ hdrs = serf_bucket_response_get_headers(response);
+ val = serf_bucket_headers_get(hdrs, SVN_DAV_RESULT_FULLTEXT_MD5_HEADER);
+ SVN_ERR(svn_checksum_parse_hex(&prc->file_ctx->remote_result_checksum,
+ svn_checksum_md5, val, prc->file_ctx->pool));
+
+ return svn_error_trace(
+ svn_ra_serf__expect_empty_body(request, response,
+ prc->handler, scratch_pool));
+}
+
+static svn_error_t *
+apply_textdelta_stream(const svn_delta_editor_t *editor,
+ void *file_baton,
+ const char *base_checksum,
+ svn_txdelta_stream_open_func_t open_func,
+ void *open_baton,
+ apr_pool_t *scratch_pool)
+{
+ file_context_t *ctx = file_baton;
+ open_txdelta_baton_t open_txdelta_baton = {0};
+ svn_ra_serf__handler_t *handler;
+ put_response_ctx_t *prc;
+ int expected_result;
+ svn_error_t *err;
+
+ /* Remember that we have sent the svndiff. A case when we need to
+ * perform a zero-byte file PUT (during add_file, close_file editor
+ * sequences) is handled in close_file().
+ */
+ ctx->svndiff_sent = TRUE;
+ ctx->base_checksum = base_checksum;
+
+ handler = svn_ra_serf__create_handler(ctx->commit_ctx->session,
+ scratch_pool);
+ handler->method = "PUT";
+ handler->path = ctx->url;
+
+ prc = apr_pcalloc(scratch_pool, sizeof(*prc));
+ prc->handler = handler;
+ prc->file_ctx = ctx;
+
+ handler->response_handler = put_response_handler;
+ handler->response_baton = prc;
+
+ open_txdelta_baton.session = ctx->commit_ctx->session;
+ open_txdelta_baton.open_func = open_func;
+ open_txdelta_baton.open_baton = open_baton;
+ open_txdelta_baton.err = SVN_NO_ERROR;
+
+ handler->body_delegate = create_body_from_txdelta_stream;
+ handler->body_delegate_baton = &open_txdelta_baton;
+ handler->body_type = SVN_SVNDIFF_MIME_TYPE;
+
+ handler->header_delegate = setup_put_headers;
+ handler->header_delegate_baton = ctx;
+
+ err = svn_ra_serf__context_run_one(handler, scratch_pool);
+ /* Do we have an error from the stream bucket? If yes, use it. */
+ if (open_txdelta_baton.err)
+ {
+ svn_error_clear(err);
+ return svn_error_trace(open_txdelta_baton.err);
+ }
+ else if (err)
+ return svn_error_trace(err);
+
+ if (ctx->added && !ctx->copy_path)
+ expected_result = 201; /* Created */
+ else
+ expected_result = 204; /* Updated */
+
+ if (handler->sline.code != expected_result)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
change_file_prop(void *file_baton,
const char *name,
@@ -1962,8 +2149,8 @@ close_file(void *file_baton,
if ((!ctx->svndiff) && ctx->added && (!ctx->copy_path))
put_empty_file = TRUE;
- /* If we had a stream of changes, push them to the server... */
- if (ctx->svndiff || put_empty_file)
+ /* If we have a stream of changes, push them to the server... */
+ if ((ctx->svndiff || put_empty_file) && !ctx->svndiff_sent)
{
svn_ra_serf__handler_t *handler;
int expected_result;
@@ -2028,6 +2215,22 @@ close_file(void *file_baton,
proppatch, scratch_pool));
}
+ if (ctx->result_checksum && ctx->remote_result_checksum)
+ {
+ svn_checksum_t *result_checksum;
+
+ SVN_ERR(svn_checksum_parse_hex(&result_checksum, svn_checksum_md5,
+ ctx->result_checksum, scratch_pool));
+
+ if (!svn_checksum_match(result_checksum, ctx->remote_result_checksum))
+ return svn_checksum_mismatch_err(result_checksum,
+ ctx->remote_result_checksum,
+ scratch_pool,
+ _("Checksum mismatch for '%s'"),
+ svn_dirent_local_style(ctx->relpath,
+ scratch_pool));
+ }
+
ctx->commit_ctx->open_batons--;
return SVN_NO_ERROR;
@@ -2203,6 +2406,12 @@ svn_ra_serf__get_commit_editor(svn_ra_se
editor->close_file = close_file;
editor->close_edit = close_edit;
editor->abort_edit = abort_edit;
+ /* Only install the callback that allows streaming PUT request bodies
+ * if the server has the necessary capability. Otherwise, this will
+ * fallback to the default implementation using the temporary files.
+ * See default_editor.c:apply_textdelta_stream(). */
+ if (session->supports_put_result_checksum)
+ editor->apply_textdelta_stream = apply_textdelta_stream;
*ret_editor = editor;
*edit_baton = ctx;
Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/get_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/get_file.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/get_file.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/get_file.c Wed Nov 7 12:30:06 2018
@@ -60,7 +60,7 @@ typedef struct stream_ctx_t {
/* Have we read our response headers yet? */
svn_boolean_t read_headers;
- svn_boolean_t using_compression;
+ svn_ra_serf__session_t *session;
/* This flag is set when our response is aborted before we reach the
* end and we decide to requeue this request.
@@ -88,7 +88,7 @@ headers_fetch(serf_bucket_t *headers,
{
stream_ctx_t *fetch_ctx = baton;
- if (fetch_ctx->using_compression)
+ if (fetch_ctx->session->using_compression != svn_tristate_false)
{
serf_bucket_headers_setn(headers, "Accept-Encoding", "gzip");
}
@@ -396,7 +396,7 @@ svn_ra_serf__get_file(svn_ra_session_t *
/* Create the fetch context. */
stream_ctx = apr_pcalloc(scratch_pool, sizeof(*stream_ctx));
stream_ctx->result_stream = stream;
- stream_ctx->using_compression = session->using_compression;
+ stream_ctx->session = session;
handler = svn_ra_serf__create_handler(session, scratch_pool);
Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/merge.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/merge.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/merge.c Wed Nov 7 12:30:06 2018
@@ -79,6 +79,7 @@ typedef struct merge_context_t
apr_hash_t *lock_tokens;
svn_boolean_t keep_locks;
+ svn_boolean_t disable_merge_response;
const char *merge_resource_url; /* URL of resource to be merged. */
const char *merge_url; /* URL at which the MERGE request is aimed. */
@@ -275,12 +276,17 @@ setup_merge_headers(serf_bucket_t *heade
apr_pool_t *scratch_pool)
{
merge_context_t *ctx = baton;
+ apr_array_header_t *vals = apr_array_make(scratch_pool, 2,
+ sizeof(const char *));
if (!ctx->keep_locks)
- {
- serf_bucket_headers_set(headers, SVN_DAV_OPTIONS_HEADER,
- SVN_DAV_OPTION_RELEASE_LOCKS);
- }
+ APR_ARRAY_PUSH(vals, const char *) = SVN_DAV_OPTION_RELEASE_LOCKS;
+ if (ctx->disable_merge_response)
+ APR_ARRAY_PUSH(vals, const char *) = SVN_DAV_OPTION_NO_MERGE_RESPONSE;
+
+ if (vals->nelts > 0)
+ serf_bucket_headers_set(headers, SVN_DAV_OPTIONS_HEADER,
+ svn_cstring_join2(vals, " ", FALSE, scratch_pool));
return SVN_NO_ERROR;
}
@@ -412,6 +418,13 @@ svn_ra_serf__run_merge(const svn_commit_
merge_ctx->lock_tokens = lock_tokens;
merge_ctx->keep_locks = keep_locks;
+ /* We don't need the full merge response when working over HTTPv2.
+ * Over HTTPv1, this response is only required with a non-null
+ * svn_ra_push_wc_prop_func_t callback. */
+ merge_ctx->disable_merge_response =
+ SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session) ||
+ session->wc_callbacks->push_wc_prop == NULL;
+
merge_ctx->commit_info = svn_create_commit_info(result_pool);
merge_ctx->merge_url = session->session_url.path;
Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/options.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/options.c Wed Nov 7 12:30:06 2018
@@ -71,6 +71,9 @@ typedef struct options_context_t {
svn_ra_serf__response_handler_t inner_handler;
void *inner_baton;
+ /* Have we received any DAV headers at all? */
+ svn_boolean_t received_dav_header;
+
const char *activity_collection;
svn_revnum_t youngest_rev;
@@ -165,6 +168,8 @@ capabilities_headers_iterator_callback(v
apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE,
opt_ctx->pool);
+ opt_ctx->received_dav_header = TRUE;
+
/* Right now we only have a few capabilities to detect, so just
seek for them directly. This could be written slightly more
efficiently, but that wouldn't be worth it until we have many
@@ -232,6 +237,20 @@ capabilities_headers_iterator_callback(v
advertise this capability (Subversion 1.10 and greater). */
session->supports_svndiff1 = TRUE;
}
+ if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_LIST, vals))
+ {
+ svn_hash_sets(session->capabilities,
+ SVN_RA_CAPABILITY_LIST, capability_yes);
+ }
+ if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_SVNDIFF2, vals))
+ {
+ /* Same for svndiff2. */
+ session->supports_svndiff2 = TRUE;
+ }
+ if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PUT_RESULT_CHECKSUM, vals))
+ {
+ session->supports_put_result_checksum = TRUE;
+ }
}
/* SVN-specific headers -- if present, server supports HTTP protocol v2 */
@@ -249,21 +268,6 @@ capabilities_headers_iterator_callback(v
apr_hash_set(session->supported_posts, "create-txn", 10, (void *)1);
}
- /* Use compressed svndiff1 format for servers that speak HTTPv2,
- in addition to servers that send SVN_DAV_NS_DAV_SVN_SVNDIFF1.
-
- Apache HTTPd + mod_dav_svn servers support svndiff1, beginning
- from Subversion 1.4, but they do not advertise this capability.
- Compressing data can have a noticeable impact if the connection
- is slow, and we want to use it even for existing servers, so we
- send svndiff1 data to every HTTPv2 server (Subversion 1.7 and
- greater).
-
- The reasoning behind enabling it with HTTPv2 is that if the user
- is stuck with the old Subversion's HTTPv1 protocol, she probably
- doesn't really care about performance. */
- session->supports_svndiff1 = TRUE;
-
if (svn_cstring_casecmp(key, SVN_DAV_ROOT_URI_HEADER) == 0)
{
session->repos_root = session->session_url;
@@ -371,6 +375,7 @@ options_response_handler(serf_request_t
{
svn_ra_serf__session_t *session = opt_ctx->session;
serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
+ serf_connection_t *conn;
/* Start out assuming all capabilities are unsupported. */
svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
@@ -389,17 +394,36 @@ options_response_handler(serf_request_t
capability_no);
svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_GET_FILE_REVS_REVERSE,
capability_no);
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_LIST,
+ capability_no);
/* Then see which ones we can discover. */
serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback,
opt_ctx);
+ /* Bail out early if we're not talking to a DAV server.
+ Note that this check is only valid if we've received a success
+ response; redirects and errors don't count. */
+ if (opt_ctx->handler->sline.code >= 200
+ && opt_ctx->handler->sline.code < 300
+ && !opt_ctx->received_dav_header)
+ {
+ return svn_error_createf
+ (SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
+ _("The server at '%s' does not support the HTTP/DAV protocol"),
+ session->session_url_str);
+ }
+
/* Assume mergeinfo capability unsupported, if didn't receive information
about server or repository mergeinfo capability. */
if (!svn_hash_gets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO))
svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
capability_no);
+ /* Remember our latency. */
+ conn = serf_request_get_conn(request);
+ session->conn_latency = serf_connection_get_latency(conn);
+
opt_ctx->headers_processed = TRUE;
}