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 2014/05/16 20:06:32 UTC
svn commit: r1595277 - in /subversion/trunk/subversion/libsvn_fs_x: ./
cached_data.c cached_data.h dag.c dag.h temp_serializer.c temp_serializer.h
transaction.c tree.c
Author: stefan2
Date: Fri May 16 18:06:31 2014
New Revision: 1595277
URL: http://svn.apache.org/r1595277
Log:
Sync'ing FSX with FSFS:
Merge r1554711 from /subversion/libsvn_fs_fs into subversion/libsvn_fs_x.
Conflicts were due to name prefix differences (svn_fs_x vs svn_fs_fs).
This ports the "directories are arrays now" change.
Modified:
subversion/trunk/subversion/libsvn_fs_x/ (props changed)
subversion/trunk/subversion/libsvn_fs_x/cached_data.c
subversion/trunk/subversion/libsvn_fs_x/cached_data.h
subversion/trunk/subversion/libsvn_fs_x/dag.c
subversion/trunk/subversion/libsvn_fs_x/dag.h
subversion/trunk/subversion/libsvn_fs_x/temp_serializer.c
subversion/trunk/subversion/libsvn_fs_x/temp_serializer.h
subversion/trunk/subversion/libsvn_fs_x/transaction.c
subversion/trunk/subversion/libsvn_fs_x/tree.c
Propchange: subversion/trunk/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
Merged /subversion/trunk/subversion/libsvn_fs_fs:r1554711
Modified: subversion/trunk/subversion/libsvn_fs_x/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/cached_data.c?rev=1595277&r1=1595276&r2=1595277&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/cached_data.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/cached_data.c Fri May 16 18:06:31 2014
@@ -26,6 +26,11 @@
#include "svn_hash.h"
#include "svn_ctype.h"
+#include "svn_sorts.h"
+
+#include "private/svn_io_private.h"
+#include "private/svn_sorts_private.h"
+#include "private/svn_subr_private.h"
#include "private/svn_temp_serializer.h"
#include "fs_x.h"
@@ -1919,30 +1924,174 @@ svn_fs_x__get_file_delta_stream(svn_txde
return SVN_NO_ERROR;
}
+/* Return TRUE when all svn_fs_dirent_t* in ENTRIES are already sorted
+ by their respective name. */
+static svn_boolean_t
+sorted(apr_array_header_t *entries)
+{
+ int i;
+
+ const svn_fs_dirent_t * const *dirents = (const void *)entries->elts;
+ for (i = 0; i < entries->nelts-1; ++i)
+ if (strcmp(dirents[i]->name, dirents[i+1]->name) > 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Compare the names of the two dirents given in **A and **B. */
+static int
+compare_dirents(const void *a, const void *b)
+{
+ const svn_fs_dirent_t *lhs = *((const svn_fs_dirent_t * const *) a);
+ const svn_fs_dirent_t *rhs = *((const svn_fs_dirent_t * const *) b);
+
+ return strcmp(lhs->name, rhs->name);
+}
+
+/* Compare the name of the dirents given in **A with the C string in *B. */
+static int
+compare_dirent_name(const void *a, const void *b)
+{
+ const svn_fs_dirent_t *lhs = *((const svn_fs_dirent_t * const *) a);
+ const char *rhs = b;
+
+ return strcmp(lhs->name, rhs);
+}
+
+/* Into ENTRIES, read all directories entries from the key-value text in
+ * STREAM. If INCREMENTAL is TRUE, read until the end of the STREAM and
+ * update the data. ID is provided for nicer error messages.
+ */
+static svn_error_t *
+read_dir_entries(apr_array_header_t *entries,
+ svn_stream_t *stream,
+ svn_boolean_t incremental,
+ const svn_fs_id_t *id,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_hash_t *hash = incremental ? svn_hash__make(scratch_pool) : NULL;
+ const char *terminator = SVN_HASH_TERMINATOR;
+
+ /* Read until the terminator (non-incremental) or the end of STREAM
+ (incremental mode). In the latter mode, we use a temporary HASH
+ to make updating and removing entries cheaper. */
+ while (1)
+ {
+ svn_hash__entry_t entry;
+ svn_fs_dirent_t *dirent;
+ char *str;
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_hash__read_entry(&entry, stream, terminator,
+ incremental, iterpool));
+
+ /* End of directory? */
+ if (entry.key == NULL)
+ {
+ /* In incremental mode, we skip the terminator and read the
+ increments following it until the end of the stream. */
+ if (incremental && terminator)
+ terminator = NULL;
+ else
+ break;
+ }
+
+ /* Deleted entry? */
+ if (entry.val == NULL)
+ {
+ /* We must be in incremental mode */
+ assert(hash);
+ apr_hash_set(hash, entry.key, entry.keylen, NULL);
+ continue;
+ }
+
+ /* Add a new directory entry. */
+ dirent = apr_pcalloc(result_pool, sizeof(*dirent));
+ dirent->name = apr_pstrmemdup(result_pool, entry.key, entry.keylen);
+
+ str = svn_cstring_tokenize(" ", &entry.val);
+ if (str == NULL)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory entry corrupt in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
+
+ if (strcmp(str, SVN_FS_X__KIND_FILE) == 0)
+ {
+ dirent->kind = svn_node_file;
+ }
+ else if (strcmp(str, SVN_FS_X__KIND_DIR) == 0)
+ {
+ dirent->kind = svn_node_dir;
+ }
+ else
+ {
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory entry corrupt in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
+ }
+
+ str = svn_cstring_tokenize(" ", &entry.val);
+ if (str == NULL)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ _("Directory entry corrupt in '%s'"),
+ svn_fs_x__id_unparse(id, scratch_pool)->data);
+
+ dirent->id = svn_fs_x__id_parse(str, strlen(str), result_pool);
+
+ /* In incremental mode, update the hash; otherwise, write to the
+ * final array. */
+ if (incremental)
+ apr_hash_set(hash, entry.key, entry.keylen, dirent);
+ else
+ APR_ARRAY_PUSH(entries, svn_fs_dirent_t *) = dirent;
+ }
+
+ /* Convert container to a sorted array. */
+ if (incremental)
+ {
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(iterpool, hash); hi; hi = apr_hash_next(hi))
+ APR_ARRAY_PUSH(entries, svn_fs_dirent_t *)
+ = svn__apr_hash_index_val(hi);
+ }
+
+ if (!sorted(entries))
+ qsort(entries->elts, entries->nelts, entries->elt_size, compare_dirents);
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
/* Fetch the contents of a directory into ENTRIES. Values are stored
as filename to string mappings; further conversion is necessary to
convert them into svn_fs_dirent_t values. */
static svn_error_t *
-get_dir_contents(apr_hash_t *entries,
+get_dir_contents(apr_array_header_t **entries,
svn_fs_t *fs,
node_revision_t *noderev,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_stream_t *contents;
+ *entries = apr_array_make(result_pool, 16, sizeof(svn_fs_dirent_t *));
if (noderev->data_rep
&& ! svn_fs_x__is_revision(noderev->data_rep->id.change_set))
{
const char *filename
- = svn_fs_x__path_txn_node_children(fs, noderev->id, pool);
+ = svn_fs_x__path_txn_node_children(fs, noderev->id, scratch_pool);
/* The representation is mutable. Read the old directory
contents from the mutable children file, followed by the
changes we've made in this transaction. */
- SVN_ERR(svn_stream_open_readonly(&contents, filename, pool, pool));
- SVN_ERR(svn_hash_read2(entries, contents, SVN_HASH_TERMINATOR, pool));
- SVN_ERR(svn_hash_read_incremental(entries, contents, NULL, pool));
+ SVN_ERR(svn_stream_open_readonly(&contents, filename, scratch_pool,
+ scratch_pool));
+ SVN_ERR(read_dir_entries(*entries, contents, TRUE, noderev->id,
+ result_pool, scratch_pool));
SVN_ERR(svn_stream_close(contents));
}
else if (noderev->data_rep)
@@ -1951,7 +2100,7 @@ get_dir_contents(apr_hash_t *entries,
* Also undeltify content before parsing it. Otherwise, we could only
* parse it byte-by-byte.
*/
- apr_pool_t *text_pool = svn_pool_create(pool);
+ apr_pool_t *text_pool = svn_pool_create(scratch_pool);
apr_size_t len = noderev->data_rep->expanded_size;
svn_stringbuf_t *text = svn_stringbuf_create_ensure(len, text_pool);
text->len = len;
@@ -1963,7 +2112,8 @@ get_dir_contents(apr_hash_t *entries,
/* de-serialize hash */
contents = svn_stream_from_stringbuf(text, text_pool);
- SVN_ERR(svn_hash_read2(entries, contents, SVN_HASH_TERMINATOR, pool));
+ SVN_ERR(read_dir_entries(*entries, contents, FALSE, noderev->id,
+ result_pool, scratch_pool));
svn_pool_destroy(text_pool);
}
@@ -1972,66 +2122,6 @@ get_dir_contents(apr_hash_t *entries,
}
-/* Given a hash STR_ENTRIES with values as svn_string_t as specified
- in an FSX directory contents listing, return a hash of dirents in
- *ENTRIES_P. Use ID to generate more helpful error messages.
- Perform allocations in POOL. */
-static svn_error_t *
-parse_dir_entries(apr_hash_t **entries_p,
- apr_hash_t *str_entries,
- const svn_fs_id_t *id,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
-
- *entries_p = apr_hash_make(pool);
-
- /* Translate the string dir entries into real entries. */
- for (hi = apr_hash_first(pool, str_entries); hi; hi = apr_hash_next(hi))
- {
- const char *name = svn__apr_hash_index_key(hi);
- svn_string_t *str_val = svn__apr_hash_index_val(hi);
- char *str, *last_str;
- svn_fs_dirent_t *dirent = apr_pcalloc(pool, sizeof(*dirent));
-
- last_str = apr_pstrdup(pool, str_val->data);
- dirent->name = apr_pstrdup(pool, name);
-
- str = svn_cstring_tokenize(" ", &last_str);
- if (str == NULL)
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, pool)->data);
-
- if (strcmp(str, SVN_FS_X__KIND_FILE) == 0)
- {
- dirent->kind = svn_node_file;
- }
- else if (strcmp(str, SVN_FS_X__KIND_DIR) == 0)
- {
- dirent->kind = svn_node_dir;
- }
- else
- {
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, pool)->data);
- }
-
- str = svn_cstring_tokenize(" ", &last_str);
- if (str == NULL)
- return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Directory entry corrupt in '%s'"),
- svn_fs_x__id_unparse(id, pool)->data);
-
- dirent->id = svn_fs_x__id_parse(str, strlen(str), pool);
-
- svn_hash_sets(*entries_p, dirent->name, dirent);
- }
-
- return SVN_NO_ERROR;
-}
-
/* Return the cache object in FS responsible to storing the directory the
* NODEREV plus the corresponding pre-allocated *KEY.
*/
@@ -2068,39 +2158,47 @@ locate_dir_cache(svn_fs_t *fs,
}
svn_error_t *
-svn_fs_x__rep_contents_dir(apr_hash_t **entries_p,
+svn_fs_x__rep_contents_dir(apr_array_header_t **entries_p,
svn_fs_t *fs,
node_revision_t *noderev,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_fs_x__id_part_t key;
- apr_hash_t *unparsed_entries, *parsed_entries;
/* find the cache we may use */
- svn_cache__t *cache = locate_dir_cache(fs, &key, noderev, pool);
+ svn_cache__t *cache = locate_dir_cache(fs, &key, noderev, scratch_pool);
if (cache)
{
svn_boolean_t found;
- SVN_ERR(svn_cache__get((void **)entries_p, &found, cache, &key, pool));
+ SVN_ERR(svn_cache__get((void **)entries_p, &found, cache, &key,
+ result_pool));
if (found)
return SVN_NO_ERROR;
}
- /* Read in the directory hash. */
- unparsed_entries = apr_hash_make(pool);
- SVN_ERR(get_dir_contents(unparsed_entries, fs, noderev, pool));
- SVN_ERR(parse_dir_entries(&parsed_entries, unparsed_entries,
- noderev->id, pool));
+ /* Read in the directory contents. */
+ SVN_ERR(get_dir_contents(entries_p, fs, noderev, result_pool,
+ scratch_pool));
/* Update the cache, if we are to use one. */
if (cache)
- SVN_ERR(svn_cache__set(cache, &key, parsed_entries, pool));
+ SVN_ERR(svn_cache__set(cache, &key, *entries_p, scratch_pool));
- *entries_p = parsed_entries;
return SVN_NO_ERROR;
}
+svn_fs_dirent_t *
+svn_fs_x__find_dir_entry(apr_array_header_t *entries,
+ const char *name,
+ int *hint)
+{
+ svn_fs_dirent_t **result
+ = svn_sort__array_lookup(entries, name, hint, compare_dirent_name);
+ return result ? *result : NULL;
+}
+
svn_error_t *
svn_fs_x__rep_contents_dir_entry(svn_fs_dirent_t **dirent,
svn_fs_t *fs,
@@ -2129,18 +2227,18 @@ svn_fs_x__rep_contents_dir_entry(svn_fs_
/* fetch data from disk if we did not find it in the cache */
if (! found)
{
- apr_hash_t *entries;
+ apr_array_header_t *entries;
svn_fs_dirent_t *entry;
svn_fs_dirent_t *entry_copy = NULL;
/* read the dir from the file system. It will probably be put it
into the cache for faster lookup in future calls. */
SVN_ERR(svn_fs_x__rep_contents_dir(&entries, fs, noderev,
- scratch_pool));
+ scratch_pool, scratch_pool));
/* find desired entry and return a copy in POOL, if found */
- entry = svn_hash_gets(entries, name);
- if (entry != NULL)
+ entry = svn_fs_x__find_dir_entry(entries, name, NULL);
+ if (entry)
{
entry_copy = apr_palloc(result_pool, sizeof(*entry_copy));
entry_copy->name = apr_pstrdup(result_pool, entry->name);
Modified: subversion/trunk/subversion/libsvn_fs_x/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/cached_data.h?rev=1595277&r1=1595276&r2=1595277&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/cached_data.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/cached_data.h Fri May 16 18:06:31 2014
@@ -122,15 +122,25 @@ svn_fs_x__get_file_delta_stream(svn_txde
node_revision_t *target,
apr_pool_t *pool);
-/* Set *ENTRIES to an apr_hash_t of dirent structs that contain the
- directory entries of node-revision NODEREV in filesystem FS. The
- returned table (and its keys and values) is allocated in POOL,
- which is also used for temporary allocations. */
+/* Set *ENTRIES to an apr_array_header_t of dirent structs that contain
+ the directory entries of node-revision NODEREV in filesystem FS. The
+ returned table is allocated in RESULT_POOL and entries are sorted
+ lexicographically. SCRATCH_POOL is used for temporary allocations. */
svn_error_t *
-svn_fs_x__rep_contents_dir(apr_hash_t **entries_p,
+svn_fs_x__rep_contents_dir(apr_array_header_t **entries_p,
svn_fs_t *fs,
node_revision_t *noderev,
- apr_pool_t *pool);
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/* Return the directory entry from ENTRIES that matches NAME. If no such
+ entry exists, return NULL. If HINT is not NULL, set *HINT to the array
+ index of the entry returned. Successive calls in a linear scan scenario
+ will be faster called with the same HINT variable. */
+svn_fs_dirent_t *
+svn_fs_x__find_dir_entry(apr_array_header_t *entries,
+ const char *name,
+ int *hint);
/* Set *DIRENT to the entry identified by NAME in the directory given
by NODEREV in filesystem FS. If no such entry exits, *DIRENT will
Modified: subversion/trunk/subversion/libsvn_fs_x/dag.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/dag.c?rev=1595277&r1=1595276&r2=1595277&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/dag.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/dag.c Fri May 16 18:06:31 2014
@@ -415,9 +415,9 @@ make_entry(dag_node_t **child_p,
svn_error_t *
-svn_fs_x__dag_dir_entries(apr_hash_t **entries,
- dag_node_t *node,
- apr_pool_t *pool)
+svn_fs_x__dag_dir_entries(apr_array_header_t **entries,
+ dag_node_t *node,
+ apr_pool_t *pool)
{
node_revision_t *noderev;
@@ -427,7 +427,7 @@ svn_fs_x__dag_dir_entries(apr_hash_t **e
return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
_("Can't get entries of non-directory"));
- return svn_fs_x__rep_contents_dir(entries, node->fs, noderev, pool);
+ return svn_fs_x__rep_contents_dir(entries, node->fs, noderev, pool, pool);
}
svn_error_t *
@@ -856,22 +856,16 @@ svn_fs_x__dag_delete_if_mutable(svn_fs_t
/* Else it's mutable. Recurse on directories... */
if (node->kind == svn_node_dir)
{
- apr_hash_t *entries;
- apr_hash_index_t *hi;
+ apr_array_header_t *entries;
+ int i;
- /* Loop over hash entries */
+ /* Loop over directory entries */
SVN_ERR(svn_fs_x__dag_dir_entries(&entries, node, pool));
if (entries)
- {
- for (hi = apr_hash_first(pool, entries);
- hi;
- hi = apr_hash_next(hi))
- {
- svn_fs_dirent_t *dirent = svn__apr_hash_index_val(hi);
-
- SVN_ERR(svn_fs_x__dag_delete_if_mutable(fs, dirent->id, pool));
- }
- }
+ for (i = 0; i < entries->nelts; ++i)
+ SVN_ERR(svn_fs_x__dag_delete_if_mutable(fs,
+ APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *)->id,
+ pool));
}
/* ... then delete the node itself, after deleting any mutable
Modified: subversion/trunk/subversion/libsvn_fs_x/dag.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/dag.h?rev=1595277&r1=1595276&r2=1595277&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/dag.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/dag.h Fri May 16 18:06:31 2014
@@ -264,11 +264,10 @@ svn_fs_x__dag_open(dag_node_t **child_p,
apr_pool_t *scratch_pool);
-/* Set *ENTRIES_P to a hash table of NODE's entries. The keys of the
- table are entry names, and the values are svn_fs_dirent_t's. The
- returned table (and its keys and values) is allocated in POOL,
- which is also used for temporary allocations. */
-svn_error_t *svn_fs_x__dag_dir_entries(apr_hash_t **entries_p,
+/* Set *ENTRIES_P to an array of NODE's entries, sorted by entry names,
+ and the values are svn_fs_dirent_t's. The returned table (and elements)
+ is allocated in POOL, which is also used for temporary allocations. */
+svn_error_t *svn_fs_x__dag_dir_entries(apr_array_header_t **entries_p,
dag_node_t *node,
apr_pool_t *pool);
Modified: subversion/trunk/subversion/libsvn_fs_x/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/temp_serializer.c?rev=1595277&r1=1595276&r2=1595277&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/temp_serializer.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/temp_serializer.c Fri May 16 18:06:31 2014
@@ -24,16 +24,18 @@
#include "svn_pools.h"
#include "svn_hash.h"
-
-#include "id.h"
+#include "svn_sorts.h"
#include "svn_fs.h"
#include "private/svn_fs_util.h"
+#include "private/svn_sorts_private.h"
#include "private/svn_temp_serializer.h"
#include "private/svn_subr_private.h"
+#include "id.h"
#include "temp_serializer.h"
#include "low_level.h"
+#include "cached_data.h"
/* Utility to encode a signed NUMBER into a variable-length sequence of
* 8-bit chars in KEY_BUFFER and return the last writen position.
@@ -181,8 +183,8 @@ svn_fs_x__deserialize_apr_array(void *bu
(*array)->pool = pool;
}
-/* auxiliary structure representing the content of a directory hash */
-typedef struct hash_data_t
+/* auxilliary structure representing the content of a directory array */
+typedef struct dir_data_t
{
/* number of entries in the directory */
apr_size_t count;
@@ -205,14 +207,7 @@ typedef struct hash_data_t
/* size of the serialized entries and don't be too wasteful
* (needed since the entries are no longer in sequence) */
apr_uint32_t *lengths;
-} hash_data_t;
-
-static int
-compare_dirent_id_names(const void *lhs, const void *rhs)
-{
- return strcmp((*(const svn_fs_dirent_t *const *)lhs)->name,
- (*(const svn_fs_dirent_t *const *)rhs)->name);
-}
+} dir_data_t;
/* Utility function to serialize the *ENTRY_P into a the given
* serialization CONTEXT. Return the serialized size of the
@@ -243,91 +238,85 @@ serialize_dir_entry(svn_temp_serializer_
* context to be returned. Allocation will be made form POOL.
*/
static svn_temp_serializer__context_t *
-serialize_dir(apr_hash_t *entries, apr_pool_t *pool)
+serialize_dir(apr_array_header_t *entries, apr_pool_t *pool)
{
- hash_data_t hash_data;
- apr_hash_index_t *hi;
+ dir_data_t dir_data;
apr_size_t i = 0;
svn_temp_serializer__context_t *context;
/* calculate sizes */
- apr_size_t count = apr_hash_count(entries);
+ apr_size_t count = entries->nelts;
apr_size_t over_provision = 2 + count / 4;
apr_size_t entries_len = (count + over_provision) * sizeof(svn_fs_dirent_t*);
apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
/* copy the hash entries to an auxiliary struct of known layout */
- hash_data.count = count;
- hash_data.over_provision = over_provision;
- hash_data.operations = 0;
- hash_data.entries = apr_palloc(pool, entries_len);
- hash_data.lengths = apr_palloc(pool, lengths_len);
-
- for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi), ++i)
- hash_data.entries[i] = svn__apr_hash_index_val(hi);
-
- /* sort entry index by ID name */
- qsort(hash_data.entries,
- count,
- sizeof(*hash_data.entries),
- compare_dirent_id_names);
+ dir_data.count = count;
+ dir_data.over_provision = over_provision;
+ dir_data.operations = 0;
+ dir_data.entries = apr_palloc(pool, entries_len);
+ dir_data.lengths = apr_palloc(pool, lengths_len);
+
+ for (i = 0; i < count; ++i)
+ dir_data.entries[i] = APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *);
/* Serialize that aux. structure into a new one. Also, provide a good
* estimate for the size of the buffer that we will need. */
- context = svn_temp_serializer__init(&hash_data,
- sizeof(hash_data),
+ context = svn_temp_serializer__init(&dir_data,
+ sizeof(dir_data),
50 + count * 200 + entries_len,
pool);
/* serialize entries references */
svn_temp_serializer__push(context,
- (const void * const *)&hash_data.entries,
+ (const void * const *)&dir_data.entries,
entries_len);
/* serialize the individual entries and their sub-structures */
for (i = 0; i < count; ++i)
serialize_dir_entry(context,
- &hash_data.entries[i],
- &hash_data.lengths[i]);
+ &dir_data.entries[i],
+ &dir_data.lengths[i]);
svn_temp_serializer__pop(context);
/* serialize entries references */
svn_temp_serializer__push(context,
- (const void * const *)&hash_data.lengths,
+ (const void * const *)&dir_data.lengths,
lengths_len);
return context;
}
-/* Utility function to reconstruct a dir entries hash from serialized data
- * in BUFFER and HASH_DATA. Allocation will be made form POOL.
+/* Utility function to reconstruct a dir entries array from serialized data
+ * in BUFFER and DIR_DATA. Allocation will be made form POOL.
*/
-static apr_hash_t *
-deserialize_dir(void *buffer, hash_data_t *hash_data, apr_pool_t *pool)
+static apr_array_header_t *
+deserialize_dir(void *buffer, dir_data_t *dir_data, apr_pool_t *pool)
{
- apr_hash_t *result = svn_hash__make(pool);
+ apr_array_header_t *result
+ = apr_array_make(pool, dir_data->count, sizeof(svn_fs_dirent_t *));
apr_size_t i;
apr_size_t count;
svn_fs_dirent_t *entry;
svn_fs_dirent_t **entries;
/* resolve the reference to the entries array */
- svn_temp_deserializer__resolve(buffer, (void **)&hash_data->entries);
- entries = hash_data->entries;
+ svn_temp_deserializer__resolve(buffer, (void **)&dir_data->entries);
+ entries = dir_data->entries;
/* fixup the references within each entry and add it to the hash */
- for (i = 0, count = hash_data->count; i < count; ++i)
+ for (i = 0, count = dir_data->count; i < count; ++i)
{
svn_temp_deserializer__resolve(entries, (void **)&entries[i]);
- entry = hash_data->entries[i];
+ entry = dir_data->entries[i];
/* pointer fixup */
svn_temp_deserializer__resolve(entry, (void **)&entry->name);
svn_fs_x__id_deserialize(entry, (svn_fs_id_t **)&entry->id, pool);
/* add the entry to the hash */
- svn_hash_sets(result, entry->name, entry);
+ APR_ARRAY_PUSH(result, svn_fs_dirent_t *) = entry;
}
/* return the now complete hash */
@@ -754,7 +743,7 @@ return_serialized_dir_context(svn_temp_s
*data = serialized->data;
*data_len = serialized->blocksize;
- ((hash_data_t *)serialized->data)->len = serialized->len;
+ ((dir_data_t *)serialized->data)->len = serialized->len;
return SVN_NO_ERROR;
}
@@ -765,7 +754,7 @@ svn_fs_x__serialize_dir_entries(void **d
void *in,
apr_pool_t *pool)
{
- apr_hash_t *dir = in;
+ apr_array_header_t *dir = in;
/* serialize the dir content into a new serialization context
* and return the serialized data */
@@ -781,10 +770,10 @@ svn_fs_x__deserialize_dir_entries(void *
apr_pool_t *pool)
{
/* Copy the _full_ buffer as it also contains the sub-structures. */
- hash_data_t *hash_data = (hash_data_t *)data;
+ dir_data_t *dir_data = (dir_data_t *)data;
/* reconstruct the hash from the serialized data */
- *out = deserialize_dir(hash_data, hash_data, pool);
+ *out = deserialize_dir(dir_data, dir_data, pool);
return SVN_NO_ERROR;
}
@@ -857,22 +846,22 @@ svn_fs_x__extract_dir_entry(void **out,
void *baton,
apr_pool_t *pool)
{
- const hash_data_t *hash_data = data;
+ const dir_data_t *dir_data = data;
const char* name = baton;
svn_boolean_t found;
/* resolve the reference to the entries array */
const svn_fs_dirent_t * const *entries =
- svn_temp_deserializer__ptr(data, (const void *const *)&hash_data->entries);
+ svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->entries);
/* resolve the reference to the lengths array */
const apr_uint32_t *lengths =
- svn_temp_deserializer__ptr(data, (const void *const *)&hash_data->lengths);
+ svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths);
/* binary search for the desired entry by name */
apr_size_t pos = find_entry((svn_fs_dirent_t **)entries,
name,
- hash_data->count,
+ dir_data->count,
&found);
/* de-serialize that entry or return NULL, if no match has been found */
@@ -912,14 +901,33 @@ slowly_replace_dir_entry(void **data,
apr_pool_t *pool)
{
replace_baton_t *replace_baton = (replace_baton_t *)baton;
- hash_data_t *hash_data = (hash_data_t *)*data;
- apr_hash_t *dir;
+ dir_data_t *dir_data = (dir_data_t *)*data;
+ apr_array_header_t *dir;
+ int idx = -1;
+ svn_fs_dirent_t *entry;
SVN_ERR(svn_fs_x__deserialize_dir_entries((void **)&dir,
*data,
- hash_data->len,
+ dir_data->len,
pool));
- svn_hash_sets(dir, replace_baton->name, replace_baton->new_entry);
+
+ entry = svn_fs_x__find_dir_entry(dir, replace_baton->name, &idx);
+
+ /* Replacement or removal? */
+ if (replace_baton->new_entry)
+ {
+ /* Replace ENTRY with / insert the NEW_ENTRY */
+ if (entry)
+ APR_ARRAY_IDX(dir, idx, svn_fs_dirent_t *) = replace_baton->new_entry;
+ else
+ svn_sort__array_insert(dir, &replace_baton->new_entry, idx);
+ }
+ else
+ {
+ /* Remove the old ENTRY. */
+ if (entry)
+ svn_sort__array_delete(dir, idx, 1);
+ }
return svn_fs_x__serialize_dir_entries(data, data_len, dir, pool);
}
@@ -931,7 +939,7 @@ svn_fs_x__replace_dir_entry(void **data,
apr_pool_t *pool)
{
replace_baton_t *replace_baton = (replace_baton_t *)baton;
- hash_data_t *hash_data = (hash_data_t *)*data;
+ dir_data_t *dir_data = (dir_data_t *)*data;
svn_boolean_t found;
svn_fs_dirent_t **entries;
apr_uint32_t *lengths;
@@ -941,23 +949,23 @@ svn_fs_x__replace_dir_entry(void **data,
svn_temp_serializer__context_t *context;
/* after quite a number of operations, let's re-pack everything.
- * This is to limit the number of vasted space as we cannot overwrite
+ * This is to limit the number of wasted space as we cannot overwrite
* existing data but must always append. */
- if (hash_data->operations > 2 + hash_data->count / 4)
+ if (dir_data->operations > 2 + dir_data->count / 4)
return slowly_replace_dir_entry(data, data_len, baton, pool);
/* resolve the reference to the entries array */
entries = (svn_fs_dirent_t **)
- svn_temp_deserializer__ptr(hash_data,
- (const void *const *)&hash_data->entries);
+ svn_temp_deserializer__ptr((const char *)dir_data,
+ (const void *const *)&dir_data->entries);
/* resolve the reference to the lengths array */
lengths = (apr_uint32_t *)
- svn_temp_deserializer__ptr(hash_data,
- (const void *const *)&hash_data->lengths);
+ svn_temp_deserializer__ptr((const char *)dir_data,
+ (const void *const *)&dir_data->lengths);
/* binary search for the desired entry by name */
- pos = find_entry(entries, replace_baton->name, hash_data->count, &found);
+ pos = find_entry(entries, replace_baton->name, dir_data->count, &found);
/* handle entry removal (if found at all) */
if (replace_baton->new_entry == NULL)
@@ -967,14 +975,14 @@ svn_fs_x__replace_dir_entry(void **data,
/* remove reference to the entry from the index */
memmove(&entries[pos],
&entries[pos + 1],
- sizeof(entries[pos]) * (hash_data->count - pos));
+ sizeof(entries[pos]) * (dir_data->count - pos));
memmove(&lengths[pos],
&lengths[pos + 1],
- sizeof(lengths[pos]) * (hash_data->count - pos));
+ sizeof(lengths[pos]) * (dir_data->count - pos));
- hash_data->count--;
- hash_data->over_provision++;
- hash_data->operations++;
+ dir_data->count--;
+ dir_data->over_provision++;
+ dir_data->operations++;
}
return SVN_NO_ERROR;
@@ -986,27 +994,27 @@ svn_fs_x__replace_dir_entry(void **data,
/* fallback to slow operation if there is no place left to insert an
* new entry to index. That will automatically give add some spare
* entries ("overprovision"). */
- if (hash_data->over_provision == 0)
+ if (dir_data->over_provision == 0)
return slowly_replace_dir_entry(data, data_len, baton, pool);
/* make entries[index] available for pointing to the new entry */
memmove(&entries[pos + 1],
&entries[pos],
- sizeof(entries[pos]) * (hash_data->count - pos));
+ sizeof(entries[pos]) * (dir_data->count - pos));
memmove(&lengths[pos + 1],
&lengths[pos],
- sizeof(lengths[pos]) * (hash_data->count - pos));
+ sizeof(lengths[pos]) * (dir_data->count - pos));
- hash_data->count++;
- hash_data->over_provision--;
- hash_data->operations++;
+ dir_data->count++;
+ dir_data->over_provision--;
+ dir_data->operations++;
}
/* de-serialize the new entry */
entries[pos] = replace_baton->new_entry;
- context = svn_temp_serializer__init_append(hash_data,
+ context = svn_temp_serializer__init_append(dir_data,
entries,
- hash_data->len,
+ dir_data->len,
*data_len,
pool);
serialize_dir_entry(context, &entries[pos], &length);
@@ -1020,10 +1028,10 @@ svn_fs_x__replace_dir_entry(void **data,
* pointer may no longer point to the entry in that buffer. Therefore,
* re-map it again and store the length value after that. */
- hash_data = (hash_data_t *)*data;
+ dir_data = (dir_data_t *)*data;
lengths = (apr_uint32_t *)
- svn_temp_deserializer__ptr(hash_data,
- (const void *const *)&hash_data->lengths);
+ svn_temp_deserializer__ptr((const char *)dir_data,
+ (const void *const *)&dir_data->lengths);
lengths[pos] = length;
return SVN_NO_ERROR;
Modified: subversion/trunk/subversion/libsvn_fs_x/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/temp_serializer.h?rev=1595277&r1=1595276&r2=1595277&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/temp_serializer.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/temp_serializer.h Fri May 16 18:06:31 2014
@@ -182,7 +182,7 @@ svn_fs_x__deserialize_node_revision(void
apr_pool_t *pool);
/**
- * Implements #svn_cache__serialize_func_t for a directory contents hash
+ * Implements #svn_cache__serialize_func_t for a directory contents array
*/
svn_error_t *
svn_fs_x__serialize_dir_entries(void **data,
@@ -191,7 +191,7 @@ svn_fs_x__serialize_dir_entries(void **d
apr_pool_t *pool);
/**
- * Implements #svn_cache__deserialize_func_t for a directory contents hash
+ * Implements #svn_cache__deserialize_func_t for a directory contents array
*/
svn_error_t *
svn_fs_x__deserialize_dir_entries(void **out,
Modified: subversion/trunk/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/transaction.c?rev=1595277&r1=1595276&r2=1595277&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/transaction.c Fri May 16 18:06:31 2014
@@ -782,50 +782,45 @@ store_sha1_rep_mapping(svn_fs_t *fs,
return SVN_NO_ERROR;
}
-
-static const char *
-unparse_dir_entry(svn_node_kind_t kind, const svn_fs_id_t *id,
+static svn_error_t *
+unparse_dir_entry(svn_fs_dirent_t *dirent,
+ svn_stream_t *stream,
apr_pool_t *pool)
{
- return apr_psprintf(pool, "%s %s",
- (kind == svn_node_file) ? SVN_FS_X__KIND_FILE
- : SVN_FS_X__KIND_DIR,
- svn_fs_x__id_unparse(id, pool)->data);
+ const char *val
+ = apr_psprintf(pool, "%s %s",
+ (dirent->kind == svn_node_file) ? SVN_FS_X__KIND_FILE
+ : SVN_FS_X__KIND_DIR,
+ svn_fs_x__id_unparse(dirent->id, pool)->data);
+
+ SVN_ERR(svn_stream_printf(stream, pool, "K %" APR_SIZE_T_FMT "\n%s\n"
+ "V %" APR_SIZE_T_FMT "\n%s\n",
+ strlen(dirent->name), dirent->name,
+ strlen(val), val));
+ return SVN_NO_ERROR;
}
-/* Given a hash ENTRIES of dirent structions, return a hash in
- *STR_ENTRIES_P, that has svn_string_t as the values in the format
- specified by the fs_x directory contents file. Perform
- allocations in POOL. */
+/* Write the directory given as array of dirent structs in ENTRIES to STREAM.
+ Perform temporary allocations in POOL. */
static svn_error_t *
-unparse_dir_entries(apr_hash_t **str_entries_p,
- apr_hash_t *entries,
+unparse_dir_entries(apr_array_header_t *entries,
+ svn_stream_t *stream,
apr_pool_t *pool)
{
- apr_hash_index_t *hi;
-
- /* For now, we use a our own hash function to ensure that we get a
- * (largely) stable order when serializing the data. It also gives
- * us some performance improvement.
- *
- * ### TODO ###
- * Use some sorted or other fixed order data container.
- */
- *str_entries_p = svn_hash__make(pool);
-
- for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ int i;
+ for (i = 0; i < entries->nelts; ++i)
{
- const void *key;
- apr_ssize_t klen;
- svn_fs_dirent_t *dirent = svn__apr_hash_index_val(hi);
- const char *new_val;
-
- apr_hash_this(hi, &key, &klen, NULL);
- new_val = unparse_dir_entry(dirent->kind, dirent->id, pool);
- apr_hash_set(*str_entries_p, key, klen,
- svn_string_create(new_val, pool));
+ svn_fs_dirent_t *dirent;
+
+ svn_pool_clear(iterpool);
+ dirent = APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *);
+ SVN_ERR(unparse_dir_entry(dirent, stream, iterpool));
}
+ SVN_ERR(svn_stream_printf(stream, pool, "%s\n", SVN_HASH_TERMINATOR));
+
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -1693,18 +1688,17 @@ svn_fs_x__set_entry(svn_fs_t *fs,
if (!rep || !svn_fs_x__is_txn(rep->id.change_set))
{
- apr_hash_t *entries;
+ apr_array_header_t *entries;
/* Before we can modify the directory, we need to dump its old
contents into a mutable representation file. */
SVN_ERR(svn_fs_x__rep_contents_dir(&entries, fs, parent_noderev,
- subpool));
- SVN_ERR(unparse_dir_entries(&entries, entries, subpool));
+ subpool, subpool));
SVN_ERR(svn_io_file_open(&file, filename,
APR_WRITE | APR_CREATE | APR_BUFFERED,
APR_OS_DEFAULT, pool));
out = svn_stream_from_aprfile2(file, TRUE, pool);
- SVN_ERR(svn_hash_write2(entries, out, SVN_HASH_TERMINATOR, subpool));
+ SVN_ERR(unparse_dir_entries(entries, out, subpool));
svn_pool_clear(subpool);
@@ -1752,12 +1746,12 @@ svn_fs_x__set_entry(svn_fs_t *fs,
/* Append an incremental hash entry for the entry change. */
if (id)
{
- const char *val = unparse_dir_entry(kind, id, subpool);
+ svn_fs_dirent_t entry;
+ entry.name = name;
+ entry.id = id;
+ entry.kind = kind;
- SVN_ERR(svn_stream_printf(out, subpool, "K %" APR_SIZE_T_FMT "\n%s\n"
- "V %" APR_SIZE_T_FMT "\n%s\n",
- strlen(name), name,
- strlen(val), val));
+ SVN_ERR(unparse_dir_entry(&entry, out, subpool));
}
else
{
@@ -2410,8 +2404,8 @@ svn_fs_x__set_proplist(svn_fs_t *fs,
return SVN_NO_ERROR;
}
-/* This baton is used by the stream created for write_hash_rep. */
-struct write_hash_baton
+/* This baton is used by the stream created for write_container_rep. */
+struct write_container_baton
{
svn_stream_t *stream;
@@ -2421,15 +2415,15 @@ struct write_hash_baton
svn_checksum_ctx_t *sha1_ctx;
};
-/* The handler for the write_hash_rep stream. BATON is a
- write_hash_baton, DATA has the data to write and *LEN is the number
+/* The handler for the write_container_rep stream. BATON is a
+ write_container_baton, DATA has the data to write and *LEN is the number
of bytes to write. */
static svn_error_t *
-write_hash_handler(void *baton,
- const char *data,
- apr_size_t *len)
+write_container_handler(void *baton,
+ const char *data,
+ apr_size_t *len)
{
- struct write_hash_baton *whb = baton;
+ struct write_container_baton *whb = baton;
SVN_ERR(svn_checksum_update(whb->md5_ctx, data, *len));
SVN_ERR(svn_checksum_update(whb->sha1_ctx, data, *len));
@@ -2440,25 +2434,64 @@ write_hash_handler(void *baton,
return SVN_NO_ERROR;
}
-/* Write out the hash HASH pertaining to the NODEREV in FS as a deltified
- text representation to file FILE. In the process, record the total size
- and the md5 digest in REP. If rep sharing has been enabled and REPS_HASH
- is not NULL, it will be used in addition to the on-disk cache to find
- earlier reps with the same content. When such existing reps can be found,
- we will truncate the one just written from the file and return the existing
- rep. If PROPS is set, assume that we want to a props representation as
- the base for our delta. Perform temporary allocations in POOL. */
-static svn_error_t *
-write_hash_delta_rep(representation_t *rep,
- apr_file_t *file,
- apr_hash_t *hash,
- svn_fs_t *fs,
- svn_fs_x__txn_id_t txn_id,
- node_revision_t *noderev,
- apr_hash_t *reps_hash,
- int item_type,
+/* Callback function type. Write the data provided by BATON into STREAM. */
+typedef svn_error_t *
+(* collection_writer_t)(svn_stream_t *stream, void *baton, apr_pool_t *pool);
+
+/* Implement collection_writer_t writing the C string->svn_string_t hash
+ given as BATON. */
+static svn_error_t *
+write_hash_to_stream(svn_stream_t *stream,
+ void *baton,
apr_pool_t *pool)
{
+ apr_hash_t *hash = baton;
+ SVN_ERR(svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Implement collection_writer_t writing the svn_fs_dirent_t* array given
+ as BATON. */
+static svn_error_t *
+write_directory_to_stream(svn_stream_t *stream,
+ void *baton,
+ apr_pool_t *pool)
+{
+ apr_array_header_t *dir = baton;
+ SVN_ERR(unparse_dir_entries(dir, stream, pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Write out the COLLECTION pertaining to the NODEREV in FS as a deltified
+ text representation to file FILE using WRITER. In the process, record the
+ total size and the md5 digest in REP and add the representation of type
+ ITEM_TYPE to the indexes if necessary. If rep sharing has been enabled and
+ REPS_HASH is not NULL, it will be used in addition to the on-disk cache to
+ find earlier reps with the same content. When such existing reps can be
+ found, we will truncate the one just written from the file and return the
+ existing rep.
+
+ If ITEM_TYPE is IS_PROPS equals SVN_FS_FS__ITEM_TYPE_*_PROPS, assume
+ that we want to a props representation as the base for our delta.
+ If FINAL_REVISION is not SVN_INVALID_REVNUM, use it to determine whether
+ to write to the proto-index files. Perform temporary allocations in POOL.
+ */
+static svn_error_t *
+write_container_delta_rep(representation_t *rep,
+ apr_file_t *file,
+ void *collection,
+ collection_writer_t writer,
+ svn_fs_t *fs,
+ svn_fs_x__txn_id_t txn_id,
+ node_revision_t *noderev,
+ apr_hash_t *reps_hash,
+ int item_type,
+ svn_revnum_t final_revision,
+ apr_pool_t *pool)
+{
svn_txdelta_window_handler_t diff_wh;
void *diff_whb;
@@ -2473,7 +2506,7 @@ write_hash_delta_rep(representation_t *r
apr_off_t delta_start = 0;
apr_off_t offset = 0;
- struct write_hash_baton *whb;
+ struct write_container_baton *whb;
int diff_version = 1;
svn_boolean_t is_props = (item_type == SVN_FS_X__ITEM_TYPE_FILE_PROPS)
|| (item_type == SVN_FS_X__ITEM_TYPE_DIR_PROPS);
@@ -2517,9 +2550,9 @@ write_hash_delta_rep(representation_t *r
/* serialize the hash */
stream = svn_stream_create(whb, pool);
- svn_stream_set_write(stream, write_hash_handler);
+ svn_stream_set_write(stream, write_container_handler);
- SVN_ERR(svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, pool));
+ SVN_ERR(writer(stream, collection, pool));
SVN_ERR(svn_stream_close(whb->stream));
/* Store the results. */
@@ -2700,24 +2733,18 @@ write_final_rev(const svn_fs_id_t **new_
if (noderev->kind == svn_node_dir)
{
apr_pool_t *subpool;
- apr_hash_t *entries, *str_entries;
- apr_array_header_t *sorted_entries;
+ apr_array_header_t *entries;
int i;
/* This is a directory. Write out all the children first. */
subpool = svn_pool_create(pool);
- SVN_ERR(svn_fs_x__rep_contents_dir(&entries, fs, noderev, pool));
- /* For the sake of the repository administrator sort the entries
- so that the final file is deterministic and repeatable,
- however the rest of the FSX code doesn't require any
- particular order here. */
- sorted_entries = svn_sort__hash(entries, svn_sort_compare_items_lexically,
- pool);
- for (i = 0; i < sorted_entries->nelts; ++i)
+ SVN_ERR(svn_fs_x__rep_contents_dir(&entries, fs, noderev, pool,
+ subpool));
+ for (i = 0; i < entries->nelts; ++i)
{
- svn_fs_dirent_t *dirent = APR_ARRAY_IDX(sorted_entries, i,
- svn_sort__item_t).value;
+ svn_fs_dirent_t *dirent
+ = APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *);
svn_pool_clear(subpool);
SVN_ERR(write_final_rev(&new_id, file, rev, fs, dirent->id,
@@ -2732,13 +2759,13 @@ write_final_rev(const svn_fs_id_t **new_
&& ! svn_fs_x__is_revision(noderev->data_rep->id.change_set))
{
/* Write out the contents of this directory as a text rep. */
- SVN_ERR(unparse_dir_entries(&str_entries, entries, pool));
noderev->data_rep->id.change_set = change_set;
-
- SVN_ERR(write_hash_delta_rep(noderev->data_rep, file,
- str_entries, fs, txn_id, noderev,
- NULL, SVN_FS_X__ITEM_TYPE_DIR_REP,
- pool));
+ SVN_ERR(write_container_delta_rep(noderev->data_rep, file,
+ entries,
+ write_directory_to_stream,
+ fs, txn_id, noderev, NULL,
+ SVN_FS_X__ITEM_TYPE_DIR_REP,
+ rev, pool));
}
}
else
@@ -2766,9 +2793,10 @@ write_final_rev(const svn_fs_id_t **new_
noderev->prop_rep->id.change_set = change_set;
- SVN_ERR(write_hash_delta_rep(noderev->prop_rep, file,
- proplist, fs, txn_id, noderev,
- reps_hash, item_type, pool));
+ SVN_ERR(write_container_delta_rep(noderev->prop_rep, file, proplist,
+ write_hash_to_stream, fs, txn_id,
+ noderev, reps_hash, item_type, rev,
+ pool));
}
/* Convert our temporary ID into a permanent revision one. */
Modified: subversion/trunk/subversion/libsvn_fs_x/tree.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/tree.c?rev=1595277&r1=1595276&r2=1595277&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/tree.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/tree.c Fri May 16 18:06:31 2014
@@ -49,6 +49,7 @@
#include "svn_mergeinfo.h"
#include "svn_fs.h"
#include "svn_props.h"
+#include "svn_sorts.h"
#include "fs.h"
#include "dag.h"
@@ -1642,33 +1643,23 @@ compare_dir_structure(svn_boolean_t *cha
dag_node_t *rhs,
apr_pool_t *pool)
{
- apr_hash_t *lhs_entries;
- apr_hash_t *rhs_entries;
- apr_hash_index_t *hi;
+ apr_array_header_t *lhs_entries;
+ apr_array_header_t *rhs_entries;
+ int i;
SVN_ERR(svn_fs_x__dag_dir_entries(&lhs_entries, lhs, pool));
SVN_ERR(svn_fs_x__dag_dir_entries(&rhs_entries, rhs, pool));
- /* different number of entries -> some addition / removal */
- if (apr_hash_count(lhs_entries) != apr_hash_count(rhs_entries))
- {
- *changed = TRUE;
- return SVN_NO_ERROR;
- }
-
- /* Since the number of dirents is the same, we simply need to do a
- one-sided comparison. */
- for (hi = apr_hash_first(pool, lhs_entries); hi; hi = apr_hash_next(hi))
- {
- svn_fs_dirent_t *lhs_entry;
- svn_fs_dirent_t *rhs_entry;
- const char *name;
- apr_ssize_t klen;
-
- apr_hash_this(hi, (const void **)&name, &klen, (void **)&lhs_entry);
- rhs_entry = apr_hash_get(rhs_entries, name, klen);
+ /* Since directories are sorted by name, we can simply compare their
+ entries one-by-one without binary lookup etc. */
+ for (i = 0; i < lhs_entries->nelts; ++i)
+ {
+ svn_fs_dirent_t *lhs_entry
+ = APR_ARRAY_IDX(lhs_entries, i, svn_fs_dirent_t *);
+ svn_fs_dirent_t *rhs_entry
+ = APR_ARRAY_IDX(rhs_entries, i, svn_fs_dirent_t *);
- if (!rhs_entry
+ if (strcmp(lhs_entry->name, rhs_entry->name)
|| !svn_fs_x__id_part_eq(svn_fs_x__id_node_id(lhs_entry->id),
svn_fs_x__id_node_id(rhs_entry->id))
|| !svn_fs_x__id_part_eq(svn_fs_x__id_copy_id(lhs_entry->id),
@@ -1716,8 +1707,8 @@ merge(svn_stringbuf_t *conflict_p,
apr_pool_t *pool)
{
const svn_fs_id_t *source_id, *target_id, *ancestor_id;
- apr_hash_t *s_entries, *t_entries, *a_entries;
- apr_hash_index_t *hi;
+ apr_array_header_t *s_entries, *t_entries, *a_entries;
+ int i, s_idx = -1, t_idx = -1;
svn_fs_t *fs;
apr_pool_t *iterpool;
apr_int64_t mergeinfo_increment = 0;
@@ -1883,27 +1874,19 @@ merge(svn_stringbuf_t *conflict_p,
/* for each entry E in a_entries... */
iterpool = svn_pool_create(pool);
- for (hi = apr_hash_first(pool, a_entries);
- hi;
- hi = apr_hash_next(hi))
+ for (i = 0; i < a_entries->nelts; ++i)
{
svn_fs_dirent_t *s_entry, *t_entry, *a_entry;
- const char *name;
- apr_ssize_t klen;
-
svn_pool_clear(iterpool);
- name = svn__apr_hash_index_key(hi);
- klen = svn__apr_hash_index_klen(hi);
- a_entry = svn__apr_hash_index_val(hi);
-
- s_entry = apr_hash_get(s_entries, name, klen);
- t_entry = apr_hash_get(t_entries, name, klen);
+ a_entry = APR_ARRAY_IDX(a_entries, i, svn_fs_dirent_t *);
+ s_entry = svn_fs_x__find_dir_entry(s_entries, a_entry->name, &s_idx);
+ t_entry = svn_fs_x__find_dir_entry(t_entries, a_entry->name, &t_idx);
/* No changes were made to this entry while the transaction was
in progress, so do nothing to the target. */
if (s_entry && svn_fs_x__id_eq(a_entry->id, s_entry->id))
- goto end;
+ continue;
/* A change was made to this entry while the transaction was in
process, but the transaction did not touch this entry. */
@@ -1929,15 +1912,16 @@ merge(svn_stringbuf_t *conflict_p,
s_ent_node));
mergeinfo_increment += mergeinfo_end;
- SVN_ERR(svn_fs_x__dag_set_entry(target, name,
+ SVN_ERR(svn_fs_x__dag_set_entry(target, a_entry->name,
s_entry->id,
s_entry->kind,
txn_id,
- pool));
+ iterpool));
}
else
{
- SVN_ERR(svn_fs_x__dag_delete(target, name, txn_id, iterpool));
+ SVN_ERR(svn_fs_x__dag_delete(target, a_entry->name, txn_id,
+ iterpool));
}
}
@@ -2000,30 +1984,24 @@ merge(svn_stringbuf_t *conflict_p,
iterpool));
mergeinfo_increment += sub_mergeinfo_increment;
}
-
- /* We've taken care of any possible implications E could have.
- Remove it from source_entries, so it's easy later to loop
- over all the source entries that didn't exist in
- ancestor_entries. */
- end:
- apr_hash_set(s_entries, name, klen, NULL);
}
/* For each entry E in source but not in ancestor */
- for (hi = apr_hash_first(pool, s_entries);
- hi;
- hi = apr_hash_next(hi))
- {
- svn_fs_dirent_t *s_entry, *t_entry;
- const char *name = svn__apr_hash_index_key(hi);
- apr_ssize_t klen = svn__apr_hash_index_klen(hi);
+ for (i = 0; i < s_entries->nelts; ++i)
+ {
+ svn_fs_dirent_t *a_entry, *s_entry, *t_entry;
dag_node_t *s_ent_node;
apr_int64_t mergeinfo_s;
svn_pool_clear(iterpool);
- s_entry = svn__apr_hash_index_val(hi);
- t_entry = apr_hash_get(t_entries, name, klen);
+ s_entry = APR_ARRAY_IDX(s_entries, i, svn_fs_dirent_t *);
+ a_entry = svn_fs_x__find_dir_entry(a_entries, s_entry->name, &s_idx);
+ t_entry = svn_fs_x__find_dir_entry(t_entries, s_entry->name, &t_idx);
+
+ /* Process only entries in source that are NOT in ancestor. */
+ if (a_entry)
+ continue;
/* If NAME exists in TARGET, declare a conflict. */
if (t_entry)
@@ -2324,10 +2302,23 @@ x_dir_entries(apr_hash_t **table_p,
apr_pool_t *pool)
{
dag_node_t *node;
+ apr_hash_t *hash = svn_hash__make(pool);
+ apr_array_header_t *table;
+ int i;
/* Get the entries for this path in the caller's pool. */
SVN_ERR(get_dag(&node, root, path, FALSE, pool));
- return svn_fs_x__dag_dir_entries(table_p, node, pool);
+ SVN_ERR(svn_fs_x__dag_dir_entries(&table, node, pool));
+
+ /* Convert directory array to hash. */
+ for (i = 0; i < table->nelts; ++i)
+ {
+ svn_fs_dirent_t *entry = APR_ARRAY_IDX(table, i, svn_fs_dirent_t *);
+ svn_hash_sets(hash, entry->name, entry);
+ }
+
+ *table_p = hash;
+ return SVN_NO_ERROR;
}
static svn_error_t *
@@ -3819,17 +3810,14 @@ crawl_directory_dag_for_mergeinfo(svn_fs
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_hash_t *entries;
- apr_hash_index_t *hi;
+ apr_array_header_t *entries;
+ int i;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_fs_x__dag_dir_entries(&entries, dir_dag, scratch_pool));
-
- for (hi = apr_hash_first(scratch_pool, entries);
- hi;
- hi = apr_hash_next(hi))
+ for (i = 0; i < entries->nelts; ++i)
{
- svn_fs_dirent_t *dirent = svn__apr_hash_index_val(hi);
+ svn_fs_dirent_t *dirent = APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *);
const char *kid_path;
dag_node_t *kid_dag;
svn_boolean_t has_mergeinfo, go_down;
@@ -4361,18 +4349,17 @@ verify_node(dag_node_t *node,
}
if (kind == svn_node_dir)
{
- apr_hash_t *entries;
- apr_hash_index_t *hi;
+ apr_array_header_t *entries;
+ int i;
apr_int64_t children_mergeinfo = 0;
SVN_ERR(svn_fs_x__dag_dir_entries(&entries, node, pool));
/* Compute CHILDREN_MERGEINFO. */
- for (hi = apr_hash_first(pool, entries);
- hi;
- hi = apr_hash_next(hi))
+ for (i = 0; i < entries->nelts; ++i)
{
- svn_fs_dirent_t *dirent = svn__apr_hash_index_val(hi);
+ svn_fs_dirent_t *dirent
+ = APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *);
dag_node_t *child;
apr_int64_t child_mergeinfo;