You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2011/02/20 08:45:54 UTC
svn commit: r1072522 [2/9] - in /subversion/branches/performance: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/ notes/
notes/wc-ng/ subversion/bindings/javahl/native/
subversion/bindings/javahl/src/org/apache/subversion/javahl/...
Modified: subversion/branches/performance/subversion/include/svn_config.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_config.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_config.h (original)
+++ subversion/branches/performance/subversion/include/svn_config.h Sun Feb 20 07:45:48 2011
@@ -189,10 +189,14 @@ svn_config_get_config(apr_hash_t **cfg_h
/** Set @a *cfgp to an empty @c svn_config_t structure,
* allocated in @a result_pool.
*
+ * Pass TRUE to @a section_names_case_sensitive if
+ * section names are to be populated case sensitively.
+ *
* @since New in 1.7.
*/
svn_error_t *
svn_config_create(svn_config_t **cfgp,
+ svn_boolean_t section_names_case_sensitive,
apr_pool_t *result_pool);
/** Read configuration data from @a file (a file or registry path) into
@@ -200,7 +204,26 @@ svn_config_create(svn_config_t **cfgp,
*
* If @a file does not exist, then if @a must_exist, return an error,
* otherwise return an empty @c svn_config_t.
+ *
+ * If @a section_names_case_sensitive is TRUE, populate section name hashes
+ * case sensitively, except for the default SVN_CONFIG__DEFAULT_SECTION.
+ *
+ * @since New in 1.7.
*/
+
+svn_error_t *
+svn_config_read2(svn_config_t **cfgp,
+ const char *file,
+ svn_boolean_t must_exist,
+ svn_boolean_t section_names_case_sensitive,
+ apr_pool_t *pool);
+
+/** Similar to svn_config_read2, but always passes FALSE to
+ * section_names_case_sensitive.
+ *
+ * @deprecated Provided for backward compatibility with 1.6 API.
+ */
+SVN_DEPRECATED
svn_error_t *
svn_config_read(svn_config_t **cfgp,
const char *file,
Modified: subversion/branches/performance/subversion/include/svn_delta.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_delta.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_delta.h (original)
+++ subversion/branches/performance/subversion/include/svn_delta.h Sun Feb 20 07:45:48 2011
@@ -49,11 +49,20 @@ extern "C" {
+/** This compression level effectively disables data compression.
+ * However, the data pre-processing costs may still not be zero.
+ */
+#define SVN_NO_COMPRESSION_LEVEL 0
+
+/** This is the maximum compression level we can pass to zlib.
+ */
+#define SVN_BEST_COMPRESSION_LEVEL 9
+
/** This is the default compression level we pass to zlib. It
- * should be between 0 and 9, with higher numbers being greater
- * compression.
+ * should be between 0 and 9, with higher numbers resulting in
+ * better compression rates but slower operation.
*/
-#define SVNDIFF1_COMPRESS_LEVEL 5
+#define SVN_DEFAULT_COMPRESSION_LEVEL 5
/**
* Get libsvn_delta version information.
@@ -487,12 +496,12 @@ svn_txdelta_to_svndiff3(svn_txdelta_wind
int compression_level,
apr_pool_t *pool);
- /** Similar to svn_txdelta_to_svndiff3, but always using the SVN default
- * compression level (@ref SVNDIFF1_COMPRESS_LEVEL).
- *
- * @since New in 1.4.
- * @deprecated Provided for backward compatibility with the 1.6 API.
- */
+/** Similar to svn_txdelta_to_svndiff3, but always using the SVN default
+ * compression level (@ref SVN_DEFAULT_COMPRESSION_LEVEL).
+ *
+ * @since New in 1.4.
+ * @deprecated Provided for backward compatibility with the 1.6 API.
+ */
SVN_DEPRECATED
void
svn_txdelta_to_svndiff2(svn_txdelta_window_handler_t *handler,
Modified: subversion/branches/performance/subversion/include/svn_diff.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_diff.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_diff.h (original)
+++ subversion/branches/performance/subversion/include/svn_diff.h Sun Feb 20 07:45:48 2011
@@ -106,6 +106,51 @@ typedef enum svn_diff_datasource_e
/** A vtable for reading data from the three datasources. */
+typedef struct svn_diff_fns2_t
+{
+ /** Open the datasources of type @a datasources. */
+ svn_error_t *(*datasources_open)(void *diff_baton,
+ apr_off_t *prefix_lines,
+ apr_off_t *suffix_lines,
+ const svn_diff_datasource_e *datasources,
+ apr_size_t datasources_len);
+
+ /** Close the datasource of type @a datasource. */
+ svn_error_t *(*datasource_close)(void *diff_baton,
+ svn_diff_datasource_e datasource);
+
+ /** Get the next "token" from the datasource of type @a datasource.
+ * Return a "token" in @a *token. Return a hash of "token" in @a *hash.
+ * Leave @a token and @a hash untouched when the datasource is exhausted.
+ */
+ svn_error_t *(*datasource_get_next_token)(apr_uint32_t *hash, void **token,
+ void *diff_baton,
+ svn_diff_datasource_e datasource);
+
+ /** A function for ordering the tokens, resembling 'strcmp' in functionality.
+ * @a compare should contain the return value of the comparison:
+ * If @a ltoken and @a rtoken are "equal", return 0. If @a ltoken is
+ * "less than" @a rtoken, return a number < 0. If @a ltoken is
+ * "greater than" @a rtoken, return a number > 0.
+ */
+ svn_error_t *(*token_compare)(void *diff_baton,
+ void *ltoken,
+ void *rtoken,
+ int *compare);
+
+ /** Free @a token from memory, the diff algorithm is done with it. */
+ void (*token_discard)(void *diff_baton,
+ void *token);
+
+ /** Free *all* tokens from memory, they're no longer needed. */
+ void (*token_discard_all)(void *diff_baton);
+} svn_diff_fns2_t;
+
+
+/** A vtable for reading data from the three datasources.
+ *
+ * @deprecated Provided for backward compatibility with the 1.6 API.
+ */
typedef struct svn_diff_fns_t
{
/** Open the datasource of type @a datasource. */
@@ -149,8 +194,23 @@ typedef struct svn_diff_fns_t
/** Given a vtable of @a diff_fns/@a diff_baton for reading datasources,
* return a diff object in @a *diff that represents a difference between
* an "original" and "modified" datasource. Do all allocation in @a pool.
+ *
+ * @since New in 1.7.
*/
svn_error_t *
+svn_diff_diff_2(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns2_t *diff_fns,
+ apr_pool_t *pool);
+
+/** Given a vtable of @a diff_fns/@a diff_baton for reading datasources,
+ * return a diff object in @a *diff that represents a difference between
+ * an "original" and "modified" datasource. Do all allocation in @a pool.
+ *
+ * @deprecated Provided for backward compatibility with the 1.6 API.
+ */
+SVN_DEPRECATED
+svn_error_t *
svn_diff_diff(svn_diff_t **diff,
void *diff_baton,
const svn_diff_fns_t *diff_fns,
@@ -160,7 +220,23 @@ svn_diff_diff(svn_diff_t **diff,
* return a diff object in @a *diff that represents a difference between
* three datasources: "original", "modified", and "latest". Do all
* allocation in @a pool.
+ *
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_diff_diff3_2(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns2_t *diff_fns,
+ apr_pool_t *pool);
+
+/** Given a vtable of @a diff_fns/@a diff_baton for reading datasources,
+ * return a diff object in @a *diff that represents a difference between
+ * three datasources: "original", "modified", and "latest". Do all
+ * allocation in @a pool.
+ *
+ * @deprecated Provided for backward compatibility with the 1.6 API.
*/
+SVN_DEPRECATED
svn_error_t *
svn_diff_diff3(svn_diff_t **diff,
void *diff_baton,
@@ -172,8 +248,25 @@ svn_diff_diff3(svn_diff_t **diff,
* two datasources: "original" and "latest", adjusted to become a full
* difference between "original", "modified" and "latest" using "ancestor".
* Do all allocation in @a pool.
+ *
+ * @since New in 1.7.
*/
svn_error_t *
+svn_diff_diff4_2(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns2_t *diff_fns,
+ apr_pool_t *pool);
+
+/** Given a vtable of @a diff_fns/@a diff_baton for reading datasources,
+ * return a diff object in @a *diff that represents a difference between
+ * two datasources: "original" and "latest", adjusted to become a full
+ * difference between "original", "modified" and "latest" using "ancestor".
+ * Do all allocation in @a pool.
+ *
+ * @deprecated Provided for backward compatibility with the 1.6 API.
+ */
+SVN_DEPRECATED
+svn_error_t *
svn_diff_diff4(svn_diff_t **diff,
void *diff_baton,
const svn_diff_fns_t *diff_fns,
@@ -837,8 +930,8 @@ typedef struct svn_diff_hunk_t svn_diff_
* text will be returned in reversed form.
* The line-terminator is detected automatically and stored in @a *eol
* if @a eol is not NULL.
- * If EOF is reached and the stream does not end with a newline character,
- * and @a eol is not NULL, @a *eol is set to NULL.
+ * If EOF is reached, set @a *eof to TRUE, and set @a *eol to NULL if the
+ * hunk does not end with a newline character and @a eol is not NULL.
* Temporary allocations will be performed in @a scratch_pool.
*
* @since New in 1.7.
@@ -856,8 +949,8 @@ svn_diff_hunk_readline_diff_text(svn_dif
* of the original text of @a hunk.
* The line-terminator is detected automatically and stored in @a *eol
* if @a eol is not NULL.
- * If EOF is reached and the stream does not end with a newline character,
- * and @a eol is not NULL, @a *eol is set to NULL.
+ * If EOF is reached, set @a *eof to TRUE, and set @a *eol to NULL if the
+ * hunk text does not end with a newline character and @a eol is not NULL.
* Temporary allocations will be performed in @a scratch_pool.
*
* @see svn_diff_hunk_t
Modified: subversion/branches/performance/subversion/include/svn_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_fs.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_fs.h (original)
+++ subversion/branches/performance/subversion/include/svn_fs.h Sun Feb 20 07:45:48 2011
@@ -1397,8 +1397,9 @@ svn_fs_props_changed(svn_boolean_t *chan
/** Discover a node's copy ancestry, if any.
*
* If the node at @a path in @a root was copied from some other node, set
- * @a *rev_p and @a *path_p to the revision and path of the other node,
- * allocating @a *path_p in @a pool.
+ * @a *rev_p and @a *path_p to the revision and path (expressed as an
+ * absolute filesystem path) of the other node, allocating @a *path_p
+ * in @a pool.
*
* Else if there is no copy ancestry for the node, set @a *rev_p to
* #SVN_INVALID_REVNUM and @a *path_p to NULL.
Modified: subversion/branches/performance/subversion/include/svn_io.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_io.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_io.h (original)
+++ subversion/branches/performance/subversion/include/svn_io.h Sun Feb 20 07:45:48 2011
@@ -763,7 +763,9 @@ typedef svn_error_t *(*svn_write_fn_t)(v
/** Close handler function for a generic stream. @see svn_stream_t. */
typedef svn_error_t *(*svn_close_fn_t)(void *baton);
-/** An opaque type which represents a mark on a stream.
+/** An opaque type which represents a mark on a stream. There is no
+ * concrete definition of this type, it is a named type for stream
+ * implementation specific baton pointers.
*
* @see svn_stream_mark().
* @since New in 1.7.
@@ -785,7 +787,7 @@ typedef svn_error_t *(*svn_io_mark_fn_t)
* @since New in 1.7.
*/
typedef svn_error_t *(*svn_io_seek_fn_t)(void *baton,
- svn_stream_mark_t *mark);
+ const svn_stream_mark_t *mark);
/** Buffer test handler function for a generic stream. @see svn_stream_t
* and svn_stream_buffered().
@@ -959,6 +961,16 @@ svn_stream_t *
svn_stream_from_aprfile(apr_file_t *file,
apr_pool_t *pool);
+/** Set @a *err to a generic stream connected to stderr, allocated in
+ * @a pool. The stream and its underlying APR handle will be closed
+ * when @a pool is cleared or destroyed.
+ *
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_stream_for_stderr(svn_stream_t **err,
+ apr_pool_t *pool);
+
/** Set @a *out to a generic stream connected to stdout, allocated in
* @a pool. The stream and its underlying APR handle will be closed
* when @a pool is cleared or destroyed.
@@ -1045,7 +1057,17 @@ svn_stream_read(svn_stream_t *stream,
char *buffer,
apr_size_t *len);
-/** Skip data from a generic stream. @see svn_stream_t. */
+/**
+ * Skip COUNT bytes from a generic STREAM. If the stream is exhausted
+ * before COUNT bytes have been read, an error will be returned and
+ * COUNT will be changed to the actual number of bytes skipped.
+ *
+ * NOTE. No assumption can be made on the semantics of this function
+ * other than that the stream read pointer will be advanced by *count
+ * bytes. Depending on the capabilities of the underlying stream
+ * implementation, this may for instance be translated into a sequence
+ * of reads or a simple seek operation.
+ */
svn_error_t *
svn_stream_skip(svn_stream_t *stream,
apr_size_t *count);
@@ -1102,7 +1124,7 @@ svn_stream_mark(svn_stream_t *stream,
* @since New in 1.7.
*/
svn_error_t *
-svn_stream_seek(svn_stream_t *stream, svn_stream_mark_t *mark);
+svn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark);
/** Return whether this generic @a stream uses internal buffering.
* This may be used to work around subtle differences between buffered
@@ -1843,11 +1865,11 @@ svn_io_file_read(apr_file_t *file,
*/
svn_error_t *
svn_io_file_read_full2(apr_file_t *file,
- void *buf,
- apr_size_t nbytes,
- apr_size_t *bytes_read,
- svn_boolean_t *hit_eof,
- apr_pool_t *pool);
+ void *buf,
+ apr_size_t nbytes,
+ apr_size_t *bytes_read,
+ svn_boolean_t *hit_eof,
+ apr_pool_t *pool);
/** Similar to svn_io_file_read_full2 with hit_eof being set
Modified: subversion/branches/performance/subversion/include/svn_ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_ra_svn.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_ra_svn.h (original)
+++ subversion/branches/performance/subversion/include/svn_ra_svn.h Sun Feb 20 07:45:48 2011
@@ -173,8 +173,9 @@ svn_ra_svn_create_conn2(apr_socket_t *so
int compression_level,
apr_pool_t *pool);
-/** Similar to @ref svn_ra_svn_create_conn2() but uses default
- * compression level (#SVNDIFF1_COMPRESS_LEVEL) for network transmissions.
+/** Similar to @ref svn_ra_svn_create_conn2() but uses default
+ * compression level (@ref SVN_DEFAULT_COMPRESSION_LEVEL) for network
+ * transmissions.
*
* @deprecated Provided for backward compatibility with the 1.6 API.
*/
Modified: subversion/branches/performance/subversion/include/svn_string.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_string.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_string.h (original)
+++ subversion/branches/performance/subversion/include/svn_string.h Sun Feb 20 07:45:48 2011
@@ -372,6 +372,13 @@ svn_cstring_split_append(apr_array_heade
svn_boolean_t
svn_cstring_match_glob_list(const char *str, const apr_array_header_t *list);
+/** Return @c TRUE iff @a str exactly matches any of the elements of @a list.
+ *
+ * @since new in 1.7
+ */
+svn_boolean_t
+svn_cstring_match_list(const char *str, const apr_array_header_t *list);
+
/**
* Return the number of line breaks in @a msg, allowing any kind of newline
* termination (CR, LF, CRLF, or LFCR), even inconsistent.
Modified: subversion/branches/performance/subversion/include/svn_types.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_types.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_types.h (original)
+++ subversion/branches/performance/subversion/include/svn_types.h Sun Feb 20 07:45:48 2011
@@ -839,6 +839,9 @@ typedef struct svn_log_entry_t
* value as changed_paths for compatibility with users assuming an older
* version.
*
+ * @note See http://svn.haxx.se/dev/archive-2010-08/0362.shtml for
+ * further explanation.
+ *
* @since New in 1.6.
*/
apr_hash_t *changed_paths2;
Modified: subversion/branches/performance/subversion/include/svn_wc.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_wc.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_wc.h (original)
+++ subversion/branches/performance/subversion/include/svn_wc.h Sun Feb 20 07:45:48 2011
@@ -200,7 +200,7 @@ typedef struct svn_wc_context_t svn_wc_c
*/
svn_error_t *
svn_wc_context_create(svn_wc_context_t **wc_ctx,
- svn_config_t *config,
+ const svn_config_t *config,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
@@ -2569,9 +2569,9 @@ svn_wc_text_modified_p(svn_boolean_t *mo
*/
svn_error_t *
svn_wc_props_modified_p2(svn_boolean_t *modified_p,
- svn_wc_context_t* wc_ctx,
+ svn_wc_context_t *wc_ctx,
const char *local_abspath,
- apr_pool_t *scratch_pool);
+ apr_pool_t *scratch_pool);
/** Similar to svn_wc_props_modified_p2(), but with a relative path and
* adm_access baton.
Modified: subversion/branches/performance/subversion/libsvn_client/commit_util.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/commit_util.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/commit_util.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/commit_util.c Sun Feb 20 07:45:48 2011
@@ -242,10 +242,7 @@ add_lock_token(const char *local_abspath
* information in its parent dir is the only indication that the node
* is under version control. This function is necessary for this
* particular case. In all other cases, this simply bails out a little
- * bit earlier.
- *
- * Note: Tree-conflicts info can only be found in "THIS_DIR" entries,
- * where each THIS_DIR will only hold tree-conflicts on its children. */
+ * bit earlier. */
static svn_error_t *
bail_on_tree_conflicted_children(svn_wc_context_t *wc_ctx,
const char *local_abspath,
Modified: subversion/branches/performance/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/export.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/export.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/export.c Sun Feb 20 07:45:48 2011
@@ -900,9 +900,10 @@ close_file(void *file_baton,
actual_checksum = svn_checksum__from_digest(fb->text_digest,
svn_checksum_md5, pool);
- SVN_ERR(svn_checksum_mismatch_err(text_checksum, actual_checksum, pool,
- _("Checksum mismatch for '%s'"),
- svn_dirent_local_style(fb->path, pool)));
+ if (!svn_checksum_match(text_checksum, actual_checksum))
+ return svn_checksum_mismatch_err(text_checksum, actual_checksum, pool,
+ _("Checksum mismatch for '%s'"),
+ svn_dirent_local_style(fb->path, pool));
if ((! fb->eol_style_val) && (! fb->keywords_val) && (! fb->special))
{
Modified: subversion/branches/performance/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/externals.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/externals.c Sun Feb 20 07:45:48 2011
@@ -36,6 +36,7 @@
#include "svn_error.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
+#include "svn_props.h"
#include "svn_config.h"
#include "client.h"
@@ -593,7 +594,7 @@ resolve_relative_external_url(svn_wc_ext
apr_pstrndup(pool, url, num_leading_slashes),
svn_relpath_canonicalize(url + num_leading_slashes,
pool),
- NULL);
+ (char*)NULL);
}
else
{
@@ -696,7 +697,7 @@ resolve_relative_external_url(svn_wc_ext
SVN_ERR(uri_scheme(&scheme, repos_root_url, pool));
item->url = svn_uri_canonicalize(apr_pstrcat(pool, scheme, ":",
- url, NULL), pool);
+ url, (char *)NULL), pool);
return SVN_NO_ERROR;
}
@@ -1424,33 +1425,36 @@ svn_client__external_info_gatherer(void
}
-/* Callback of type svn_wc_external_update_t. Just squirrels away an
+/* An implementation of svn_wc__proplist_receiver_t. Just squirrels away an
svn:externals property value into BATON (which is an apr_hash_t *
keyed on local absolute path). */
static svn_error_t *
-externals_update_func(void *baton,
- const char *local_abspath,
- const svn_string_t *old_val,
- const svn_string_t *new_val,
- svn_depth_t depth,
- apr_pool_t *scratch_pool)
+externals_crawl_proplist_receiver(void *baton,
+ const char *local_abspath,
+ apr_hash_t *props,
+ apr_pool_t *scratch_pool)
{
- apr_hash_t *externals_hash = baton;
- apr_pool_t *hash_pool = apr_hash_pool_get(externals_hash);
+ apr_hash_index_t *hi;
+ apr_hash_t *externals_hash = (apr_hash_t*)baton;
- apr_hash_set(externals_hash, apr_pstrdup(hash_pool, local_abspath),
- APR_HASH_KEY_STRING, svn_string_dup(new_val, hash_pool));
- return SVN_NO_ERROR;
-}
+ for (hi = apr_hash_first(scratch_pool, props);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *propname;
+ propname = svn__apr_hash_index_key(hi);
+ if (strcmp(propname, SVN_PROP_EXTERNALS) == 0)
+ {
+ apr_pool_t *hash_pool = apr_hash_pool_get(externals_hash);
+ svn_string_t *propval = svn__apr_hash_index_val(hi);
+
+ apr_hash_set(externals_hash, apr_pstrdup(hash_pool, local_abspath),
+ APR_HASH_KEY_STRING, svn_string_dup(propval, hash_pool));
+ break;
+ }
+ }
-/* Callback of type svn_wc_status_func4_t. Does nothing. */
-static svn_error_t *
-status_noop_func(void *baton,
- const char *local_abspath,
- const svn_wc_status3_t *status,
- apr_pool_t *scratch_pool)
-{
return SVN_NO_ERROR;
}
@@ -1465,12 +1469,12 @@ svn_client__crawl_for_externals(apr_hash
{
apr_hash_t *externals_hash = apr_hash_make(result_pool);
- /* Do a status run just to harvest externals definitions. */
- SVN_ERR(svn_wc_walk_status(ctx->wc_ctx, local_abspath, depth,
- FALSE, FALSE, NULL, status_noop_func, NULL,
- externals_update_func, externals_hash,
- ctx->cancel_func, ctx->cancel_baton,
- scratch_pool));
+ SVN_ERR(svn_wc__prop_list_recursive(ctx->wc_ctx, local_abspath, depth,
+ externals_crawl_proplist_receiver,
+ externals_hash,
+ ctx->cancel_func,
+ ctx->cancel_baton,
+ scratch_pool));
*externals_p = externals_hash;
return SVN_NO_ERROR;
Modified: subversion/branches/performance/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/patch.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/patch.c Sun Feb 20 07:45:48 2011
@@ -2744,23 +2744,32 @@ svn_client_patch(const char *patch_abspa
if (svn_path_is_url(local_abspath))
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("'%s' is not a local path"), local_abspath);
+ _("'%s' is not a local path"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
SVN_ERR(svn_io_check_path(patch_abspath, &kind, scratch_pool));
if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("'%s' does not exist"), patch_abspath);
+ _("'%s' does not exist"),
+ svn_dirent_dirname(patch_abspath, scratch_pool));
if (kind != svn_node_file)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("'%s' is not a file"), patch_abspath);
+ _("'%s' is not a file"),
+ svn_dirent_local_style(patch_abspath,
+ scratch_pool));
SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("'%s' does not exist"), local_abspath);
+ _("'%s' does not exist"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
if (kind != svn_node_dir)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("'%s' is not a directory"), local_abspath);
+ _("'%s' is not a directory"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
baton.patch_abspath = patch_abspath;
baton.abs_wc_path = local_abspath;
Modified: subversion/branches/performance/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/relocate.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/relocate.c Sun Feb 20 07:45:48 2011
@@ -157,6 +157,7 @@ relocate_externals(const char *local_abs
APR_ARRAY_IDX(ext_desc, i, svn_wc_external_item2_t *);
const char *target_repos_root_url;
const char *target_abspath;
+ svn_error_t *err;
svn_pool_clear(iterpool);
@@ -181,8 +182,19 @@ relocate_externals(const char *local_abs
ext_item->target_dir,
iterpool),
iterpool));
- SVN_ERR(svn_client_root_url_from_path(&target_repos_root_url,
- target_abspath, ctx, iterpool));
+ err = svn_client_root_url_from_path(&target_repos_root_url,
+ target_abspath, ctx, iterpool);
+
+ /* Ignore externals that aren't present in the working copy.
+ * This can happen if an external is deleted from disk accidentally,
+ * or if an external is configured on a locally added directory. */
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ continue;
+ }
+ else
+ SVN_ERR(err);
if (strcmp(target_repos_root_url, old_parent_repos_root_url) == 0)
SVN_ERR(svn_client_relocate2(target_abspath,
Modified: subversion/branches/performance/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/update.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/update.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/update.c Sun Feb 20 07:45:48 2011
@@ -44,6 +44,58 @@
/*** Code. ***/
+/* Helper function to fix issue #2267,
+ * "support svn:externals on locally added directories".
+ *
+ * Crawl all externals beneath ANCHOR_ABSPATH (this is cheap because we're
+ * only crawling the WC DB itself). If there are externals within the
+ * REQUESTED_DEPTH that weren't already picked up while we were crawling
+ * the BASE tree, add them to the EXTERNALS_NEW hash with ambient depth
+ * infinity. Facilitates populating externals in locally added directories.
+ *
+ * ### This is a bit of a hack. We should try to find a better solution
+ * ### to this problem. */
+static svn_error_t *
+gather_externals_in_locally_added_dirs(apr_hash_t *externals_new,
+ apr_hash_t *ambient_depths,
+ const char *anchor_abspath,
+ svn_depth_t requested_depth,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *all_externals;
+ apr_hash_index_t *hi;
+
+ /* If there was no requested depth for this operation, use infinity.
+ * svn_client__crawl_for_externals() doesn't like depth 'unknown'. */
+ if (requested_depth == svn_depth_unknown)
+ requested_depth = svn_depth_infinity;
+
+ SVN_ERR(svn_client__crawl_for_externals(&all_externals, anchor_abspath,
+ requested_depth, ctx, scratch_pool,
+ scratch_pool));
+
+ for (hi = apr_hash_first(scratch_pool, all_externals);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *local_abspath = svn__apr_hash_index_key(hi);
+
+ if (! apr_hash_get(externals_new, local_abspath, APR_HASH_KEY_STRING))
+ {
+ apr_pool_t *hash_pool = apr_hash_pool_get(externals_new);
+ svn_string_t *propval = svn__apr_hash_index_val(hi);
+
+ apr_hash_set(externals_new, local_abspath, APR_HASH_KEY_STRING,
+ apr_pstrdup(hash_pool, propval->data));
+ apr_hash_set(ambient_depths, local_abspath, APR_HASH_KEY_STRING,
+ svn_depth_to_word(svn_depth_infinity));
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* This is a helper for svn_client__update_internal(), which see for
an explanation of most of these parameters. Some stuff that's
unique is as follows:
@@ -250,6 +302,10 @@ update_internal(svn_revnum_t *result_rev
the primary operation. */
if (SVN_DEPTH_IS_RECURSIVE(depth) && (! ignore_externals))
{
+ SVN_ERR(gather_externals_in_locally_added_dirs(efb.externals_new,
+ efb.ambient_depths,
+ anchor_abspath,
+ depth, ctx, pool));
SVN_ERR(svn_client__handle_externals(efb.externals_old,
efb.externals_new,
efb.ambient_depths,
Modified: subversion/branches/performance/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_delta/svndiff.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/performance/subversion/libsvn_delta/svndiff.c Sun Feb 20 07:45:48 2011
@@ -309,7 +309,7 @@ svn_txdelta_to_svndiff2(svn_txdelta_wind
apr_pool_t *pool)
{
svn_txdelta_to_svndiff3(handler, handler_baton, output,
- svndiff_version, SVNDIFF1_COMPRESS_LEVEL, pool);
+ svndiff_version, SVN_DEFAULT_COMPRESSION_LEVEL, pool);
}
void
@@ -319,7 +319,7 @@ svn_txdelta_to_svndiff(svn_stream_t *out
void **handler_baton)
{
svn_txdelta_to_svndiff3(handler, handler_baton, output,
- 0, SVNDIFF1_COMPRESS_LEVEL, pool);
+ 0, SVN_DEFAULT_COMPRESSION_LEVEL, pool);
}
Modified: subversion/branches/performance/subversion/libsvn_diff/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/deprecated.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/deprecated.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/deprecated.c Sun Feb 20 07:45:48 2011
@@ -41,6 +41,106 @@
/*** Code. ***/
+struct fns_wrapper_baton
+{
+ /* We put the old baton in front of this one, so that we can still use
+ this baton in place of the old. This prevents us from having to
+ implement simple wrappers around each member of diff_fns_t. */
+ void *old_baton;
+ const svn_diff_fns_t *vtable;
+};
+
+static svn_error_t *
+datasources_open(void *baton,
+ apr_off_t *prefix_lines,
+ apr_off_t *suffix_lines,
+ const svn_diff_datasource_e *datasources,
+ apr_size_t datasource_len)
+{
+ struct fns_wrapper_baton *fwb = baton;
+ apr_size_t i;
+
+ /* Just iterate over the datasources, using the old singular version. */
+ for (i = 0; i < datasource_len; i++)
+ {
+ SVN_ERR(fwb->vtable->datasource_open(fwb->old_baton, datasources[i]));
+ }
+
+ /* Don't claim any prefix or suffix matches. */
+ *prefix_lines = 0;
+ *suffix_lines = 0;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+datasource_close(void *baton,
+ svn_diff_datasource_e datasource)
+{
+ struct fns_wrapper_baton *fwb = baton;
+ return fwb->vtable->datasource_close(fwb->old_baton, datasource);
+}
+
+static svn_error_t *
+datasource_get_next_token(apr_uint32_t *hash,
+ void **token,
+ void *baton,
+ svn_diff_datasource_e datasource)
+{
+ struct fns_wrapper_baton *fwb = baton;
+ return fwb->vtable->datasource_get_next_token(hash, token, fwb->old_baton,
+ datasource);
+}
+
+static svn_error_t *
+token_compare(void *baton,
+ void *ltoken,
+ void *rtoken,
+ int *compare)
+{
+ struct fns_wrapper_baton *fwb = baton;
+ return fwb->vtable->token_compare(fwb->old_baton, ltoken, rtoken, compare);
+}
+
+static void
+token_discard(void *baton,
+ void *token)
+{
+ struct fns_wrapper_baton *fwb = baton;
+ fwb->vtable->token_discard(fwb->old_baton, token);
+}
+
+static void
+token_discard_all(void *baton)
+{
+ struct fns_wrapper_baton *fwb = baton;
+ fwb->vtable->token_discard_all(fwb->old_baton);
+}
+
+
+static void
+wrap_diff_fns(svn_diff_fns2_t **diff_fns2,
+ struct fns_wrapper_baton **baton2,
+ const svn_diff_fns_t *diff_fns,
+ void *baton,
+ apr_pool_t *result_pool)
+{
+ /* Initialize the return vtable. */
+ *diff_fns2 = apr_palloc(result_pool, sizeof(**diff_fns2));
+
+ (*diff_fns2)->datasources_open = datasources_open;
+ (*diff_fns2)->datasource_close = datasource_close;
+ (*diff_fns2)->datasource_get_next_token = datasource_get_next_token;
+ (*diff_fns2)->token_compare = token_compare;
+ (*diff_fns2)->token_discard = token_discard;
+ (*diff_fns2)->token_discard_all = token_discard_all;
+
+ /* Initialize the wrapper baton. */
+ *baton2 = apr_palloc(result_pool, sizeof (**baton2));
+ (*baton2)->old_baton = baton;
+ (*baton2)->vtable = diff_fns;
+}
+
/*** From diff_file.c ***/
svn_error_t *
@@ -142,3 +242,48 @@ svn_diff_file_output_merge(svn_stream_t
style,
pool);
}
+
+
+/*** From diff.c ***/
+svn_error_t *
+svn_diff_diff(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns_t *vtable,
+ apr_pool_t *pool)
+{
+ svn_diff_fns2_t *diff_fns2;
+ struct fns_wrapper_baton *fwb;
+
+ wrap_diff_fns(&diff_fns2, &fwb, vtable, diff_baton, pool);
+ return svn_diff_diff_2(diff, fwb, diff_fns2, pool);
+}
+
+
+/*** From diff3.c ***/
+svn_error_t *
+svn_diff_diff3(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns_t *vtable,
+ apr_pool_t *pool)
+{
+ svn_diff_fns2_t *diff_fns2;
+ struct fns_wrapper_baton *fwb;
+
+ wrap_diff_fns(&diff_fns2, &fwb, vtable, diff_baton, pool);
+ return svn_diff_diff3_2(diff, fwb, diff_fns2, pool);
+}
+
+
+/*** From diff4.c ***/
+svn_error_t *
+svn_diff_diff4(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns_t *vtable,
+ apr_pool_t *pool)
+{
+ svn_diff_fns2_t *diff_fns2;
+ struct fns_wrapper_baton *fwb;
+
+ wrap_diff_fns(&diff_fns2, &fwb, vtable, diff_baton, pool);
+ return svn_diff_diff4_2(diff, fwb, diff_fns2, pool);
+}
Modified: subversion/branches/performance/subversion/libsvn_diff/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/diff.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/diff.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/diff.c Sun Feb 20 07:45:48 2011
@@ -98,16 +98,20 @@ svn_diff__diff(svn_diff__lcs_t *lcs,
svn_error_t *
-svn_diff_diff(svn_diff_t **diff,
- void *diff_baton,
- const svn_diff_fns_t *vtable,
- apr_pool_t *pool)
+svn_diff_diff_2(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns2_t *vtable,
+ apr_pool_t *pool)
{
svn_diff__tree_t *tree;
svn_diff__position_t *position_list[2];
+ svn_diff_datasource_e datasource[] = {svn_diff_datasource_original,
+ svn_diff_datasource_modified};
svn_diff__lcs_t *lcs;
apr_pool_t *subpool;
apr_pool_t *treepool;
+ apr_off_t prefix_lines = 0;
+ apr_off_t suffix_lines = 0;
*diff = NULL;
@@ -116,17 +120,22 @@ svn_diff_diff(svn_diff_t **diff,
svn_diff__tree_create(&tree, treepool);
+ SVN_ERR(vtable->datasources_open(diff_baton, &prefix_lines, &suffix_lines,
+ datasource, 2));
+
/* Insert the data into the tree */
SVN_ERR(svn_diff__get_tokens(&position_list[0],
tree,
diff_baton, vtable,
svn_diff_datasource_original,
+ prefix_lines,
subpool));
SVN_ERR(svn_diff__get_tokens(&position_list[1],
tree,
diff_baton, vtable,
svn_diff_datasource_modified,
+ prefix_lines,
subpool));
/* The cool part is that we don't need the tokens anymore.
@@ -139,7 +148,8 @@ svn_diff_diff(svn_diff_t **diff,
svn_pool_destroy(treepool);
/* Get the lcs */
- lcs = svn_diff__lcs(position_list[0], position_list[1], subpool);
+ lcs = svn_diff__lcs(position_list[0], position_list[1], prefix_lines,
+ suffix_lines, subpool);
/* Produce the diff */
*diff = svn_diff__diff(lcs, 1, 1, TRUE, pool);
Modified: subversion/branches/performance/subversion/libsvn_diff/diff.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/diff.h?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/diff.h (original)
+++ subversion/branches/performance/subversion/libsvn_diff/diff.h Sun Feb 20 07:45:48 2011
@@ -91,6 +91,8 @@ typedef enum svn_diff__normalize_state_t
svn_diff__lcs_t *
svn_diff__lcs(svn_diff__position_t *position_list1, /* pointer to tail (ring) */
svn_diff__position_t *position_list2, /* pointer to tail (ring) */
+ apr_off_t prefix_lines,
+ apr_off_t suffix_lines,
apr_pool_t *pool);
@@ -109,8 +111,9 @@ svn_error_t *
svn_diff__get_tokens(svn_diff__position_t **position_list,
svn_diff__tree_t *tree,
void *diff_baton,
- const svn_diff_fns_t *vtable,
+ const svn_diff_fns2_t *vtable,
svn_diff_datasource_e datasource,
+ apr_off_t prefix_lines,
apr_pool_t *pool);
Modified: subversion/branches/performance/subversion/libsvn_diff/diff3.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/diff3.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/diff3.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/diff3.c Sun Feb 20 07:45:48 2011
@@ -173,7 +173,7 @@ svn_diff__resolve_conflict(svn_diff_t *h
position[1]->next = start_position[1];
}
- *lcs_ref = svn_diff__lcs(position[0], position[1],
+ *lcs_ref = svn_diff__lcs(position[0], position[1], 0, 0,
subpool);
/* Fix up the EOF lcs element in case one of
@@ -244,17 +244,22 @@ svn_diff__resolve_conflict(svn_diff_t *h
svn_error_t *
-svn_diff_diff3(svn_diff_t **diff,
- void *diff_baton,
- const svn_diff_fns_t *vtable,
- apr_pool_t *pool)
+svn_diff_diff3_2(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns2_t *vtable,
+ apr_pool_t *pool)
{
svn_diff__tree_t *tree;
svn_diff__position_t *position_list[3];
+ svn_diff_datasource_e datasource[] = {svn_diff_datasource_original,
+ svn_diff_datasource_modified,
+ svn_diff_datasource_latest};
svn_diff__lcs_t *lcs_om;
svn_diff__lcs_t *lcs_ol;
apr_pool_t *subpool;
apr_pool_t *treepool;
+ apr_off_t prefix_lines = 0;
+ apr_off_t suffix_lines = 0;
*diff = NULL;
@@ -263,22 +268,28 @@ svn_diff_diff3(svn_diff_t **diff,
svn_diff__tree_create(&tree, treepool);
+ SVN_ERR(vtable->datasources_open(diff_baton, &prefix_lines, &suffix_lines,
+ datasource, 3));
+
SVN_ERR(svn_diff__get_tokens(&position_list[0],
tree,
diff_baton, vtable,
svn_diff_datasource_original,
+ prefix_lines,
subpool));
SVN_ERR(svn_diff__get_tokens(&position_list[1],
tree,
diff_baton, vtable,
svn_diff_datasource_modified,
+ prefix_lines,
subpool));
SVN_ERR(svn_diff__get_tokens(&position_list[2],
tree,
diff_baton, vtable,
svn_diff_datasource_latest,
+ prefix_lines,
subpool));
/* Get rid of the tokens, we don't need them to calc the diff */
@@ -289,10 +300,10 @@ svn_diff_diff3(svn_diff_t **diff,
svn_pool_destroy(treepool);
/* Get the lcs for original-modified and original-latest */
- lcs_om = svn_diff__lcs(position_list[0], position_list[1],
- subpool);
- lcs_ol = svn_diff__lcs(position_list[0], position_list[2],
- subpool);
+ lcs_om = svn_diff__lcs(position_list[0], position_list[1], prefix_lines,
+ suffix_lines, subpool);
+ lcs_ol = svn_diff__lcs(position_list[0], position_list[2], prefix_lines,
+ suffix_lines, subpool);
/* Produce a merged diff */
{
@@ -324,7 +335,7 @@ svn_diff_diff3(svn_diff_t **diff,
}
else
{
- sentinel_position[0].offset = 1;
+ sentinel_position[0].offset = prefix_lines + 1;
sentinel_position[0].next = NULL;
position_list[1] = &sentinel_position[0];
}
@@ -338,7 +349,7 @@ svn_diff_diff3(svn_diff_t **diff,
}
else
{
- sentinel_position[1].offset = 1;
+ sentinel_position[1].offset = prefix_lines + 1;
sentinel_position[1].next = NULL;
position_list[2] = &sentinel_position[1];
}
Modified: subversion/branches/performance/subversion/libsvn_diff/diff4.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/diff4.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/diff4.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/diff4.c Sun Feb 20 07:45:48 2011
@@ -166,13 +166,17 @@ adjust_diff(svn_diff_t *diff, svn_diff_t
}
svn_error_t *
-svn_diff_diff4(svn_diff_t **diff,
- void *diff_baton,
- const svn_diff_fns_t *vtable,
- apr_pool_t *pool)
+svn_diff_diff4_2(svn_diff_t **diff,
+ void *diff_baton,
+ const svn_diff_fns2_t *vtable,
+ apr_pool_t *pool)
{
svn_diff__tree_t *tree;
svn_diff__position_t *position_list[4];
+ svn_diff_datasource_e datasource[] = {svn_diff_datasource_original,
+ svn_diff_datasource_modified,
+ svn_diff_datasource_latest,
+ svn_diff_datasource_ancestor};
svn_diff__lcs_t *lcs_ol;
svn_diff__lcs_t *lcs_adjust;
svn_diff_t *diff_ol;
@@ -181,6 +185,8 @@ svn_diff_diff4(svn_diff_t **diff,
apr_pool_t *subpool;
apr_pool_t *subpool2;
apr_pool_t *subpool3;
+ apr_off_t prefix_lines = 0;
+ apr_off_t suffix_lines = 0;
*diff = NULL;
@@ -190,28 +196,35 @@ svn_diff_diff4(svn_diff_t **diff,
svn_diff__tree_create(&tree, subpool3);
+ SVN_ERR(vtable->datasources_open(diff_baton, &prefix_lines, &suffix_lines,
+ datasource, 4));
+
SVN_ERR(svn_diff__get_tokens(&position_list[0],
tree,
diff_baton, vtable,
svn_diff_datasource_original,
+ prefix_lines,
subpool2));
SVN_ERR(svn_diff__get_tokens(&position_list[1],
tree,
diff_baton, vtable,
svn_diff_datasource_modified,
+ prefix_lines,
subpool));
SVN_ERR(svn_diff__get_tokens(&position_list[2],
tree,
diff_baton, vtable,
svn_diff_datasource_latest,
+ prefix_lines,
subpool));
SVN_ERR(svn_diff__get_tokens(&position_list[3],
tree,
diff_baton, vtable,
svn_diff_datasource_ancestor,
+ prefix_lines,
subpool2));
/* Get rid of the tokens, we don't need them to calc the diff */
@@ -222,7 +235,8 @@ svn_diff_diff4(svn_diff_t **diff,
svn_pool_clear(subpool3);
/* Get the lcs for original - latest */
- lcs_ol = svn_diff__lcs(position_list[0], position_list[2], subpool3);
+ lcs_ol = svn_diff__lcs(position_list[0], position_list[2], prefix_lines,
+ suffix_lines, subpool3);
diff_ol = svn_diff__diff(lcs_ol, 1, 1, TRUE, pool);
svn_pool_clear(subpool3);
@@ -243,7 +257,8 @@ svn_diff_diff4(svn_diff_t **diff,
/* Get the lcs for common ancestor - original
* Do reverse adjustements
*/
- lcs_adjust = svn_diff__lcs(position_list[3], position_list[2], subpool3);
+ lcs_adjust = svn_diff__lcs(position_list[3], position_list[2], prefix_lines,
+ suffix_lines, subpool3);
diff_adjust = svn_diff__diff(lcs_adjust, 1, 1, FALSE, subpool3);
adjust_diff(diff_ol, diff_adjust);
@@ -252,7 +267,8 @@ svn_diff_diff4(svn_diff_t **diff,
/* Get the lcs for modified - common ancestor
* Do forward adjustments
*/
- lcs_adjust = svn_diff__lcs(position_list[1], position_list[3], subpool3);
+ lcs_adjust = svn_diff__lcs(position_list[1], position_list[3], prefix_lines,
+ suffix_lines, subpool3);
diff_adjust = svn_diff__diff(lcs_adjust, 1, 1, FALSE, subpool3);
adjust_diff(diff_ol, diff_adjust);
Modified: subversion/branches/performance/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/diff_file.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/diff_file.c Sun Feb 20 07:45:48 2011
@@ -83,6 +83,10 @@ typedef struct svn_diff__file_baton_t
char *endp; /* next memory address after the current chunk */
svn_diff__normalize_state_t normalize_state;
+
+ /* Where the identical suffix starts in this datasource */
+ int suffix_start_chunk;
+ apr_off_t suffix_offset_in_chunk;
} files[4];
/* List of free tokens that may be reused. */
@@ -205,47 +209,593 @@ map_or_read_file(apr_file_t **file,
}
-/* Let FILE stand for the file_info struct element of BATON->files that is
- * indexed by DATASOURCE. BATON's type is (svn_diff__file_baton_t *).
- *
- * Open the file at FILE.path; initialize FILE.file, FILE.size, FILE.buffer,
- * FILE.curp and FILE.endp; allocate a buffer and read the first chunk.
- *
- * Implements svn_diff_fns_t::datasource_open. */
+/* For all files in the FILE array, increment the curp pointer. If a file
+ * points before the beginning of file, let it point at the first byte again.
+ * If the end of the current chunk is reached, read the next chunk in the
+ * buffer and point curp to the start of the chunk. If EOF is reached, set
+ * curp equal to endp to indicate EOF. */
+#define INCREMENT_POINTERS(all_files, files_len, pool) \
+ do { \
+ apr_size_t svn_macro__i; \
+ \
+ for (svn_macro__i = 0; svn_macro__i < (files_len); svn_macro__i++) \
+ { \
+ if ((all_files)[svn_macro__i].curp < (all_files)[svn_macro__i].endp - 1)\
+ (all_files)[svn_macro__i].curp++; \
+ else \
+ SVN_ERR(increment_chunk(&(all_files)[svn_macro__i], (pool))); \
+ } \
+ } while (0)
+
+
+/* For all files in the FILE array, decrement the curp pointer. If the
+ * start of a chunk is reached, read the previous chunk in the buffer and
+ * point curp to the last byte of the chunk. If the beginning of a FILE is
+ * reached, set chunk to -1 to indicate BOF. */
+#define DECREMENT_POINTERS(all_files, files_len, pool) \
+ do { \
+ apr_size_t svn_macro__i; \
+ \
+ for (svn_macro__i = 0; svn_macro__i < (files_len); svn_macro__i++) \
+ { \
+ if ((all_files)[svn_macro__i].curp > (all_files)[svn_macro__i].buffer) \
+ (all_files)[svn_macro__i].curp--; \
+ else \
+ SVN_ERR(decrement_chunk(&(all_files)[svn_macro__i], (pool))); \
+ } \
+ } while (0)
+
+
static svn_error_t *
-datasource_open(void *baton, svn_diff_datasource_e datasource)
+increment_chunk(struct file_info *file, apr_pool_t *pool)
{
- svn_diff__file_baton_t *file_baton = baton;
- struct file_info *file = &file_baton->files[datasource_to_index(datasource)];
- apr_finfo_t finfo;
apr_off_t length;
- char *curp;
- char *endp;
+ apr_off_t last_chunk = offset_to_chunk(file->size);
- SVN_ERR(svn_io_file_open(&file->file, file->path,
- APR_READ, APR_OS_DEFAULT, file_baton->pool));
+ if (file->chunk == -1)
+ {
+ /* We are at BOF (Beginning Of File). Point to first chunk/byte again. */
+ file->chunk = 0;
+ file->curp = file->buffer;
+ }
+ else if (file->chunk == last_chunk)
+ {
+ /* We are at the last chunk. Indicate EOF by setting curp == endp. */
+ file->curp = file->endp;
+ }
+ else
+ {
+ /* There are still chunks left. Read next chunk and reset pointers. */
+ file->chunk++;
+ length = file->chunk == last_chunk ?
+ offset_in_chunk(file->size) : CHUNK_SIZE;
+ SVN_ERR(read_chunk(file->file, file->path, file->buffer,
+ length, chunk_to_offset(file->chunk),
+ pool));
+ file->endp = file->buffer + length;
+ file->curp = file->buffer;
+ }
+
+ return SVN_NO_ERROR;
+}
- SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE,
- file->file, file_baton->pool));
- file->size = finfo.size;
- length = finfo.size > CHUNK_SIZE ? CHUNK_SIZE : finfo.size;
+static svn_error_t *
+decrement_chunk(struct file_info *file, apr_pool_t *pool)
+{
+ if (file->chunk == 0)
+ {
+ /* We are already at the first chunk. Indicate BOF (Beginning Of File)
+ by setting chunk = -1 and curp = endp - 1. Both conditions are
+ important. They help the increment step to catch the BOF situation
+ in an efficient way. */
+ file->chunk--;
+ file->curp = file->endp - 1;
+ }
+ else
+ {
+ /* Read previous chunk and reset pointers. */
+ file->chunk--;
+ SVN_ERR(read_chunk(file->file, file->path, file->buffer,
+ CHUNK_SIZE, chunk_to_offset(file->chunk),
+ pool));
+ file->endp = file->buffer + CHUNK_SIZE;
+ file->curp = file->endp - 1;
+ }
+
+ return SVN_NO_ERROR;
+}
- if (length == 0)
- return SVN_NO_ERROR;
- endp = curp = apr_palloc(file_baton->pool, (apr_size_t) length);
- endp += length;
+/* Check whether one of the FILEs has its pointers 'before' the beginning of
+ * the file (this can happen while scanning backwards). This is the case if
+ * one of them has chunk == -1. */
+static svn_boolean_t
+is_one_at_bof(struct file_info file[], apr_size_t file_len)
+{
+ apr_size_t i;
+
+ for (i = 0; i < file_len; i++)
+ if (file[i].chunk == -1)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Check whether one of the FILEs has its pointers at EOF (this is the case if
+ * one of them has curp == endp (this can only happen at the last chunk)) */
+static svn_boolean_t
+is_one_at_eof(struct file_info file[], apr_size_t file_len)
+{
+ apr_size_t i;
+
+ for (i = 0; i < file_len; i++)
+ if (file[i].curp == file[i].endp)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Quickly determine whether there is a eol char in CHUNK.
+ * (mainly copy-n-paste from eol.c#svn_eol__find_eol_start).
+ */
+#if SVN_UNALIGNED_ACCESS_IS_OK
+#if APR_SIZEOF_VOIDP == 8
+# define LOWER_7BITS_SET 0x7f7f7f7f7f7f7f7f
+# define BIT_7_SET 0x8080808080808080
+# define R_MASK 0x0a0a0a0a0a0a0a0a
+# define N_MASK 0x0d0d0d0d0d0d0d0d
+#else
+# define LOWER_7BITS_SET 0x7f7f7f7f
+# define BIT_7_SET 0x80808080
+# define R_MASK 0x0a0a0a0a
+# define N_MASK 0x0d0d0d0d
+#endif
+#endif
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+static svn_boolean_t contains_eol(apr_size_t chunk)
+{
+ apr_size_t r_test = chunk ^ R_MASK;
+ apr_size_t n_test = chunk ^ N_MASK;
+
+ r_test |= (r_test & LOWER_7BITS_SET) + LOWER_7BITS_SET;
+ n_test |= (n_test & LOWER_7BITS_SET) + LOWER_7BITS_SET;
+
+ return (r_test & n_test & BIT_7_SET) != BIT_7_SET;
+}
+#endif
+
+/* Find the prefix which is identical between all elements of the FILE array.
+ * Return the number of prefix lines in PREFIX_LINES. REACHED_ONE_EOF will be
+ * set to TRUE if one of the FILEs reached its end while scanning prefix,
+ * i.e. at least one file consisted entirely of prefix. Otherwise,
+ * REACHED_ONE_EOF is set to FALSE.
+ *
+ * After this function is finished, the buffers, chunks, curp's and endp's
+ * of the FILEs are set to point at the first byte after the prefix. */
+static svn_error_t *
+find_identical_prefix(svn_boolean_t *reached_one_eof, apr_off_t *prefix_lines,
+ struct file_info file[], apr_size_t file_len,
+ apr_pool_t *pool)
+{
+ svn_boolean_t had_cr = FALSE;
+ svn_boolean_t is_match;
+ apr_off_t lines = 0;
+ apr_size_t i;
+
+ for (i = 1, is_match = TRUE; i < file_len; i++)
+ is_match = is_match && *file[0].curp == *file[i].curp;
+ while (is_match)
+ {
+#if SVN_UNALIGNED_ACCESS_IS_OK
+ apr_ssize_t max_delta, delta;
+#endif /* SVN_UNALIGNED_ACCESS_IS_OK */
+
+ /* ### TODO: see if we can take advantage of
+ diff options like ignore_eol_style or ignore_space. */
+ /* check for eol, and count */
+ if (*file[0].curp == '\r')
+ {
+ lines++;
+ had_cr = TRUE;
+ }
+ else if (*file[0].curp == '\n' && !had_cr)
+ {
+ lines++;
+ }
+ else
+ {
+ had_cr = FALSE;
+ }
+
+ INCREMENT_POINTERS(file, file_len, pool);
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+
+ /* Try to advance as far as possible with machine-word granularity.
+ * Determine how far we may advance with chunky ops without reaching
+ * endp for any of the files.
+ * Signedness is important here if curp gets close to endp.
+ */
+ max_delta = file[0].endp - file[0].curp - sizeof(apr_size_t);
+ for (i = 1; i < file_len; i++)
+ {
+ delta = file[i].endp - file[i].curp - sizeof(apr_size_t);
+ if (delta < max_delta)
+ max_delta = delta;
+ }
+
+ is_match = TRUE;
+ for (delta = 0; delta < max_delta && is_match; delta += sizeof(apr_size_t))
+ {
+ apr_size_t chunk = *(const apr_size_t *)(file[0].curp + delta);
+ if (contains_eol(chunk))
+ break;
+
+ for (i = 1; i < file_len; i++)
+ if (chunk != *(const apr_size_t *)(file[i].curp + delta))
+ {
+ is_match = FALSE;
+ delta -= sizeof(apr_size_t);
+ break;
+ }
+ }
+
+ /* We either found a mismatch or an EOL at or shortly behind curp+delta
+ * or we cannot proceed with chunky ops without exceeding endp.
+ * In any way, everything up to curp + delta is equal and not an EOL.
+ */
+ for (i = 0; i < file_len; i++)
+ file[i].curp += delta;
+
+#endif
+
+ *reached_one_eof = is_one_at_eof(file, file_len);
+ if (*reached_one_eof)
+ break;
+ else
+ for (i = 1, is_match = TRUE; i < file_len; i++)
+ is_match = is_match && *file[0].curp == *file[i].curp;
+ }
+
+ if (had_cr)
+ {
+ /* Check if we ended in the middle of a \r\n for one file, but \r for
+ another. If so, back up one byte, so the next loop will back up
+ the entire line. Also decrement lines, since we counted one
+ too many for the \r. */
+ svn_boolean_t ended_at_nonmatching_newline = FALSE;
+ for (i = 0; i < file_len; i++)
+ ended_at_nonmatching_newline = ended_at_nonmatching_newline
+ || *file[i].curp == '\n';
+ if (ended_at_nonmatching_newline)
+ {
+ lines--;
+ DECREMENT_POINTERS(file, file_len, pool);
+ }
+ }
+
+ /* Back up one byte, so we point at the last identical byte */
+ DECREMENT_POINTERS(file, file_len, pool);
+
+ /* Back up to the last eol sequence (\n, \r\n or \r) */
+ while (!is_one_at_bof(file, file_len) &&
+ *file[0].curp != '\n' && *file[0].curp != '\r')
+ DECREMENT_POINTERS(file, file_len, pool);
+
+ /* Slide one byte forward, to point past the eol sequence */
+ INCREMENT_POINTERS(file, file_len, pool);
+
+ *prefix_lines = lines;
+
+ return SVN_NO_ERROR;
+}
+
+
+/* The number of identical suffix lines to keep with the middle section. These
+ * lines are not eliminated as suffix, and can be picked up by the token
+ * parsing and lcs steps. This is mainly for backward compatibility with
+ * the previous diff (and blame) output (if there are multiple diff solutions,
+ * our lcs algorithm prefers taking common lines from the start, rather than
+ * from the end. By giving it back some suffix lines, we give it some wiggle
+ * room to find the exact same diff as before).
+ *
+ * The number 50 is more or less arbitrary, based on some real-world tests
+ * with big files (and then doubling the required number to be on the safe
+ * side). This has a negligible effect on the power of the optimization. */
+#ifndef SUFFIX_LINES_TO_KEEP
+#define SUFFIX_LINES_TO_KEEP 50
+#endif
+
+/* Find the suffix which is identical between all elements of the FILE array.
+ * Return the number of suffix lines in SUFFIX_LINES.
+ *
+ * Before this function is called the FILEs' pointers and chunks should be
+ * positioned right after the identical prefix (which is the case after
+ * find_identical_prefix), so we can determine where suffix scanning should
+ * ultimately stop. */
+static svn_error_t *
+find_identical_suffix(apr_off_t *suffix_lines, struct file_info file[],
+ apr_size_t file_len, apr_pool_t *pool)
+{
+ struct file_info file_for_suffix[4] = { { 0 } };
+ apr_off_t length[4];
+ apr_off_t suffix_min_chunk0;
+ apr_off_t suffix_min_offset0;
+ apr_off_t min_file_size;
+ int suffix_lines_to_keep = SUFFIX_LINES_TO_KEEP;
+ svn_boolean_t is_match, reached_prefix;
+ apr_off_t lines = 0;
+ svn_boolean_t had_cr, had_nl;
+ apr_size_t i;
+
+ /* Initialize file_for_suffix[].
+ Read last chunk, position curp at last byte. */
+ for (i = 0; i < file_len; i++)
+ {
+ file_for_suffix[i].path = file[i].path;
+ file_for_suffix[i].file = file[i].file;
+ file_for_suffix[i].size = file[i].size;
+ file_for_suffix[i].chunk =
+ (int) offset_to_chunk(file_for_suffix[i].size); /* last chunk */
+ length[i] = offset_in_chunk(file_for_suffix[i].size);
+ if (file_for_suffix[i].chunk == file[i].chunk)
+ {
+ /* Prefix ended in last chunk, so we can reuse the prefix buffer */
+ file_for_suffix[i].buffer = file[i].buffer;
+ }
+ else
+ {
+ /* There is at least more than 1 chunk,
+ so allocate full chunk size buffer */
+ file_for_suffix[i].buffer = apr_palloc(pool, CHUNK_SIZE);
+ SVN_ERR(read_chunk(file_for_suffix[i].file, file_for_suffix[i].path,
+ file_for_suffix[i].buffer, length[i],
+ chunk_to_offset(file_for_suffix[i].chunk),
+ pool));
+ }
+ file_for_suffix[i].endp = file_for_suffix[i].buffer + length[i];
+ file_for_suffix[i].curp = file_for_suffix[i].endp - 1;
+ }
+
+ /* Get the chunk and pointer offset (for file[0]) at which we should stop
+ scanning backward for the identical suffix, i.e. when we reach prefix. */
+ suffix_min_chunk0 = file[0].chunk;
+ suffix_min_offset0 = file[0].curp - file[0].buffer;
+
+ /* Compensate if other files are smaller than file[0] */
+ for (i = 1, min_file_size = file[0].size; i < file_len; i++)
+ if (file[i].size < min_file_size)
+ min_file_size = file[i].size;
+ if (file[0].size > min_file_size)
+ {
+ suffix_min_chunk0 += (file[0].size - min_file_size) / CHUNK_SIZE;
+ suffix_min_offset0 += (file[0].size - min_file_size) % CHUNK_SIZE;
+ }
+
+ /* Scan backwards until mismatch or until we reach the prefix. */
+ for (i = 1, is_match = TRUE; i < file_len; i++)
+ is_match = is_match
+ && *file_for_suffix[0].curp == *file_for_suffix[i].curp;
+ if (is_match && *file_for_suffix[0].curp != '\r'
+ && *file_for_suffix[0].curp != '\n')
+ /* Count an extra line for the last line not ending in an eol. */
+ lines++;
+
+ while (is_match)
+ {
+ /* Initialize the minimum pointer positions. */
+ const char *min_curp[4];
+#if SVN_UNALIGNED_ACCESS_IS_OK
+ svn_boolean_t can_read_word;
+#endif /* SVN_UNALIGNED_ACCESS_IS_OK */
+
+ /* ### TODO: see if we can take advantage of
+ diff options like ignore_eol_style or ignore_space. */
+ /* check for eol, and count */
+ if (*file_for_suffix[0].curp == '\n')
+ {
+ lines++;
+ had_nl = TRUE;
+ }
+ else if (*file_for_suffix[0].curp == '\r' && !had_nl)
+ {
+ lines++;
+ }
+ else
+ {
+ had_nl = FALSE;
+ }
+
+ DECREMENT_POINTERS(file_for_suffix, file_len, pool);
+
+
+ min_curp[0] = file_for_suffix[0].chunk == suffix_min_chunk0
+ ? file_for_suffix[0].buffer + suffix_min_offset0 + 1
+ : file_for_suffix[0].buffer + 1;
+ for (i = 1; i < file_len; i++)
+ min_curp[i] = file_for_suffix[i].buffer + 1;
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+
+ /* Scan quickly by reading with machine-word granularity. */
+ for (i = 0, can_read_word = TRUE; i < file_len; i++)
+ can_read_word = can_read_word
+ && ( file_for_suffix[i].curp - sizeof(apr_size_t)
+ >= min_curp[i]);
+ if (can_read_word)
+ {
+ do
+ {
+ apr_size_t chunk;
+ for (i = 0; i < file_len; i++)
+ file_for_suffix[i].curp -= sizeof(apr_size_t);
+
+ chunk = *(const apr_size_t *)(file_for_suffix[0].curp + 1);
+ if (contains_eol(chunk))
+ break;
+
+ for (i = 0, can_read_word = TRUE; i < file_len; i++)
+ can_read_word = can_read_word
+ && ( file_for_suffix[i].curp - sizeof(apr_size_t)
+ >= min_curp[i]);
+ for (i = 1, is_match = TRUE; i < file_len; i++)
+ is_match = is_match
+ && ( chunk
+ == *(const apr_size_t *)(file_for_suffix[i].curp + 1));
+ } while (can_read_word && is_match);
+
+ for (i = 0; i < file_len; i++)
+ file_for_suffix[i].curp += sizeof(apr_size_t);
+ }
+
+#endif
+
+ reached_prefix = file_for_suffix[0].chunk == suffix_min_chunk0
+ && (file_for_suffix[0].curp - file_for_suffix[0].buffer)
+ == suffix_min_offset0;
+ if (reached_prefix || is_one_at_bof(file_for_suffix, file_len))
+ break;
+
+ for (i = 1, is_match = TRUE; i < file_len; i++)
+ is_match = is_match
+ && *file_for_suffix[0].curp == *file_for_suffix[i].curp;
+ }
+
+ /* Slide one byte forward, to point at the first byte of identical suffix */
+ INCREMENT_POINTERS(file_for_suffix, file_len, pool);
+
+ /* Slide forward until we find an eol sequence to add the rest of the line
+ we're in. Then add SUFFIX_LINES_TO_KEEP more lines. Stop if at least
+ one file reaches its end. */
+ do
+ {
+ had_cr = FALSE;
+ while (!is_one_at_eof(file_for_suffix, file_len)
+ && *file_for_suffix[0].curp != '\n'
+ && *file_for_suffix[0].curp != '\r')
+ INCREMENT_POINTERS(file_for_suffix, file_len, pool);
+
+ /* Slide one or two more bytes, to point past the eol. */
+ if (!is_one_at_eof(file_for_suffix, file_len)
+ && *file_for_suffix[0].curp == '\r')
+ {
+ lines--;
+ had_cr = TRUE;
+ INCREMENT_POINTERS(file_for_suffix, file_len, pool);
+ }
+ if (!is_one_at_eof(file_for_suffix, file_len)
+ && *file_for_suffix[0].curp == '\n')
+ {
+ if (!had_cr)
+ lines--;
+ INCREMENT_POINTERS(file_for_suffix, file_len, pool);
+ }
+ }
+ while (!is_one_at_eof(file_for_suffix, file_len)
+ && suffix_lines_to_keep--);
+
+ if (is_one_at_eof(file_for_suffix, file_len))
+ lines = 0;
+
+ /* Save the final suffix information in the original file_info */
+ for (i = 0; i < file_len; i++)
+ {
+ file[i].suffix_start_chunk = file_for_suffix[i].chunk;
+ file[i].suffix_offset_in_chunk =
+ file_for_suffix[i].curp - file_for_suffix[i].buffer;
+ }
- file->buffer = file->curp = curp;
- file->endp = endp;
+ *suffix_lines = lines;
- return read_chunk(file->file, file->path,
- curp, length, 0, file_baton->pool);
+ return SVN_NO_ERROR;
}
-/* Implements svn_diff_fns_t::datasource_close */
+/* Let FILE stand for the array of file_info struct elements of BATON->files
+ * that are indexed by the elements of the DATASOURCE array.
+ * BATON's type is (svn_diff__file_baton_t *).
+ *
+ * For each file in the FILE array, open the file at FILE.path; initialize
+ * FILE.file, FILE.size, FILE.buffer, FILE.curp and FILE.endp; allocate a
+ * buffer and read the first chunk. Then find the prefix and suffix lines
+ * which are identical between all the files. Return the number of identical
+ * prefix lines in PREFIX_LINES, and the number of identical suffix lines in
+ * SUFFIX_LINES.
+ *
+ * Finding the identical prefix and suffix allows us to exclude those from the
+ * rest of the diff algorithm, which increases performance by reducing the
+ * problem space.
+ *
+ * Implements svn_diff_fns2_t::datasources_open. */
+static svn_error_t *
+datasources_open(void *baton,
+ apr_off_t *prefix_lines,
+ apr_off_t *suffix_lines,
+ const svn_diff_datasource_e *datasources,
+ apr_size_t datasources_len)
+{
+ svn_diff__file_baton_t *file_baton = baton;
+ struct file_info files[4];
+ apr_finfo_t finfo[4];
+ apr_off_t length[4];
+ svn_boolean_t reached_one_eof;
+ apr_size_t i;
+
+ /* Make sure prefix_lines and suffix_lines are set correctly, even if we
+ * exit early because one of the files is empty. */
+ *prefix_lines = 0;
+ *suffix_lines = 0;
+
+ /* Open datasources and read first chunk */
+ for (i = 0; i < datasources_len; i++)
+ {
+ struct file_info *file
+ = &file_baton->files[datasource_to_index(datasources[i])];
+ SVN_ERR(svn_io_file_open(&file->file, file->path,
+ APR_READ, APR_OS_DEFAULT, file_baton->pool));
+ SVN_ERR(svn_io_file_info_get(&finfo[i], APR_FINFO_SIZE,
+ file->file, file_baton->pool));
+ file->size = finfo[i].size;
+ length[i] = finfo[i].size > CHUNK_SIZE ? CHUNK_SIZE : finfo[i].size;
+ file->buffer = apr_palloc(file_baton->pool, (apr_size_t) length[i]);
+ SVN_ERR(read_chunk(file->file, file->path, file->buffer,
+ length[i], 0, file_baton->pool));
+ file->endp = file->buffer + length[i];
+ file->curp = file->buffer;
+ /* Set suffix_start_chunk to a guard value, so if suffix scanning is
+ * skipped because one of the files is empty, or because of
+ * reached_one_eof, we can still easily check for the suffix during
+ * token reading (datasource_get_next_token). */
+ file->suffix_start_chunk = -1;
+
+ files[i] = *file;
+ }
+
+ for (i = 0; i < datasources_len; i++)
+ if (length[i] == 0)
+ /* There will not be any identical prefix/suffix, so we're done. */
+ return SVN_NO_ERROR;
+
+ SVN_ERR(find_identical_prefix(&reached_one_eof, prefix_lines,
+ files, datasources_len, file_baton->pool));
+
+ if (!reached_one_eof)
+ /* No file consisted totally of identical prefix,
+ * so there may be some identical suffix. */
+ SVN_ERR(find_identical_suffix(suffix_lines, files, datasources_len,
+ file_baton->pool));
+
+ /* Copy local results back to baton. */
+ for (i = 0; i < datasources_len; i++)
+ file_baton->files[datasource_to_index(datasources[i])] = files[i];
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Implements svn_diff_fns2_t::datasource_close */
static svn_error_t *
datasource_close(void *baton, svn_diff_datasource_e datasource)
{
@@ -256,7 +806,7 @@ datasource_close(void *baton, svn_diff_d
return SVN_NO_ERROR;
}
-/* Implements svn_diff_fns_t::datasource_get_next_token */
+/* Implements svn_diff_fns2_t::datasource_get_next_token */
static svn_error_t *
datasource_get_next_token(apr_uint32_t *hash, void **token, void *baton,
svn_diff_datasource_e datasource)
@@ -286,7 +836,14 @@ datasource_get_next_token(apr_uint32_t *
return SVN_NO_ERROR;
}
- /* Get a new token */
+ /* Stop when we encounter the identical suffix. If suffix scanning was not
+ * performed, suffix_start_chunk will be -1, so this condition will never
+ * be true. */
+ if (file->chunk == file->suffix_start_chunk
+ && curp - file->buffer == file->suffix_offset_in_chunk)
+ return SVN_NO_ERROR;
+
+ /* Allocate a new token, or fetch one from the "reusable tokens" list. */
file_token = file_baton->tokens;
if (file_token)
{
@@ -388,7 +945,7 @@ datasource_get_next_token(apr_uint32_t *
#define COMPARE_CHUNK_SIZE 4096
-/* Implements svn_diff_fns_t::token_compare */
+/* Implements svn_diff_fns2_t::token_compare */
static svn_error_t *
token_compare(void *baton, void *token1, void *token2, int *compare)
{
@@ -509,19 +1066,20 @@ token_compare(void *baton, void *token1,
}
-/* Implements svn_diff_fns_t::token_discard */
+/* Implements svn_diff_fns2_t::token_discard */
static void
token_discard(void *baton, void *token)
{
svn_diff__file_baton_t *file_baton = baton;
svn_diff__file_token_t *file_token = token;
+ /* Prepend FILE_TOKEN to FILE_BATON->TOKENS, for reuse. */
file_token->next = file_baton->tokens;
file_baton->tokens = file_token;
}
-/* Implements svn_diff_fns_t::token_discard_all */
+/* Implements svn_diff_fns2_t::token_discard_all */
static void
token_discard_all(void *baton)
{
@@ -532,9 +1090,9 @@ token_discard_all(void *baton)
}
-static const svn_diff_fns_t svn_diff__file_vtable =
+static const svn_diff_fns2_t svn_diff__file_vtable =
{
- datasource_open,
+ datasources_open,
datasource_close,
datasource_get_next_token,
token_compare,
@@ -668,15 +1226,14 @@ svn_diff_file_diff_2(svn_diff_t **diff,
const svn_diff_file_options_t *options,
apr_pool_t *pool)
{
- svn_diff__file_baton_t baton;
+ svn_diff__file_baton_t baton = { 0 };
- memset(&baton, 0, sizeof(baton));
baton.options = options;
baton.files[0].path = original;
baton.files[1].path = modified;
baton.pool = svn_pool_create(pool);
- SVN_ERR(svn_diff_diff(diff, &baton, &svn_diff__file_vtable, pool));
+ SVN_ERR(svn_diff_diff_2(diff, &baton, &svn_diff__file_vtable, pool));
svn_pool_destroy(baton.pool);
return SVN_NO_ERROR;
@@ -690,16 +1247,15 @@ svn_diff_file_diff3_2(svn_diff_t **diff,
const svn_diff_file_options_t *options,
apr_pool_t *pool)
{
- svn_diff__file_baton_t baton;
+ svn_diff__file_baton_t baton = { 0 };
- memset(&baton, 0, sizeof(baton));
baton.options = options;
baton.files[0].path = original;
baton.files[1].path = modified;
baton.files[2].path = latest;
baton.pool = svn_pool_create(pool);
- SVN_ERR(svn_diff_diff3(diff, &baton, &svn_diff__file_vtable, pool));
+ SVN_ERR(svn_diff_diff3_2(diff, &baton, &svn_diff__file_vtable, pool));
svn_pool_destroy(baton.pool);
return SVN_NO_ERROR;
@@ -714,9 +1270,8 @@ svn_diff_file_diff4_2(svn_diff_t **diff,
const svn_diff_file_options_t *options,
apr_pool_t *pool)
{
- svn_diff__file_baton_t baton;
+ svn_diff__file_baton_t baton = { 0 };
- memset(&baton, 0, sizeof(baton));
baton.options = options;
baton.files[0].path = original;
baton.files[1].path = modified;
@@ -724,7 +1279,7 @@ svn_diff_file_diff4_2(svn_diff_t **diff,
baton.files[3].path = ancestor;
baton.pool = svn_pool_create(pool);
- SVN_ERR(svn_diff_diff4(diff, &baton, &svn_diff__file_vtable, pool));
+ SVN_ERR(svn_diff_diff4_2(diff, &baton, &svn_diff__file_vtable, pool));
svn_pool_destroy(baton.pool);
return SVN_NO_ERROR;
Modified: subversion/branches/performance/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/diff_memory.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/diff_memory.c Sun Feb 20 07:45:48 2011
@@ -88,16 +88,22 @@ datasource_to_index(svn_diff_datasource_
}
-/* Implements svn_diff_fns_t::datasource_open */
+/* Implements svn_diff_fns2_t::datasources_open */
static svn_error_t *
-datasource_open(void *baton, svn_diff_datasource_e datasource)
+datasources_open(void *baton,
+ apr_off_t *prefix_lines,
+ apr_off_t *suffix_lines,
+ const svn_diff_datasource_e *datasources,
+ apr_size_t datasources_len)
{
/* Do nothing: everything is already there and initialized to 0 */
+ *prefix_lines = 0;
+ *suffix_lines = 0;
return SVN_NO_ERROR;
}
-/* Implements svn_diff_fns_t::datasource_close */
+/* Implements svn_diff_fns2_t::datasource_close */
static svn_error_t *
datasource_close(void *baton, svn_diff_datasource_e datasource)
{
@@ -109,7 +115,7 @@ datasource_close(void *baton, svn_diff_d
}
-/* Implements svn_diff_fns_t::datasource_get_next_token */
+/* Implements svn_diff_fns2_t::datasource_get_next_token */
static svn_error_t *
datasource_get_next_token(apr_uint32_t *hash, void **token, void *baton,
svn_diff_datasource_e datasource)
@@ -138,7 +144,7 @@ datasource_get_next_token(apr_uint32_t *
return SVN_NO_ERROR;
}
-/* Implements svn_diff_fns_t::token_compare */
+/* Implements svn_diff_fns2_t::token_compare */
static svn_error_t *
token_compare(void *baton, void *token1, void *token2, int *result)
{
@@ -167,7 +173,7 @@ token_compare(void *baton, void *token1,
return SVN_NO_ERROR;
}
-/* Implements svn_diff_fns_t::token_discard */
+/* Implements svn_diff_fns2_t::token_discard */
static void
token_discard(void *baton, void *token)
{
@@ -175,7 +181,7 @@ token_discard(void *baton, void *token)
}
-/* Implements svn_diff_fns_t::token_discard_all */
+/* Implements svn_diff_fns2_t::token_discard_all */
static void
token_discard_all(void *baton)
{
@@ -187,9 +193,9 @@ token_discard_all(void *baton)
}
-static const svn_diff_fns_t svn_diff__mem_vtable =
+static const svn_diff_fns2_t svn_diff__mem_vtable =
{
- datasource_open,
+ datasources_open,
datasource_close,
datasource_get_next_token,
token_compare,
@@ -284,7 +290,7 @@ svn_diff_mem_string_diff(svn_diff_t **di
baton.normalization_options = options;
- return svn_diff_diff(diff, &baton, &svn_diff__mem_vtable, pool);
+ return svn_diff_diff_2(diff, &baton, &svn_diff__mem_vtable, pool);
}
svn_error_t *
@@ -304,7 +310,7 @@ svn_diff_mem_string_diff3(svn_diff_t **d
baton.normalization_options = options;
- return svn_diff_diff3(diff, &baton, &svn_diff__mem_vtable, pool);
+ return svn_diff_diff3_2(diff, &baton, &svn_diff__mem_vtable, pool);
}
@@ -327,7 +333,7 @@ svn_diff_mem_string_diff4(svn_diff_t **d
baton.normalization_options = options;
- return svn_diff_diff4(diff, &baton, &svn_diff__mem_vtable, pool);
+ return svn_diff_diff4_2(diff, &baton, &svn_diff__mem_vtable, pool);
}
Modified: subversion/branches/performance/subversion/libsvn_diff/lcs.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/lcs.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/lcs.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/lcs.c Sun Feb 20 07:45:48 2011
@@ -160,9 +160,36 @@ svn_diff__lcs_reverse(svn_diff__lcs_t *l
}
+/* Prepends a new lcs chunk for the amount of LINES at the given positions
+ * POS0_OFFSET and POS1_OFFSET to the given LCS chain, and returns it.
+ * This function assumes LINES > 0. */
+static svn_diff__lcs_t *
+prepend_lcs(svn_diff__lcs_t *lcs, apr_off_t lines,
+ apr_off_t pos0_offset, apr_off_t pos1_offset,
+ apr_pool_t *pool)
+{
+ svn_diff__lcs_t *new_lcs;
+
+ SVN_ERR_ASSERT_NO_RETURN(lines > 0);
+
+ new_lcs = apr_palloc(pool, sizeof(*new_lcs));
+ new_lcs->position[0] = apr_pcalloc(pool, sizeof(*new_lcs->position[0]));
+ new_lcs->position[0]->offset = pos0_offset;
+ new_lcs->position[1] = apr_pcalloc(pool, sizeof(*new_lcs->position[1]));
+ new_lcs->position[1]->offset = pos1_offset;
+ new_lcs->length = lines;
+ new_lcs->refcount = 1;
+ new_lcs->next = lcs;
+
+ return new_lcs;
+}
+
+
svn_diff__lcs_t *
svn_diff__lcs(svn_diff__position_t *position_list1, /* pointer to tail (ring) */
svn_diff__position_t *position_list2, /* pointer to tail (ring) */
+ apr_off_t prefix_lines,
+ apr_off_t suffix_lines,
apr_pool_t *pool)
{
int idx;
@@ -180,15 +207,29 @@ svn_diff__lcs(svn_diff__position_t *posi
*/
lcs = apr_palloc(pool, sizeof(*lcs));
lcs->position[0] = apr_pcalloc(pool, sizeof(*lcs->position[0]));
- lcs->position[0]->offset = position_list1 ? position_list1->offset + 1 : 1;
+ lcs->position[0]->offset = position_list1
+ ? position_list1->offset + suffix_lines + 1
+ : prefix_lines + suffix_lines + 1;
lcs->position[1] = apr_pcalloc(pool, sizeof(*lcs->position[1]));
- lcs->position[1]->offset = position_list2 ? position_list2->offset + 1 : 1;
+ lcs->position[1]->offset = position_list2
+ ? position_list2->offset + suffix_lines + 1
+ : prefix_lines + suffix_lines + 1;
lcs->length = 0;
lcs->refcount = 1;
lcs->next = NULL;
if (position_list1 == NULL || position_list2 == NULL)
- return lcs;
+ {
+ if (suffix_lines)
+ lcs = prepend_lcs(lcs, suffix_lines,
+ lcs->position[0]->offset - suffix_lines,
+ lcs->position[1]->offset - suffix_lines,
+ pool);
+ if (prefix_lines)
+ lcs = prepend_lcs(lcs, prefix_lines, 1, 1, pool);
+
+ return lcs;
+ }
/* Calculate length of both sequences to be compared */
length[0] = position_list1->offset - position_list1->next->offset + 1;
@@ -243,11 +284,21 @@ svn_diff__lcs(svn_diff__position_t *posi
}
while (fp[d].position[1] != &sentinel_position[1]);
- lcs->next = fp[d].lcs;
+ if (suffix_lines)
+ lcs->next = prepend_lcs(fp[d].lcs, suffix_lines,
+ lcs->position[0]->offset - suffix_lines,
+ lcs->position[1]->offset - suffix_lines,
+ pool);
+ else
+ lcs->next = fp[d].lcs;
+
lcs = svn_diff__lcs_reverse(lcs);
position_list1->next = sentinel_position[idx].next;
position_list2->next = sentinel_position[abs(1 - idx)].next;
- return lcs;
+ if (prefix_lines)
+ return prepend_lcs(lcs, prefix_lines, 1, 1, pool);
+ else
+ return lcs;
}
Modified: subversion/branches/performance/subversion/libsvn_diff/token.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/token.c?rev=1072522&r1=1072521&r2=1072522&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/token.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/token.c Sun Feb 20 07:45:48 2011
@@ -71,7 +71,7 @@ svn_diff__tree_create(svn_diff__tree_t *
static svn_error_t *
tree_insert_token(svn_diff__node_t **node, svn_diff__tree_t *tree,
void *diff_baton,
- const svn_diff_fns_t *vtable,
+ const svn_diff_fns2_t *vtable,
apr_uint32_t hash, void *token)
{
svn_diff__node_t *new_node;
@@ -137,8 +137,9 @@ svn_error_t *
svn_diff__get_tokens(svn_diff__position_t **position_list,
svn_diff__tree_t *tree,
void *diff_baton,
- const svn_diff_fns_t *vtable,
+ const svn_diff_fns2_t *vtable,
svn_diff_datasource_e datasource,
+ apr_off_t prefix_lines,
apr_pool_t *pool)
{
svn_diff__position_t *start_position;
@@ -151,11 +152,8 @@ svn_diff__get_tokens(svn_diff__position_
*position_list = NULL;
-
- SVN_ERR(vtable->datasource_open(diff_baton, datasource));
-
position_ref = &start_position;
- offset = 0;
+ offset = prefix_lines;
hash = 0; /* The callback fn doesn't need to touch it per se */
while (1)
{