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 2013/10/16 00:57:09 UTC
svn commit: r1532583 [6/10] - in /subversion/branches/fsfs-improvements: ./
build/ac-macros/ build/generator/ build/generator/templates/ build/win32/
contrib/client-side/emacs/ notes/ subversion/bindings/javahl/native/
subversion/bindings/javahl/src/or...
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_repos/authz.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_repos/authz.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_repos/authz.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_repos/authz.c Tue Oct 15 22:57:03 2013
@@ -854,23 +854,9 @@ authz_retrieve_config_repo(svn_config_t
return SVN_NO_ERROR;
}
-/* Given a PATH which might be a relative repo URL (^/), an absolute
- * local repo URL (file://), an absolute path outside of the repo
- * or a location in the Windows registry.
- *
- * Retrieve the configuration data that PATH points at and parse it into
- * CFG_P allocated in POOL.
- *
- * If PATH cannot be parsed as a config file then an error is returned. The
- * contents of CFG_P is then undefined. If MUST_EXIST is TRUE, a missing
- * authz file is also an error.
- *
- * REPOS_ROOT points at the root of the repos you are
- * going to apply the authz against, can be NULL if you are sure that you
- * don't have a repos relative URL in PATH. */
-static svn_error_t *
-authz_retrieve_config(svn_config_t **cfg_p, const char *path,
- svn_boolean_t must_exist, apr_pool_t *pool)
+svn_error_t *
+svn_repos__retrieve_config(svn_config_t **cfg_p, const char *path,
+ svn_boolean_t must_exist, apr_pool_t *pool)
{
if (svn_path_is_url(path))
{
@@ -943,7 +929,7 @@ svn_repos__authz_read(svn_authz_t **auth
/* Load the authz file */
if (accept_urls)
- SVN_ERR(authz_retrieve_config(&authz->cfg, path, must_exist, pool));
+ SVN_ERR(svn_repos__retrieve_config(&authz->cfg, path, must_exist, pool));
else
SVN_ERR(svn_config_read3(&authz->cfg, path, must_exist, TRUE, TRUE, pool));
@@ -954,8 +940,8 @@ svn_repos__authz_read(svn_authz_t **auth
/* Load the groups file */
if (accept_urls)
- SVN_ERR(authz_retrieve_config(&groups_cfg, groups_path, must_exist,
- pool));
+ SVN_ERR(svn_repos__retrieve_config(&groups_cfg, groups_path,
+ must_exist, pool));
else
SVN_ERR(svn_config_read3(&groups_cfg, groups_path, must_exist,
TRUE, TRUE, pool));
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_repos/commit.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_repos/commit.c Tue Oct 15 22:57:03 2013
@@ -1198,20 +1198,6 @@ move_cb(void *baton,
}
-/* This implements svn_editor_cb_rotate_t */
-static svn_error_t *
-rotate_cb(void *baton,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions,
- apr_pool_t *scratch_pool)
-{
- struct ev2_baton *eb = baton;
-
- SVN_ERR(svn_editor_rotate(eb->inner, relpaths, revisions));
- return SVN_NO_ERROR;
-}
-
-
/* This implements svn_editor_cb_complete_t */
static svn_error_t *
complete_cb(void *baton,
@@ -1333,7 +1319,6 @@ svn_repos__get_commit_ev2(svn_editor_t *
delete_cb,
copy_cb,
move_cb,
- rotate_cb,
complete_cb,
abort_cb
};
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_repos/deprecated.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_repos/deprecated.c Tue Oct 15 22:57:03 2013
@@ -472,6 +472,30 @@ svn_repos_fs_get_locks(apr_hash_t **lock
/*** From logs.c ***/
svn_error_t *
+svn_repos_get_logs4(svn_repos_t *repos,
+ const apr_array_header_t *paths,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ int limit,
+ svn_boolean_t discover_changed_paths,
+ svn_boolean_t strict_node_history,
+ svn_boolean_t include_merged_revisions,
+ const apr_array_header_t *revprops,
+ svn_repos_authz_func_t authz_read_func,
+ void *authz_read_baton,
+ svn_log_entry_receiver_t receiver,
+ void *receiver_baton,
+ apr_pool_t *pool)
+{
+ return svn_repos_get_logs5(repos, paths, start, end, limit,
+ discover_changed_paths, strict_node_history,
+ include_merged_revisions,
+ svn_move_behavior_no_moves, revprops,
+ authz_read_func, authz_read_baton,
+ receiver, receiver_baton, pool);
+}
+
+svn_error_t *
svn_repos_get_logs3(svn_repos_t *repos,
const apr_array_header_t *paths,
svn_revnum_t start,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_repos/dump.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_repos/dump.c Tue Oct 15 22:57:03 2013
@@ -38,6 +38,7 @@
#include "private/svn_mergeinfo_private.h"
#include "private/svn_fs_private.h"
+#include "private/svn_cache.h"
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
@@ -130,6 +131,13 @@ struct edit_baton
/* reusable buffer for writing file contents */
char buffer[SVN__STREAM_CHUNK_SIZE];
apr_size_t bufsize;
+
+ /* map nodeID -> node kind. May be NULL.
+ The key is the string representation of the node ID given in
+ directory entries. If we find an entry in this cache, the
+ respective node has already been verified as readable and being
+ of the type stored as value in the cache. */
+ svn_cache__t *verified_dirents_cache;
};
struct dir_baton
@@ -960,6 +968,7 @@ get_dump_editor(const svn_delta_editor_t
svn_revnum_t oldest_dumped_rev,
svn_boolean_t use_deltas,
svn_boolean_t verify,
+ svn_cache__t *verified_dirents_cache,
apr_pool_t *pool)
{
/* Allocate an edit baton to be stored in every directory baton.
@@ -984,6 +993,7 @@ get_dump_editor(const svn_delta_editor_t
eb->verify = verify;
eb->found_old_reference = found_old_reference;
eb->found_old_mergeinfo = found_old_mergeinfo;
+ eb->verified_dirents_cache = verified_dirents_cache;
/* Set up the editor. */
dump_editor->open_root = open_root;
@@ -1180,7 +1190,8 @@ svn_repos_dump_fs3(svn_repos_t *repos,
"", stream, &found_old_reference,
&found_old_mergeinfo, NULL,
notify_func, notify_baton,
- start_rev, use_deltas_for_rev, FALSE, subpool));
+ start_rev, use_deltas_for_rev, FALSE,
+ NULL, subpool));
/* Drive the editor in one way or another. */
SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, subpool));
@@ -1292,9 +1303,42 @@ verify_directory_entry(void *baton, cons
{
struct dir_baton *db = baton;
svn_fs_dirent_t *dirent = (svn_fs_dirent_t *)val;
- char *path = svn_relpath_join(db->path, (const char *)key, pool);
+ char *path;
apr_hash_t *dirents;
svn_filesize_t len;
+ svn_string_t *unparsed_id;
+
+ /* most directory entries will be unchanged from previous revs.
+ We should find those in the cache and they must match the
+ type defined in the DIRENT. */
+ if (db->edit_baton->verified_dirents_cache)
+ {
+ svn_node_kind_t kind;
+ svn_boolean_t found;
+ unparsed_id = svn_fs_unparse_id(dirent->id, pool);
+
+ SVN_ERR(svn_cache__get((void **)&kind, &found,
+ db->edit_baton->verified_dirents_cache,
+ unparsed_id->data, pool));
+
+ if (found)
+ {
+ if (kind == dirent->kind)
+ return SVN_NO_ERROR;
+ else
+ {
+ path = svn_relpath_join(db->path, (const char *)key, pool);
+
+ return
+ svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+ _("Unexpected node kind %d for '%s'. "
+ "Expected kind was %d."),
+ dirent->kind, path, kind);
+ }
+ }
+ }
+
+ path = svn_relpath_join(db->path, (const char *)key, pool);
/* since we can't access the directory entries directly by their ID,
we need to navigate from the FS_ROOT to them (relatively expensive
@@ -1316,6 +1360,11 @@ verify_directory_entry(void *baton, cons
dirent->kind, path);
}
+ /* remember ID, kind pair */
+ if (db->edit_baton->verified_dirents_cache)
+ SVN_ERR(svn_cache__set(db->edit_baton->verified_dirents_cache,
+ unparsed_id->data, &dirent->kind, pool));
+
return SVN_NO_ERROR;
}
@@ -1359,6 +1408,7 @@ verify_one_revision(svn_fs_t *fs,
svn_revnum_t start_rev,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_cache__t *verified_dirents_cache,
apr_pool_t *scratch_pool)
{
const svn_delta_editor_t *dump_editor;
@@ -1377,6 +1427,7 @@ verify_one_revision(svn_fs_t *fs,
notify_func, notify_baton,
start_rev,
FALSE, TRUE, /* use_deltas, verify */
+ verified_dirents_cache,
scratch_pool));
SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
dump_editor, dump_edit_baton,
@@ -1424,6 +1475,30 @@ verify_fs2_notify_func(svn_revnum_t revi
notify_baton->notify, pool);
}
+/* cache entry (de-)serialization support for svn_node_kind_t. */
+static svn_error_t *
+serialize_node_kind(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool)
+{
+ *data_len = sizeof(svn_node_kind_t);
+ *data = in;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+deserialize_node_kind(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool)
+{
+ *(svn_node_kind_t *)out = *(svn_node_kind_t *)data;
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_repos_verify_fs3(svn_repos_t *repos,
svn_revnum_t start_rev,
@@ -1444,6 +1519,7 @@ svn_repos_verify_fs3(svn_repos_t *repos,
struct verify_fs2_notify_func_baton_t *verify_notify_baton = NULL;
svn_error_t *err;
svn_boolean_t found_corruption = FALSE;
+ svn_cache__t *verified_dirents_cache = NULL;
/* Determine the current youngest revision of the filesystem. */
SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -1505,13 +1581,26 @@ svn_repos_verify_fs3(svn_repos_t *repos,
svn_error_clear(err);
}
+ if (svn_cache__get_global_membuffer_cache())
+ SVN_ERR(svn_cache__create_membuffer_cache
+ (&verified_dirents_cache,
+ svn_cache__get_global_membuffer_cache(),
+ serialize_node_kind,
+ deserialize_node_kind,
+ APR_HASH_KEY_STRING,
+ svn_uuid_generate(pool),
+ SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ FALSE,
+ pool));
+
for (rev = start_rev; rev <= end_rev; rev++)
{
svn_pool_clear(iterpool);
/* Wrapper function to catch the possible errors. */
- err = verify_one_revision(fs, rev, notify_func, notify_baton, start_rev,
- cancel_func, cancel_baton, iterpool);
+ err = verify_one_revision(fs, rev, notify_func, notify_baton,
+ start_rev, cancel_func, cancel_baton,
+ verified_dirents_cache, iterpool);
if (err)
{
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_repos/log.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_repos/log.c Tue Oct 15 22:57:03 2013
@@ -69,7 +69,8 @@ svn_repos_check_revision_access(svn_repo
/* Fetch the changes associated with REVISION. */
SVN_ERR(svn_fs_revision_root(&rev_root, fs, revision, pool));
- SVN_ERR(svn_fs_paths_changed2(&changes, rev_root, pool));
+ SVN_ERR(svn_fs_paths_changed3(&changes, rev_root,
+ svn_move_behavior_explicit_moves, pool));
/* No changed paths? We're done. */
if (apr_hash_count(changes) == 0)
@@ -105,6 +106,8 @@ svn_repos_check_revision_access(svn_repo
{
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
+ case svn_fs_path_change_move:
+ case svn_fs_path_change_movereplace:
{
const char *copyfrom_path;
svn_revnum_t copyfrom_rev;
@@ -163,7 +166,8 @@ svn_repos_check_revision_access(svn_repo
*
* To prevent changes from being processed over and over again, the
* changed paths for ROOT may be passed in PREFETCHED_CHANGES. If the
- * latter is NULL, we will request the list inside this function.
+ * latter is NULL, we will request the list inside this function using
+ * the specified MOVE_BEHAVIOR.
*
* If optional AUTHZ_READ_FUNC is non-NULL, then use it (with
* AUTHZ_READ_BATON and FS) to check whether each changed-path (and
@@ -184,6 +188,7 @@ detect_changed(apr_hash_t **changed,
svn_fs_root_t *root,
svn_fs_t *fs,
apr_hash_t *prefetched_changes,
+ svn_move_behavior_t move_behavior,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
apr_pool_t *pool)
@@ -196,7 +201,7 @@ detect_changed(apr_hash_t **changed,
*changed = svn_hash__make(pool);
if (changes == NULL)
- SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
+ SVN_ERR(svn_fs_paths_changed3(&changes, root, move_behavior, pool));
if (apr_hash_count(changes) == 0)
/* No paths changed in this revision? Uh, sure, I guess the
@@ -255,6 +260,14 @@ detect_changed(apr_hash_t **changed,
action = 'D';
break;
+ case svn_fs_path_change_move:
+ action = 'V';
+ break;
+
+ case svn_fs_path_change_movereplace:
+ action = 'E';
+ break;
+
case svn_fs_path_change_modify:
default:
action = 'M';
@@ -306,7 +319,8 @@ detect_changed(apr_hash_t **changed,
}
- if ((action == 'A') || (action == 'R'))
+ if ( (action == 'A') || (action == 'R')
+ || (action == 'V') || (action == 'E'))
{
const char *copyfrom_path = change->copyfrom_path;
svn_revnum_t copyfrom_rev = change->copyfrom_rev;
@@ -563,7 +577,9 @@ next_history_rev(const apr_array_header_
catalogs describing how mergeinfo values on paths (which are the
keys of those catalogs) were changed in REV. If *PREFETCHED_CAHNGES
already contains the changed paths for REV, use that. Otherwise,
- request that data and return it in *PREFETCHED_CHANGES. */
+ request that data and return it in *PREFETCHED_CHANGES.
+ MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
+ layer which changes to report as moves instead of additions. */
/* ### TODO: This would make a *great*, useful public function,
### svn_repos_fs_mergeinfo_changed()! -- cmpilato */
static svn_error_t *
@@ -572,6 +588,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
apr_hash_t **prefetched_changes,
svn_fs_t *fs,
svn_revnum_t rev,
+ svn_move_behavior_t move_behavior,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -592,7 +609,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
narrow down our search. */
SVN_ERR(svn_fs_revision_root(&root, fs, rev, scratch_pool));
if (*prefetched_changes == NULL)
- SVN_ERR(svn_fs_paths_changed2(prefetched_changes, root, scratch_pool));
+ SVN_ERR(svn_fs_paths_changed3(prefetched_changes, root, move_behavior,
+ scratch_pool));
/* No changed paths? We're done. */
if (apr_hash_count(*prefetched_changes) == 0)
@@ -638,6 +656,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
was. If not, there's no previous location to examine. */
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
+ case svn_fs_path_change_move:
+ case svn_fs_path_change_movereplace:
{
const char *copyfrom_path;
svn_revnum_t copyfrom_rev;
@@ -782,7 +802,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
*ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO.
If *PREFETCHED_CAHNGES already contains the changed paths for
REV, use that. Otherwise, request that data and return it in
- *PREFETCHED_CHANGES.
+ *PREFETCHED_CHANGES. MOVE_BEHAVIOR tells the FS layer which
+ changes to report as moves instead of additions.
Use POOL for all allocations. */
static svn_error_t *
get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo,
@@ -791,6 +812,7 @@ get_combined_mergeinfo_changes(svn_merge
svn_fs_t *fs,
const apr_array_header_t *paths,
svn_revnum_t rev,
+ svn_move_behavior_t move_behavior,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -820,7 +842,8 @@ get_combined_mergeinfo_changes(svn_merge
err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog,
&added_mergeinfo_catalog,
prefetched_changes,
- fs, rev, scratch_pool, scratch_pool);
+ fs, rev, move_behavior,
+ scratch_pool, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
@@ -1025,6 +1048,7 @@ fill_log_entry(svn_log_entry_t *log_entr
svn_fs_t *fs,
apr_hash_t *prefetched_changes,
svn_boolean_t discover_changed_paths,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
@@ -1043,7 +1067,7 @@ fill_log_entry(svn_log_entry_t *log_entr
SVN_ERR(svn_fs_revision_root(&newroot, fs, rev, pool));
patherr = detect_changed(&changed_paths,
- newroot, fs, prefetched_changes,
+ newroot, fs, prefetched_changes, move_behavior,
authz_read_func, authz_read_baton,
pool);
@@ -1160,9 +1184,9 @@ fill_log_entry(svn_log_entry_t *log_entr
only the revision properties named by the (const char *) array elements
(i.e. retrieve none if the array is empty).
- LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, and
- NESTED_MERGES are as per the arguments of the same name to DO_LOGS. If
- HANDLING_MERGED_REVISION is true and *all* changed paths within REV are
+ LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, MOVE_BEHAVIOR,
+ and NESTED_MERGES are as per the arguments of the same name to DO_LOGS.
+ If HANDLING_MERGED_REVISION is true and *all* changed paths within REV are
already represented in LOG_TARGET_HISTORY_AS_MERGEINFO, then don't send
the log message for REV. If SUBTRACTIVE_MERGE is true, then REV was
reverse merged.
@@ -1180,6 +1204,7 @@ send_log(svn_revnum_t rev,
svn_boolean_t discover_changed_paths,
svn_boolean_t subtractive_merge,
svn_boolean_t handling_merged_revision,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t has_children,
svn_log_entry_receiver_t receiver,
@@ -1195,8 +1220,8 @@ send_log(svn_revnum_t rev,
log_entry = svn_log_entry_create(pool);
SVN_ERR(fill_log_entry(log_entry, rev, fs, prefetched_changes,
discover_changed_paths || handling_merged_revision,
- revprops, authz_read_func, authz_read_baton,
- pool));
+ move_behavior, revprops,
+ authz_read_func, authz_read_baton, pool));
log_entry->has_children = has_children;
log_entry->subtractive_merge = subtractive_merge;
@@ -1663,6 +1688,7 @@ do_logs(svn_fs_t *fs,
svn_boolean_t handling_merged_revisions,
svn_boolean_t subtractive_merge,
svn_boolean_t ignore_missing_locations,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t descending_order,
svn_log_entry_receiver_t receiver,
@@ -1712,6 +1738,7 @@ handle_merged_revisions(svn_revnum_t rev
svn_mergeinfo_t deleted_mergeinfo,
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t receiver,
void *receiver_baton,
@@ -1754,7 +1781,7 @@ handle_merged_revisions(svn_revnum_t rev
pl_range->range.start, pl_range->range.end, 0,
discover_changed_paths, strict_node_history,
TRUE, pl_range->reverse_merge, TRUE, TRUE,
- revprops, TRUE, receiver, receiver_baton,
+ move_behavior, revprops, TRUE, receiver, receiver_baton,
authz_read_func, authz_read_baton, iterpool));
}
svn_pool_destroy(iterpool);
@@ -1888,6 +1915,9 @@ store_search(svn_mergeinfo_t processed,
If IGNORE_MISSING_LOCATIONS is set, don't treat requests for bogus
repository locations as fatal -- just ignore them.
+ MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
+ layer which changes to report as moves instead of additions.
+
If LOG_TARGET_HISTORY_AS_MERGEINFO is not NULL then it contains mergeinfo
representing the history of PATHS between HIST_START and HIST_END.
@@ -1925,6 +1955,7 @@ do_logs(svn_fs_t *fs,
svn_boolean_t subtractive_merge,
svn_boolean_t handling_merged_revisions,
svn_boolean_t ignore_missing_locations,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t descending_order,
svn_log_entry_receiver_t receiver,
@@ -2019,8 +2050,8 @@ do_logs(svn_fs_t *fs,
&deleted_mergeinfo,
&changes,
fs, cur_paths,
- current, iterpool,
- iterpool));
+ current, move_behavior,
+ iterpool, iterpool));
has_children = (apr_hash_count(added_mergeinfo) > 0
|| apr_hash_count(deleted_mergeinfo) > 0);
}
@@ -2034,7 +2065,7 @@ do_logs(svn_fs_t *fs,
log_target_history_as_mergeinfo, nested_merges,
discover_changed_paths,
subtractive_merge, handling_merged_revisions,
- revprops, has_children,
+ move_behavior, revprops, has_children,
receiver, receiver_baton,
authz_read_func, authz_read_baton, iterpool));
@@ -2057,6 +2088,7 @@ do_logs(svn_fs_t *fs,
added_mergeinfo, deleted_mergeinfo,
discover_changed_paths,
strict_node_history,
+ move_behavior,
revprops,
receiver, receiver_baton,
authz_read_func,
@@ -2138,7 +2170,8 @@ do_logs(svn_fs_t *fs,
SVN_ERR(send_log(current, fs, NULL,
log_target_history_as_mergeinfo, nested_merges,
discover_changed_paths, subtractive_merge,
- handling_merged_revisions, revprops, has_children,
+ handling_merged_revisions, move_behavior,
+ revprops, has_children,
receiver, receiver_baton, authz_read_func,
authz_read_baton, iterpool));
if (has_children)
@@ -2156,7 +2189,8 @@ do_logs(svn_fs_t *fs,
added_mergeinfo,
deleted_mergeinfo,
discover_changed_paths,
- strict_node_history, revprops,
+ strict_node_history,
+ move_behavior, revprops,
receiver, receiver_baton,
authz_read_func,
authz_read_baton,
@@ -2258,7 +2292,7 @@ get_paths_history_as_mergeinfo(svn_merge
}
svn_error_t *
-svn_repos_get_logs4(svn_repos_t *repos,
+svn_repos_get_logs5(svn_repos_t *repos,
const apr_array_header_t *paths,
svn_revnum_t start,
svn_revnum_t end,
@@ -2266,6 +2300,7 @@ svn_repos_get_logs4(svn_repos_t *repos,
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
@@ -2374,7 +2409,7 @@ svn_repos_get_logs4(svn_repos_t *repos,
rev = start + i;
SVN_ERR(send_log(rev, fs, NULL, NULL, NULL,
discover_changed_paths, FALSE,
- FALSE, revprops, FALSE, receiver,
+ FALSE, move_behavior, revprops, FALSE, receiver,
receiver_baton, authz_read_func,
authz_read_baton, iterpool));
}
@@ -2402,7 +2437,8 @@ svn_repos_get_logs4(svn_repos_t *repos,
return do_logs(repos->fs, paths, paths_history_mergeinfo, NULL, NULL, start, end,
limit, discover_changed_paths, strict_node_history,
- include_merged_revisions, FALSE, FALSE, FALSE, revprops,
+ include_merged_revisions, FALSE, FALSE, FALSE,
+ move_behavior, revprops,
descending_order, receiver, receiver_baton,
authz_read_func, authz_read_baton, pool);
}
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-membuffer.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-membuffer.c Tue Oct 15 22:57:03 2013
@@ -51,7 +51,8 @@
* 2. A directory of cache entries. This is organized similar to CPU
* data caches: for every possible key, there is exactly one group
* of entries that may contain the header info for an item with
- * that given key. The result is a GROUP_SIZE-way associative cache.
+ * that given key. The result is a GROUP_SIZE+-way associative cache
+ * whose associativity can be dynamically increased.
*
* Only the start address of these two data parts are given as a native
* pointer. All other references are expressed as offsets to these pointers.
@@ -97,6 +98,10 @@
* about 50% of the content survives every 50% of the cache being re-written
* with new entries. For details on the fine-tuning involved, see the
* comments in ensure_data_insertable_l2().
+ *
+ * Due to the randomized mapping of keys to entry groups, some groups may
+ * overflow. In that case, there are spare groups that can be chained to
+ * an already used group to extend it.
*
* To limit the entry size and management overhead, not the actual item keys
* but only their MD5-based hashes will be stored. This is reasonably safe
@@ -111,13 +116,6 @@
* on their hash key.
*/
-/* A 16-way associative cache seems to be a good compromise between
- * performance (worst-case lookups) and efficiency-loss due to collisions.
- *
- * This value may be changed to any positive integer.
- */
-#define GROUP_SIZE 16
-
/* For more efficient copy operations, let's align all data items properly.
* Must be a power of 2.
*/
@@ -298,17 +296,18 @@ static svn_error_t* assert_equal_tags(co
#define DEBUG_CACHE_MEMBUFFER_TAG tag,
-#define DEBUG_CACHE_MEMBUFFER_INIT_TAG \
- entry_tag_t _tag; \
- entry_tag_t *tag = &_tag; \
- SVN_ERR(store_key_part(tag, \
- cache->prefix, \
- cache->prefix_tail, \
- key, \
- cache->key_len == APR_HASH_KEY_STRING \
- ? strlen((const char *) key) \
- : cache->key_len, \
- cache->pool));
+#define DEBUG_CACHE_MEMBUFFER_INIT_TAG \
+ entry_tag_t _tag; \
+ entry_tag_t *tag = &_tag; \
+ if (key) \
+ SVN_ERR(store_key_part(tag, \
+ cache->prefix, \
+ cache->prefix_tail, \
+ key, \
+ cache->key_len == APR_HASH_KEY_STRING \
+ ? strlen((const char *) key) \
+ : cache->key_len, \
+ cache->pool));
#else
@@ -336,10 +335,11 @@ typedef struct entry_t
*/
apr_uint64_t offset;
- /* Size of the serialized item data. May be 0.
+ /* Size of the serialized item data. May be 0. The MAX_ITEM_SIZE macro
+ * above ensures that there will be no overflows.
* Only valid for used entries.
*/
- apr_size_t size;
+ apr_uint32_t size;
/* Number of (read) hits for this entry. Will be reset upon write.
* Only valid for used entries.
@@ -372,15 +372,60 @@ typedef struct entry_t
#endif
} entry_t;
-/* We group dictionary entries to make this GROUP-SIZE-way associative.
+/* Group header struct.
*/
-typedef struct entry_group_t
+typedef struct group_header_t
{
/* number of entries used [0 .. USED-1] */
apr_uint32_t used;
+ /* next group in the chain or NO_INDEX for the last.
+ * For recycleable unused spare groups, this points to the next
+ * unused spare group */
+ apr_uint32_t next;
+
+ /* previously group in the chain or NO_INDEX for the first */
+ apr_uint32_t previous;
+
+ /* number of elements in the chain from start to here.
+ * >= 1 for used groups, 0 for unused spare groups */
+ apr_uint32_t chain_length;
+
+} group_header_t;
+
+/* The size of the group struct should be a power of two make sure it does
+ * not cross memory page boundaries. Since we already access the cache
+ * randomly, having two page table lookups instead of one is bad.
+ */
+#define GROUP_BLOCK_SIZE 512
+
+/* A ~10-way associative cache seems to be a good compromise between
+ * performance (worst-case lookups) and efficiency-loss due to collisions.
+ *
+ * This value may be changed to any positive integer.
+ */
+#define GROUP_SIZE \
+ ((GROUP_BLOCK_SIZE - sizeof(group_header_t)) / sizeof(entry_t))
+
+/* Maximum number of groups in a chain, i.e. a cache index group can hold
+ * up to GROUP_SIZE * MAX_GROUP_CHAIN_LENGTH entries.
+ */
+#define MAX_GROUP_CHAIN_LENGTH 8
+
+/* We group dictionary entries to make this GROUP-SIZE-way associative.
+ */
+typedef struct entry_group_t
+{
+ /* group globals */
+ group_header_t header;
+
+ /* padding and also room for future extensions */
+ char padding[GROUP_BLOCK_SIZE - sizeof(group_header_t)
+ - sizeof(entry_t) * GROUP_SIZE];
+
/* the actual entries */
entry_t entries[GROUP_SIZE];
+
} entry_group_t;
/* Per-cache level header structure. Instances of this are members of
@@ -432,7 +477,8 @@ struct svn_membuffer_t
and that all segments must / will report the same values here. */
apr_uint32_t segment_count;
- /* The dictionary, GROUP_SIZE * group_count entries long. Never NULL.
+ /* The dictionary, GROUP_SIZE * (group_count + spare_group_count)
+ * entries long. Never NULL.
*/
entry_group_t *directory;
@@ -445,6 +491,20 @@ struct svn_membuffer_t
*/
apr_uint32_t group_count;
+ /* Total number of spare groups.
+ */
+ apr_uint32_t spare_group_count;
+
+ /* First recycleable spare group.
+ */
+ apr_uint32_t first_spare_group;
+
+ /* Maximum number of spare groups ever used. I.e. group index
+ * group_count + max_spare_used is the first unused spare group
+ * if first_spare_group is NO_INDEX.
+ */
+ apr_uint32_t max_spare_used;
+
/* Pointer to the data buffer, data_size bytes long. Never NULL.
*/
unsigned char *data;
@@ -645,6 +705,132 @@ do {
SVN_ERR(unlock_cache(cache, (expr))); \
} while (0)
+/* Returns 0 if the entry group identified by GROUP_INDEX in CACHE has not
+ * been initialized, yet. In that case, this group can not data. Otherwise,
+ * a non-zero value is returned.
+ */
+static APR_INLINE unsigned char
+is_group_initialized(svn_membuffer_t *cache, apr_uint32_t group_index)
+{
+ unsigned char flags
+ = cache->group_initialized[group_index / (8 * GROUP_INIT_GRANULARITY)];
+ unsigned char bit_mask
+ = (unsigned char)(1 << ((group_index / GROUP_INIT_GRANULARITY) % 8));
+
+ return flags & bit_mask;
+}
+
+/* Initializes the section of the directory in CACHE that contains
+ * the entry group identified by GROUP_INDEX. */
+static void
+initialize_group(svn_membuffer_t *cache, apr_uint32_t group_index)
+{
+ unsigned char bit_mask;
+ apr_uint32_t i;
+
+ /* range of groups to initialize due to GROUP_INIT_GRANULARITY */
+ apr_uint32_t first_index =
+ (group_index / GROUP_INIT_GRANULARITY) * GROUP_INIT_GRANULARITY;
+ apr_uint32_t last_index = first_index + GROUP_INIT_GRANULARITY;
+ if (last_index > cache->group_count)
+ last_index = cache->group_count;
+
+ for (i = first_index; i < last_index; ++i)
+ {
+ group_header_t *header = &cache->directory[i].header;
+ header->used = 0;
+ header->chain_length = 1;
+ header->next = NO_INDEX;
+ header->previous = NO_INDEX;
+ }
+
+ /* set the "initialized" bit for these groups */
+ bit_mask
+ = (unsigned char)(1 << ((group_index / GROUP_INIT_GRANULARITY) % 8));
+ cache->group_initialized[group_index / (8 * GROUP_INIT_GRANULARITY)]
+ |= bit_mask;
+}
+
+/* Return the next available spare group from CACHE and mark it as used.
+ * May return NULL.
+ */
+static entry_group_t *
+allocate_spare_group(svn_membuffer_t *cache)
+{
+ entry_group_t *group = NULL;
+
+ /* is there some ready-to-use group? */
+ if (cache->first_spare_group != NO_INDEX)
+ {
+ group = &cache->directory[cache->first_spare_group];
+ cache->first_spare_group = group->header.next;
+ }
+
+ /* any so far untouched spares available? */
+ else if (cache->max_spare_used < cache->spare_group_count)
+ {
+ apr_uint32_t group_index = cache->group_count + cache->max_spare_used;
+ ++cache->max_spare_used;
+
+ if (!is_group_initialized(cache, group_index))
+ initialize_group(cache, group_index);
+
+ group = &cache->directory[group_index];
+ }
+
+ /* spare groups must be empty */
+ assert(!group || !group->header.used);
+ return group;
+}
+
+/* Mark previously allocated spare group GROUP in CACHE as "unused".
+ */
+static void
+free_spare_group(svn_membuffer_t *cache,
+ entry_group_t *group)
+{
+ assert(group->header.used == 0);
+ assert(group->header.previous != NO_INDEX);
+ assert(group - cache->directory >= cache->group_count);
+
+ /* unchain */
+ cache->directory[group->header.previous].header.next = NO_INDEX;
+ group->header.chain_length = 0;
+ group->header.previous = NO_INDEX;
+
+ /* add to chain of spares */
+ group->header.next = cache->first_spare_group;
+ cache->first_spare_group = group - cache->directory;
+}
+
+/* Follow the group chain from GROUP in CACHE to its end and return the last
+ * group. May return GROUP.
+ */
+static entry_group_t *
+last_group_in_chain(svn_membuffer_t *cache,
+ entry_group_t *group)
+{
+ while (group->header.next != NO_INDEX)
+ group = &cache->directory[group->header.next];
+
+ return group;
+}
+
+/* Return the CHAIN_INDEX-th element in the group chain starting from group
+ * START_GROUP_INDEX in CACHE.
+ */
+static entry_group_t *
+get_group(svn_membuffer_t *cache,
+ apr_uint32_t start_group_index,
+ apr_uint32_t chain_index)
+{
+ entry_group_t *group = &cache->directory[start_group_index];
+ for (; chain_index; --chain_index)
+ group = &cache->directory[group->header.next];
+
+ return group;
+}
+
/* Resolve a dictionary entry reference, i.e. return the entry
* for the given IDX.
*/
@@ -766,13 +952,13 @@ drop_entry(svn_membuffer_t *cache, entry
*/
apr_uint32_t idx = get_index(cache, entry);
apr_uint32_t group_index = idx / GROUP_SIZE;
- entry_group_t *group = &cache->directory[group_index];
- apr_uint32_t last_in_group = group_index * GROUP_SIZE + group->used - 1;
- cache_level_t *level = get_cache_level(cache, entry);
+ entry_group_t *last_group
+ = last_group_in_chain(cache, &cache->directory[group_index]);
+ apr_uint32_t last_in_group
+ = (last_group - cache->directory) * GROUP_SIZE
+ + last_group->header.used - 1;
- /* Only valid to be called for used entries.
- */
- assert(idx <= last_in_group);
+ cache_level_t *level = get_cache_level(cache, entry);
/* update global cache usage counters
*/
@@ -806,16 +992,16 @@ drop_entry(svn_membuffer_t *cache, entry
/* unlink it from the chain of used entries
*/
unchain_entry(cache, level, entry, idx);
-
+
/* Move last entry into hole (if the removed one is not the last used).
* We need to do this since all used entries are at the beginning of
* the group's entries array.
*/
- if (idx < last_in_group)
+ if (idx != last_in_group)
{
/* copy the last used entry to the removed entry's index
*/
- *entry = group->entries[group->used-1];
+ *entry = last_group->entries[last_group->header.used-1];
/* this ENTRY may belong to a different cache level than the entry
* we have just removed */
@@ -839,7 +1025,12 @@ drop_entry(svn_membuffer_t *cache, entry
/* Update the number of used entries.
*/
- group->used--;
+ last_group->header.used--;
+
+ /* Release the last group in the chain if it is a spare group
+ */
+ if (!last_group->header.used && last_group->header.previous != NO_INDEX)
+ free_spare_group(cache, last_group);
}
/* Insert ENTRY into the chain of used dictionary entries. The entry's
@@ -860,7 +1051,7 @@ insert_entry(svn_membuffer_t *cache, ent
* It must also be the first unused entry in the group.
*/
assert(entry->offset == level->current_data);
- assert(idx == group_index * GROUP_SIZE + group->used);
+ assert(idx == group_index * GROUP_SIZE + group->header.used);
level->current_data = ALIGN_VALUE(entry->offset + entry->size);
/* update usage counters
@@ -868,7 +1059,7 @@ insert_entry(svn_membuffer_t *cache, ent
cache->used_entries++;
cache->data_used += entry->size;
entry->hit_count = 0;
- group->used++;
+ group->header.used++;
/* update entry chain
*/
@@ -910,46 +1101,6 @@ let_entry_age(svn_membuffer_t *cache, en
entry->hit_count -= hits_removed;
}
-/* Returns 0 if the entry group identified by GROUP_INDEX in CACHE has not
- * been initialized, yet. In that case, this group can not data. Otherwise,
- * a non-zero value is returned.
- */
-static APR_INLINE unsigned char
-is_group_initialized(svn_membuffer_t *cache, apr_uint32_t group_index)
-{
- unsigned char flags
- = cache->group_initialized[group_index / (8 * GROUP_INIT_GRANULARITY)];
- unsigned char bit_mask
- = (unsigned char)(1 << ((group_index / GROUP_INIT_GRANULARITY) % 8));
-
- return flags & bit_mask;
-}
-
-/* Initializes the section of the directory in CACHE that contains
- * the entry group identified by GROUP_INDEX. */
-static void
-initialize_group(svn_membuffer_t *cache, apr_uint32_t group_index)
-{
- unsigned char bit_mask;
- apr_uint32_t i;
-
- /* range of groups to initialize due to GROUP_INIT_GRANULARITY */
- apr_uint32_t first_index =
- (group_index / GROUP_INIT_GRANULARITY) * GROUP_INIT_GRANULARITY;
- apr_uint32_t last_index = first_index + GROUP_INIT_GRANULARITY;
- if (last_index > cache->group_count)
- last_index = cache->group_count;
-
- for (i = first_index; i < last_index; ++i)
- cache->directory[i].used = 0;
-
- /* set the "initialized" bit for these groups */
- bit_mask
- = (unsigned char)(1 << ((group_index / GROUP_INIT_GRANULARITY) % 8));
- cache->group_initialized[group_index / (8 * GROUP_INIT_GRANULARITY)]
- |= bit_mask;
-}
-
/* Given the GROUP_INDEX that shall contain an entry with the hash key
* TO_FIND, find that entry in the specified group.
*
@@ -995,45 +1146,98 @@ find_entry(svn_membuffer_t *cache,
/* try to find the matching entry
*/
- for (i = 0; i < group->used; ++i)
- if ( to_find[0] == group->entries[i].key[0]
- && to_find[1] == group->entries[i].key[1])
- {
- /* found it
- */
- entry = &group->entries[i];
- if (find_empty)
- drop_entry(cache, entry);
- else
- return entry;
- }
+ while (1)
+ {
+ for (i = 0; i < group->header.used; ++i)
+ if ( to_find[0] == group->entries[i].key[0]
+ && to_find[1] == group->entries[i].key[1])
+ {
+ /* found it
+ */
+ entry = &group->entries[i];
+ if (!find_empty)
+ return entry;
+
+ /* need to empty that entry */
+ drop_entry(cache, entry);
+ if (group->header.used == GROUP_SIZE)
+ group = last_group_in_chain(cache, group);
+ else if (group->header.chain_length == 0)
+ group = last_group_in_chain(cache,
+ &cache->directory[group_index]);
+
+ break;
+ }
+
+ /* end of chain? */
+ if (group->header.next == NO_INDEX)
+ break;
+
+ /* only full groups may chain */
+ assert(group->header.used == GROUP_SIZE);
+ group = &cache->directory[group->header.next];
+ }
/* None found. Are we looking for a free entry?
*/
if (find_empty)
{
- /* if there is no empty entry, delete the oldest entry
+ /* There is no empty entry in the chain, try chaining a spare group.
*/
- if (group->used == GROUP_SIZE)
+ if ( group->header.used == GROUP_SIZE
+ && group->header.chain_length < MAX_GROUP_CHAIN_LENGTH)
+ {
+ entry_group_t *new_group = allocate_spare_group(cache);
+ if (new_group)
+ {
+ /* chain groups
+ */
+ new_group->header.chain_length = group->header.chain_length + 1;
+ new_group->header.previous = group - cache->directory;
+ new_group->header.next = NO_INDEX;
+ group->header.next = new_group - cache->directory;
+ group = new_group;
+ }
+ }
+
+ /* if GROUP is still filled, we need to remove a random entry */
+ if (group->header.used == GROUP_SIZE)
{
/* every entry gets the same chance of being removed.
- * Otherwise, we free the first entry, fill it and remove it
- * again on the next occasion without considering the other
- * entries in this group. Also, apply priorities strictly.
+ * Otherwise, we free the first entry, fill it and
+ * remove it again on the next occasion without considering
+ * the other entries in this group.
+ *
+ * We hit only one random group instead of processing all
+ * groups in the chain.
*/
- entry = &group->entries[rand() % GROUP_SIZE];
- for (i = 1; i < GROUP_SIZE; ++i)
- if ( (entry->priority > group->entries[i].priority)
- || ( entry->priority == group->entries[i].priority
- && entry->hit_count > group->entries[i].hit_count))
- entry = &group->entries[i];
+ cache_level_t *entry_level;
+ int to_remove = rand() % (GROUP_SIZE * group->header.chain_length);
+ entry_group_t *to_shrink
+ = get_group(cache, group_index, to_remove / GROUP_SIZE);
+
+ entry = &to_shrink->entries[to_remove % GROUP_SIZE];
+ entry_level = get_cache_level(cache, entry);
+ for (i = 0; i < GROUP_SIZE; ++i)
+ {
+ /* keep L1 entries whenever possible */
+
+ cache_level_t *level
+ = get_cache_level(cache, &to_shrink->entries[i]);
+ if ( (level != entry_level && entry_level == &cache->l1)
+ || (entry->hit_count > to_shrink->entries[i].hit_count))
+ {
+ entry_level = level;
+ entry = &to_shrink->entries[i];
+ }
+ }
/* for the entries that don't have been removed,
* reduce their hit counts to put them at a relative
* disadvantage the next time.
*/
for (i = 0; i < GROUP_SIZE; ++i)
- if (entry != &group->entries[i])
+ if (entry != &to_shrink->entries[i])
let_entry_age(cache, entry);
drop_entry(cache, entry);
@@ -1041,7 +1245,7 @@ find_entry(svn_membuffer_t *cache,
/* initialize entry for the new key
*/
- entry = &group->entries[group->used];
+ entry = &group->entries[group->header.used];
entry->key[0] = to_find[0];
entry->key[1] = to_find[1];
}
@@ -1097,6 +1301,7 @@ promote_entry(svn_membuffer_t *cache, en
apr_uint32_t idx = get_index(cache, entry);
apr_size_t size = ALIGN_VALUE(entry->size);
assert(get_cache_level(cache, entry) == &cache->l1);
+ assert(idx == cache->l1.next);
/* copy item from the current location in L1 to the start of L2's
* insertion window */
@@ -1127,8 +1332,7 @@ promote_entry(svn_membuffer_t *cache, en
*/
static svn_boolean_t
ensure_data_insertable_l2(svn_membuffer_t *cache,
- entry_t *to_fit_in,
- apr_uint32_t idx)
+ entry_t *to_fit_in)
{
entry_t *entry;
apr_uint64_t average_hit_value;
@@ -1147,9 +1351,6 @@ ensure_data_insertable_l2(svn_membuffer_
/* accumulated "worth" of items dropped so far */
apr_size_t drop_hits = 0;
- /* verify parameters */
- assert(idx == get_index(cache, to_fit_in));
-
/* This loop will eventually terminate because every cache entry
* would get dropped eventually:
* - hit counts become 0 after the got kept for 32 full scans
@@ -1221,16 +1422,6 @@ ensure_data_insertable_l2(svn_membuffer_
{
keep = TRUE;
}
- else if (cache->l2.next / GROUP_SIZE == idx / GROUP_SIZE)
- {
- /* Special case: we cannot drop entries that are in the same
- * group as TO_FIT_IN because that might the latter to become
- * invalidated it it happens to be the highest used entry in
- * the group. So, we must keep ENTRY unconditionally.
- * (this is a very rare condition)
- */
- keep = TRUE;
- }
else if ( entry->priority < SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY
&& to_fit_in->priority > entry->priority)
{
@@ -1308,8 +1499,6 @@ ensure_data_insertable_l2(svn_membuffer_
static svn_boolean_t
ensure_data_insertable_l1(svn_membuffer_t *cache, apr_size_t size)
{
- entry_t *entry;
-
/* Guarantees that the while loop will terminate. */
if (size > cache->l1.size)
return FALSE;
@@ -1321,9 +1510,11 @@ ensure_data_insertable_l1(svn_membuffer_
{
/* first offset behind the insertion window
*/
+ apr_uint32_t entry_index = cache->l1.next;
+ entry_t *entry = get_entry(cache, entry_index);
apr_uint64_t end = cache->l1.next == NO_INDEX
? cache->l1.start_offset + cache->l1.size
- : get_entry(cache, cache->l1.next)->offset;
+ : entry->offset;
/* leave function as soon as the insertion window is large enough
*/
@@ -1347,12 +1538,16 @@ ensure_data_insertable_l1(svn_membuffer_
/* Remove the entry from the end of insertion window and promote
* it to L2, if it is important enough.
*/
- entry = get_entry(cache, cache->l1.next);
+ svn_boolean_t keep = ensure_data_insertable_l2(cache, entry);
- if (ensure_data_insertable_l2(cache, entry, cache->l1.next))
- promote_entry(cache, entry);
- else
- drop_entry(cache, entry);
+ /* We might have touched the group that contains ENTRY. Recheck. */
+ if (entry_index == cache->l1.next)
+ {
+ if (keep)
+ promote_entry(cache, entry);
+ else
+ drop_entry(cache, entry);
+ }
}
}
@@ -1395,6 +1590,8 @@ svn_cache__membuffer_cache_create(svn_me
apr_uint32_t seg;
apr_uint32_t group_count;
+ apr_uint32_t main_group_count;
+ apr_uint32_t spare_group_count;
apr_uint32_t group_init_size;
apr_uint64_t data_size;
apr_uint64_t max_entry_size;
@@ -1469,8 +1666,8 @@ svn_cache__membuffer_cache_create(svn_me
*/
if (directory_size > total_size - sizeof(entry_group_t))
directory_size = total_size - sizeof(entry_group_t);
- if (directory_size < sizeof(entry_group_t))
- directory_size = sizeof(entry_group_t);
+ if (directory_size < 2 * sizeof(entry_group_t))
+ directory_size = 2 * sizeof(entry_group_t);
/* limit the data size to what we can address.
* Note that this cannot overflow since all values are of size_t.
@@ -1498,6 +1695,11 @@ svn_cache__membuffer_cache_create(svn_me
? (APR_UINT32_MAX / GROUP_SIZE) - 1
: (apr_uint32_t)(directory_size / sizeof(entry_group_t));
+ /* set some of the index directory aside as over-flow (spare) buffers */
+ spare_group_count = MAX(group_count / 4, 1);
+ main_group_count = group_count - spare_group_count;
+ assert(spare_group_count > 0 && main_group_count > 0);
+
group_init_size = 1 + group_count / (8 * GROUP_INIT_GRANULARITY);
for (seg = 0; seg < segment_count; ++seg)
{
@@ -1505,7 +1707,11 @@ svn_cache__membuffer_cache_create(svn_me
*/
c[seg].segment_count = (apr_uint32_t)segment_count;
- c[seg].group_count = group_count;
+ c[seg].group_count = main_group_count;
+ c[seg].spare_group_count = spare_group_count;
+ c[seg].first_spare_group = NO_INDEX;
+ c[seg].max_spare_used = 0;
+
c[seg].directory = apr_pcalloc(pool,
group_count * sizeof(entry_group_t));
@@ -1870,7 +2076,24 @@ membuffer_cache_has_key_internal(svn_mem
entry_key_t to_find,
svn_boolean_t *found)
{
- *found = find_entry(cache, group_index, to_find, FALSE) != NULL;
+ entry_t *entry = find_entry(cache, group_index, to_find, FALSE);
+ if (entry)
+ {
+ /* This is often happen in "block read" where most data is already
+ in L2 and only a few previously evicted items are added to L1
+ again. While items in L1 are well protected for a while, L2
+ items may get evicted soon. Thus, mark all them as "hit" to give
+ them a higher chance for survival. */
+ entry->hit_count++;
+ cache->hit_count++;
+ cache->total_hits++;
+
+ *found = TRUE;
+ }
+ else
+ {
+ *found = FALSE;
+ }
return SVN_NO_ERROR;
}
@@ -1888,6 +2111,8 @@ membuffer_cache_has_key(svn_membuffer_t
/* find the entry group that will hold the key.
*/
apr_uint32_t group_index = get_group_index(&cache, key);
+ cache->total_reads++;
+
WITH_READ_LOCK(cache,
membuffer_cache_has_key_internal(cache,
group_index,
@@ -2573,8 +2798,10 @@ svn_membuffer_get_segment_info(svn_membu
if (include_histogram)
for (i = 0; i < segment->group_count; ++i)
{
+ entry_group_t *chain_end
+ = last_group_in_chain(segment, &segment->directory[i]);
apr_size_t use
- = MIN(segment->directory[i].used,
+ = MIN(chain_end->header.used,
sizeof(info->histogram) / sizeof(info->histogram[0]) - 1);
info->histogram[use]++;
}
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache_config.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache_config.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache_config.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache_config.c Tue Oct 15 22:57:03 2013
@@ -23,6 +23,7 @@
#include <apr_atomic.h>
#include "svn_cache_config.h"
+#include "private/svn_atomic.h"
#include "private/svn_cache.h"
#include "svn_pools.h"
@@ -69,30 +70,27 @@ svn_cache_config_get(void)
return &cache_settings;
}
-/* Access the process-global (singleton) membuffer cache. The first call
- * will automatically allocate the cache using the current cache config.
- * NULL will be returned if the desired cache size is 0 or if the cache
- * could not be created for some reason.
+/* Initializer function as required by svn_atomic__init_once. Allocate
+ * the process-global (singleton) membuffer cache and return it in the
+ * svn_membuffer_t * in *BATON. UNUSED_POOL is unused and should be NULL.
*/
-svn_membuffer_t *
-svn_cache__get_global_membuffer_cache(void)
+static svn_error_t *
+initialize_cache(void *baton, apr_pool_t *unused_pool)
{
- static svn_membuffer_t * volatile cache = NULL;
+ svn_membuffer_t **cache_p = baton;
+ svn_membuffer_t *cache = NULL;
apr_uint64_t cache_size = cache_settings.cache_size;
- if (!cache && cache_size)
+ if (cache_size)
{
svn_error_t *err;
- svn_membuffer_t *old_cache = NULL;
- svn_membuffer_t *new_cache = NULL;
-
/* auto-allocate cache */
apr_allocator_t *allocator = NULL;
apr_pool_t *pool = NULL;
if (apr_allocator_create(&allocator))
- return NULL;
+ return SVN_NO_ERROR;
/* Ensure that we free partially allocated data if we run OOM
* before the cache is complete: If the cache cannot be allocated
@@ -112,13 +110,13 @@ svn_cache__get_global_membuffer_cache(vo
*/
apr_pool_create_ex(&pool, NULL, NULL, allocator);
if (pool == NULL)
- return NULL;
+ return SVN_NO_ERROR;
apr_allocator_owner_set(allocator, pool);
err = svn_cache__membuffer_cache_create(
- &new_cache,
+ &cache,
(apr_size_t)cache_size,
- (apr_size_t)(cache_size / 10),
+ (apr_size_t)(cache_size / 5),
0,
! svn_cache_config_get()->single_threaded,
FALSE,
@@ -129,33 +127,40 @@ svn_cache__get_global_membuffer_cache(vo
*/
if (err)
{
- /* Memory and error cleanup */
- svn_error_clear(err);
+ /* Memory cleanup */
svn_pool_destroy(pool);
- /* Prevent future attempts to create the cache. However, an
- * existing cache instance (see next comment) remains valid.
- */
+ /* Document that we actually don't have a cache. */
cache_settings.cache_size = 0;
- /* The current caller won't get the cache object.
- * However, a concurrent call might have succeeded in creating
- * the cache object. That call and all following ones will then
- * use the successfully created cache instance.
- */
- return NULL;
+ return svn_error_trace(err);
}
- /* Handle race condition: if we are the first to create a
- * cache object, make it our global singleton. Otherwise,
- * discard the new cache and keep the existing one.
- *
- * Cast is necessary because of APR bug:
- * https://issues.apache.org/bugzilla/show_bug.cgi?id=50731
- */
- old_cache = apr_atomic_casptr((volatile void **)&cache, new_cache, NULL);
- if (old_cache != NULL)
- svn_pool_destroy(pool);
+ /* done */
+ *cache_p = cache;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Access the process-global (singleton) membuffer cache. The first call
+ * will automatically allocate the cache using the current cache config.
+ * NULL will be returned if the desired cache size is 0 or if the cache
+ * could not be created for some reason.
+ */
+svn_membuffer_t *
+svn_cache__get_global_membuffer_cache(void)
+{
+ static svn_membuffer_t *cache = NULL;
+ static svn_atomic_t initialized = 0;
+
+ svn_error_t *err
+ = svn_atomic__init_once(&initialized, initialize_cache, &cache, NULL);
+ if (err)
+ {
+ /* no caches today ... */
+ svn_error_clear(err);
+ return NULL;
}
return cache;
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/cmdline.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/cmdline.c Tue Oct 15 22:57:03 2013
@@ -67,11 +67,17 @@
#include "win32_crashrpt.h"
+#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1400)
+/* Before Visual Studio 2005, the C runtime didn't handle encodings for the
+ for the stdio output handling. */
+#define CMDLINE_USE_CUSTOM_ENCODING
+
/* The stdin encoding. If null, it's the same as the native encoding. */
static const char *input_encoding = NULL;
/* The stdout encoding. If null, it's the same as the native encoding. */
static const char *output_encoding = NULL;
+#endif
int
@@ -113,7 +119,7 @@ svn_cmdline_init(const char *progname, F
#endif
#ifdef WIN32
-#if _MSC_VER < 1400
+#ifdef CMDLINE_USE_CUSTOM_ENCODING
/* Initialize the input and output encodings. */
{
static char input_encoding_buffer[16];
@@ -127,7 +133,7 @@ svn_cmdline_init(const char *progname, F
"CP%u", (unsigned) GetConsoleOutputCP());
output_encoding = output_encoding_buffer;
}
-#endif /* _MSC_VER < 1400 */
+#endif /* CMDLINE_USE_CUSTOM_ENCODING */
#ifdef SVN_USE_WIN32_CRASHHANDLER
if (!getenv("SVN_CMDLINE_DISABLE_CRASH_HANDLER"))
@@ -257,10 +263,12 @@ svn_cmdline_cstring_from_utf8(const char
const char *src,
apr_pool_t *pool)
{
- if (output_encoding == NULL)
- return svn_utf_cstring_from_utf8(dest, src, pool);
- else
+#ifdef CMDLINE_USE_CUSTOM_ENCODING
+ if (output_encoding != NULL)
return svn_utf_cstring_from_utf8_ex2(dest, src, output_encoding, pool);
+#endif
+
+ return svn_utf_cstring_from_utf8(dest, src, pool);
}
@@ -278,10 +286,12 @@ svn_cmdline_cstring_to_utf8(const char *
const char *src,
apr_pool_t *pool)
{
- if (input_encoding == NULL)
- return svn_utf_cstring_to_utf8(dest, src, pool);
- else
+#ifdef CMDLINE_USE_CUSTOM_ENCODING
+ if (input_encoding != NULL)
return svn_utf_cstring_to_utf8_ex2(dest, src, input_encoding, pool);
+#endif
+
+ return svn_utf_cstring_to_utf8(dest, src, pool);
}
@@ -357,7 +367,7 @@ svn_cmdline_fputs(const char *string, FI
{
/* ### Issue #3014: Return a specific error for broken pipes,
* ### with a single element in the error chain. */
- if (APR_STATUS_IS_EPIPE(apr_get_os_error()))
+ if (SVN__APR_STATUS_IS_EPIPE(apr_get_os_error()))
return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
else
return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
@@ -380,7 +390,7 @@ svn_cmdline_fflush(FILE *stream)
{
/* ### Issue #3014: Return a specific error for broken pipes,
* ### with a single element in the error chain. */
- if (APR_STATUS_IS_EPIPE(apr_get_os_error()))
+ if (SVN__APR_STATUS_IS_EPIPE(apr_get_os_error()))
return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
else
return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
@@ -394,10 +404,12 @@ svn_cmdline_fflush(FILE *stream)
const char *svn_cmdline_output_encoding(apr_pool_t *pool)
{
+#ifdef CMDLINE_USE_CUSTOM_ENCODING
if (output_encoding)
return apr_pstrdup(pool, output_encoding);
- else
- return SVN_APR_LOCALE_CHARSET;
+#endif
+
+ return SVN_APR_LOCALE_CHARSET;
}
int
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_subr/compress.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/config.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/config.c Tue Oct 15 22:57:03 2013
@@ -23,6 +23,8 @@
+#include <assert.h>
+
#define APR_WANT_STRFUNC
#define APR_WANT_MEMFUNC
#include <apr_want.h>
@@ -93,6 +95,7 @@ svn_config_create2(svn_config_t **cfgp,
cfg->tmp_value = svn_stringbuf_create_empty(result_pool);
cfg->section_names_case_sensitive = section_names_case_sensitive;
cfg->option_names_case_sensitive = option_names_case_sensitive;
+ cfg->read_only = FALSE;
*cfgp = cfg;
return SVN_NO_ERROR;
@@ -484,7 +487,13 @@ make_string_from_option(const char **val
*/
if (opt->value && strchr(opt->value, '%'))
{
- apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool));
+ apr_pool_t *tmp_pool;
+
+ /* setting read-only mode should have expanded all values
+ * automatically. */
+ assert(!cfg->read_only);
+
+ tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool));
expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
opt->expanded = TRUE;
@@ -687,6 +696,15 @@ svn_config_set(svn_config_t *cfg,
cfg_section_t *sec;
cfg_option_t *opt;
+ /* Ignore write attempts to r/o configurations.
+ *
+ * Since we should never try to modify r/o data, trigger an assertion
+ * in debug mode.
+ */
+ assert(!cfg->read_only);
+ if (cfg->read_only)
+ return;
+
remove_expansions(cfg);
opt = find_option(cfg, section, option, &sec);
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/config_file.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/config_file.c Tue Oct 15 22:57:03 2013
@@ -37,6 +37,7 @@
#include "svn_ctype.h"
#include "svn_private_config.h"
+#include "private/svn_subr_private.h"
#ifdef __HAIKU__
# include <FindDirectory.h>
@@ -418,9 +419,48 @@ svn_config__sys_config_path(const char *
return SVN_NO_ERROR;
}
+/* Callback for svn_config_enumerate2: Continue to next value. */
+static svn_boolean_t
+expand_value(const char *name,
+ const char *value,
+ void *baton,
+ apr_pool_t *pool)
+{
+ return TRUE;
+}
+
+/* Callback for svn_config_enumerate_sections2:
+ * Enumerate and implicitly expand all values in this section.
+ */
+static svn_boolean_t
+expand_values_in_section(const char *name,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_config_t *cfg = baton;
+ svn_config_enumerate2(cfg, name, expand_value, NULL, pool);
+
+ return TRUE;
+}
+
/*** Exported interfaces. ***/
+void
+svn_config__set_read_only(svn_config_t *cfg,
+ apr_pool_t *scratch_pool)
+{
+ /* expand all items such that later calls to getters won't need to
+ * change internal state */
+ svn_config_enumerate_sections2(cfg, expand_values_in_section,
+ cfg, scratch_pool);
+
+ /* now, any modification attempt will be ignored / trigger an assertion
+ * in debug mode */
+ cfg->read_only = TRUE;
+}
+
+
svn_error_t *
svn_config__parse_file(svn_config_t *cfg, const char *file,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/config_impl.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/config_impl.h?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/config_impl.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/config_impl.h Tue Oct 15 22:57:03 2013
@@ -70,8 +70,11 @@ struct svn_config_t
/* Specifies whether option names are populated case sensitively. */
svn_boolean_t option_names_case_sensitive;
-};
+ /* When set, all modification attempts will be ignored.
+ * In debug mode, we will trigger an assertion. */
+ svn_boolean_t read_only;
+};
/* Read sections and options from a file. */
svn_error_t *svn_config__parse_file(svn_config_t *cfg,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/deprecated.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/deprecated.c Tue Oct 15 22:57:03 2013
@@ -1250,6 +1250,8 @@ svn_xml_make_header(svn_stringbuf_t **st
svn_xml_make_header2(str, NULL, pool);
}
+
+/*** From utf.c ***/
void
svn_utf_initialize(apr_pool_t *pool)
{
@@ -1257,6 +1259,18 @@ svn_utf_initialize(apr_pool_t *pool)
}
svn_error_t *
+svn_utf_cstring_from_utf8_ex(const char **dest,
+ const char *src,
+ const char *topage,
+ const char *convset_key,
+ apr_pool_t *pool)
+{
+ return svn_utf_cstring_from_utf8_ex2(dest, src, topage, pool);
+}
+
+
+/*** From subst.c ***/
+svn_error_t *
svn_subst_build_keywords(svn_subst_keywords_t *kw,
const char *keywords_val,
const char *rev,
@@ -1306,3 +1320,4 @@ svn_ver_check_list(const svn_version_t *
{
return svn_ver_check_list2(my_version, checklist, svn_ver_compatible);
}
+
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/io.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/io.c Tue Oct 15 22:57:03 2013
@@ -3487,7 +3487,7 @@ do_io_file_wrapper_cleanup(apr_file_t *f
/* ### Issue #3014: Return a specific error for broken pipes,
* ### with a single element in the error chain. */
- if (APR_STATUS_IS_EPIPE(status))
+ if (SVN__APR_STATUS_IS_EPIPE(status))
return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
if (name)
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_subr/packed_data.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/prefix_string.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/prefix_string.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/prefix_string.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/prefix_string.c Tue Oct 15 22:57:03 2013
@@ -219,7 +219,7 @@ svn_prefix_string__create(svn_prefix_tre
new_node->sub_nodes = apr_palloc(tree->pool, sizeof(node_t *));
new_node->sub_nodes[0] = sub_node;
- memcpy(sub_node->key.data, sub_node->key.data + match, 8 - match);
+ memmove(sub_node->key.data, sub_node->key.data + match, 8 - match);
/* replace old sub-node with new one and continue lookup */
sub_node->key.prefix = new_node;
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_subr/prefix_string.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/sorts.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/sorts.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/sorts.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/sorts.c Tue Oct 15 22:57:03 2013
@@ -453,4 +453,4 @@ svn_priority_queue__push(svn_priority_qu
memcpy(apr_array_push(queue->elements), element, queue->elements->elt_size);
heap_bubble_down(queue, queue->elements->nelts - 1);
-}
\ No newline at end of file
+}
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/stream.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/stream.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/stream.c Tue Oct 15 22:57:03 2013
@@ -1379,6 +1379,36 @@ svn_stream_checksummed(svn_stream_t *str
/* Miscellaneous stream functions. */
+
+svn_error_t *
+svn_stringbuf_from_stream(svn_stringbuf_t **str,
+ svn_stream_t *stream,
+ apr_size_t len_hint,
+ apr_pool_t *pool)
+{
+#define MIN_READ_SIZE 64
+
+ apr_size_t to_read = 0;
+ svn_stringbuf_t *text
+ = svn_stringbuf_create_ensure(len_hint ? len_hint : MIN_READ_SIZE, pool);
+
+ do
+ {
+ to_read = text->blocksize - 1 - text->len;
+ SVN_ERR(svn_stream_read(stream, text->data + text->len, &to_read));
+ text->len += to_read;
+
+ if (to_read && text->blocksize < text->len + MIN_READ_SIZE)
+ svn_stringbuf_ensure(text, text->blocksize * 2);
+ }
+ while (to_read);
+
+ text->data[text->len] = '\0';
+ *str = text;
+
+ return SVN_NO_ERROR;
+}
+
struct stringbuf_stream_baton
{
svn_stringbuf_t *str;
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/string.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/string.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/string.c Tue Oct 15 22:57:03 2013
@@ -53,9 +53,9 @@ membuf_create(void **data, apr_size_t *s
/* apr_palloc will allocate multiples of 8.
* Thus, we would waste some of that memory if we stuck to the
* smaller size. Note that this is safe even if apr_palloc would
- * use some other aligment or none at all. */
+ * use some other alignment or none at all. */
minimum_size = APR_ALIGN_DEFAULT(minimum_size);
- *data = (!minimum_size ? NULL : apr_palloc(pool, minimum_size));
+ *data = apr_palloc(pool, minimum_size);
*size = minimum_size;
}
@@ -121,7 +121,10 @@ svn_membuf__resize(svn_membuf_t *membuf,
const apr_size_t old_size = membuf->size;
membuf_ensure(&membuf->data, &membuf->size, size, membuf->pool);
- if (membuf->data && old_data && old_data != membuf->data)
+
+ /* If we re-allocated MEMBUF->DATA, it cannot be NULL.
+ * Statically initialized membuffers (OLD_DATA) may be NULL, though. */
+ if (old_data && old_data != membuf->data)
memcpy(membuf->data, old_data, old_size);
}
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf.c Tue Oct 15 22:57:03 2013
@@ -934,18 +934,6 @@ svn_utf_cstring_from_utf8_ex2(const char
return err;
}
-
-svn_error_t *
-svn_utf_cstring_from_utf8_ex(const char **dest,
- const char *src,
- const char *topage,
- const char *convset_key,
- apr_pool_t *pool)
-{
- return svn_utf_cstring_from_utf8_ex2(dest, src, topage, pool);
-}
-
-
const char *
svn_utf__cstring_from_utf8_fuzzy(const char *src,
apr_pool_t *pool,
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf8proc.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf8proc/utf8proc.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf8proc/utf8proc.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf8proc/utf8proc_data.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crashrpt.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crashrpt.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crashrpt.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crashrpt.c Tue Oct 15 22:57:03 2013
@@ -427,13 +427,15 @@ write_var_values(PSYMBOL_INFO sym_info,
format_value(value_str, sym_info->ModBase, sym_info->TypeIndex,
(void *)var_data);
- fprintf(log_file, "%s=%s", sym_info->Name, value_str);
+ fprintf(log_file, "%.*s=%s", (int)sym_info->NameLen, sym_info->Name,
+ value_str);
}
if (!log_params && sym_info->Flags & SYMFLAG_LOCAL)
{
format_value(value_str, sym_info->ModBase, sym_info->TypeIndex,
(void *)var_data);
- fprintf(log_file, " %s = %s\n", sym_info->Name, value_str);
+ fprintf(log_file, " %.*s = %s\n", (int)sym_info->NameLen,
+ sym_info->Name, value_str);
}
return TRUE;
@@ -466,8 +468,10 @@ write_function_detail(STACKFRAME64 stack
if (SymFromAddr_(proc, stack_frame.AddrPC.Offset, &func_disp, pIHS))
{
fprintf(log_file,
- "#%d 0x%08I64x in %.200s(",
- nr_of_frame, stack_frame.AddrPC.Offset, pIHS->Name);
+ "#%d 0x%08I64x in %.*s(",
+ nr_of_frame, stack_frame.AddrPC.Offset,
+ pIHS->NameLen > 200 ? 200 : (int)pIHS->NameLen,
+ pIHS->Name);
/* restrict symbol enumeration to this frame only */
ih_stack_frame.InstructionOffset = stack_frame.AddrPC.Offset;
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/old-and-busted.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/old-and-busted.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/old-and-busted.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/old-and-busted.c Tue Oct 15 22:57:03 2013
@@ -811,11 +811,15 @@ atts_to_entry(svn_wc_entry_t **new_entry
### not used by loggy; no need to set MODIFY_FLAGS */
entry->url = extract_string(atts, ENTRIES_ATTR_URL, pool);
+ if (entry->url)
+ entry->url = svn_uri_canonicalize(entry->url, pool);
/* Set up repository root. Make sure it is a prefix of url.
### not used by loggy; no need to set MODIFY_FLAGS */
entry->repos = extract_string(atts, ENTRIES_ATTR_REPOS, pool);
+ if (entry->repos)
+ entry->repos = svn_uri_canonicalize(entry->repos, pool);
if (entry->url && entry->repos
&& !svn_uri__is_ancestor(entry->repos, entry->url))
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/update_editor.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/update_editor.c Tue Oct 15 22:57:03 2013
@@ -3010,18 +3010,55 @@ absent_node(const char *path,
kind = svn_node_unknown;
}
- if (status == svn_wc__db_status_normal
- && kind == svn_node_dir)
+ if (status == svn_wc__db_status_normal)
{
- /* We found an obstructing working copy!
+ svn_boolean_t wcroot;
+ /* We found an obstructing working copy or a file external! */
- We can do two things now:
- 1) notify the user, record a skip, etc.
- 2) Just record the absent node in BASE in the parent
- working copy.
+ SVN_ERR(svn_wc__db_is_wcroot(&wcroot, eb->db, local_abspath,
+ scratch_pool));
- As option 2 happens to be exactly what we do anyway, lets do that.
- */
+ if (wcroot)
+ {
+ /*
+ We have an obstructing working copy; possibly a directory external
+
+ We can do two things now:
+ 1) notify the user, record a skip, etc.
+ 2) Just record the absent node in BASE in the parent
+ working copy.
+
+ As option 2 happens to be exactly what we do anyway, fall through.
+ */
+ }
+ else
+ {
+ /* The server asks us to replace a file external
+ (Existing BASE node; not reported by the working copy crawler or
+ there would have been a delete_entry() call.
+
+ There is no way we can store this state in the working copy as
+ the BASE layer is already filled.
+
+ We could error out, but that is not helping anybody; the user is not
+ even seeing with what the file external would be replaced, so let's
+ report a skip and continue the update.
+ */
+
+ if (eb->notify_func)
+ {
+ svn_wc_notify_t *notify;
+ notify = svn_wc_create_notify(
+ local_abspath,
+ svn_wc_notify_update_skip_obstruction,
+ scratch_pool);
+
+ eb->notify_func(eb->notify_baton, notify, scratch_pool);
+ }
+
+ svn_pool_destroy(scratch_pool);
+ return SVN_NO_ERROR;
+ }
}
else if (status == svn_wc__db_status_not_present
|| status == svn_wc__db_status_server_excluded
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-queries.sql?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-queries.sql Tue Oct 15 22:57:03 2013
@@ -1571,7 +1571,7 @@ WHERE wc_id = ?1
AND moved_to IS NOT NULL
-- STMT_SELECT_MOVED_OUTSIDE
-SELECT local_relpath, moved_to FROM nodes
+SELECT local_relpath, moved_to, op_depth FROM nodes
WHERE wc_id = ?1
AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
AND op_depth >= ?3