You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by iv...@apache.org on 2015/09/11 17:51:34 UTC
svn commit: r1702504 [12/19] - in /subversion/branches/reuse-ra-session: ./
build/ build/ac-macros/ build/generator/ build/generator/templates/
contrib/hook-scripts/ notes/ subversion/bindings/ctypes-python/csvn/ext/
subversion/bindings/javahl/native/ ...
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_ra_svn/marshal.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_ra_svn/marshal.c Fri Sep 11 15:51:30 2015
@@ -60,9 +60,10 @@
/* We don't use "words" longer than this in our protocol. The longest word
* we are currently using is only about 16 chars long but we leave room for
- * longer future capability and command names.
+ * longer future capability and command names. See read_item() to understand
+ * why MAX_WORD_LENGTH - 1 should be a multiple of 8.
*/
-#define MAX_WORD_LENGTH 31
+#define MAX_WORD_LENGTH 25
/* The generic parsers will use the following value to limit the recursion
* depth to some reasonable value. The current protocol implementation
@@ -79,6 +80,98 @@ get_timeout(svn_ra_svn_conn_t *conn)
return conn->block_handler ? 0 : -1;
}
+/* --- Public / private API data conversion --- */
+
+void
+svn_ra_svn__to_public_item(svn_ra_svn_item_t *target,
+ const svn_ra_svn__item_t *source,
+ apr_pool_t *result_pool)
+{
+ target->kind = source->kind;
+ switch (source->kind)
+ {
+ case SVN_RA_SVN_STRING:
+ target->u.string = svn_string_dup(&source->u.string, result_pool);
+ break;
+ case SVN_RA_SVN_NUMBER:
+ target->u.number = source->u.number;
+ break;
+ case SVN_RA_SVN_WORD:
+ target->u.word = source->u.word;
+ break;
+ case SVN_RA_SVN_LIST:
+ target->u.list = svn_ra_svn__to_public_array(&source->u.list,
+ result_pool);
+ break;
+ }
+}
+
+apr_array_header_t *
+svn_ra_svn__to_public_array(const svn_ra_svn__list_t *source,
+ apr_pool_t *result_pool)
+{
+ apr_array_header_t *result = apr_array_make(result_pool, source->nelts,
+ sizeof(svn_ra_svn_item_t));
+
+ int i;
+ for (i = 0; i < source->nelts; ++i)
+ {
+ svn_ra_svn_item_t *sub_target = apr_array_push(result);
+ svn_ra_svn__item_t *sub_source = &SVN_RA_SVN__LIST_ITEM(source, i);
+
+ svn_ra_svn__to_public_item(sub_target, sub_source, result_pool);
+ }
+
+ return result;
+}
+
+void
+svn_ra_svn__to_private_item(svn_ra_svn__item_t *target,
+ const svn_ra_svn_item_t *source,
+ apr_pool_t *result_pool)
+{
+ target->kind = source->kind;
+ switch (source->kind)
+ {
+ case SVN_RA_SVN_STRING:
+ target->u.string = *source->u.string;
+ break;
+ case SVN_RA_SVN_NUMBER:
+ target->u.number = source->u.number;
+ break;
+ case SVN_RA_SVN_WORD:
+ target->u.word = source->u.word;
+ break;
+ case SVN_RA_SVN_LIST:
+ target->u.list = *svn_ra_svn__to_private_array(source->u.list,
+ result_pool);
+ break;
+ }
+}
+
+svn_ra_svn__list_t *
+svn_ra_svn__to_private_array(const apr_array_header_t *source,
+ apr_pool_t *result_pool)
+{
+ int i;
+
+ svn_ra_svn__list_t *result = apr_pcalloc(result_pool, sizeof(*result));
+ result->nelts = source->nelts;
+ result->items = apr_palloc(result_pool,
+ source->nelts * sizeof(*result->items));
+
+ for (i = 0; i < source->nelts; ++i)
+ {
+ svn_ra_svn__item_t *sub_target = &result->items[i];
+ svn_ra_svn_item_t *sub_source = &APR_ARRAY_IDX(source, i,
+ svn_ra_svn_item_t);
+
+ svn_ra_svn__to_private_item(sub_target, sub_source, result_pool);
+ }
+
+ return result;
+}
+
/* --- CONNECTION INITIALIZATION --- */
svn_ra_svn_conn_t *svn_ra_svn_create_conn4(apr_socket_t *sock,
@@ -132,16 +225,26 @@ svn_ra_svn_conn_t *svn_ra_svn_create_con
return conn;
}
-svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
- const apr_array_header_t *list)
+svn_error_t *
+svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
+ const apr_array_header_t *list)
+{
+ svn_ra_svn__list_t *internal
+ = svn_ra_svn__to_private_array(list, list->pool);
+ return svn_error_trace(svn_ra_svn__set_capabilities(conn, internal));
+}
+
+svn_error_t *
+svn_ra_svn__set_capabilities(svn_ra_svn_conn_t *conn,
+ const svn_ra_svn__list_t *list)
{
int i;
- svn_ra_svn_item_t *item;
+ svn_ra_svn__item_t *item;
const char *word;
for (i = 0; i < list->nelts; i++)
{
- item = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
+ item = &SVN_RA_SVN__LIST_ITEM(list, i);
if (item->kind != SVN_RA_SVN_WORD)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Capability entry is not a word"));
@@ -512,22 +615,65 @@ svn_ra_svn__write_number(svn_ra_svn_conn
return write_number(conn, pool, number, ' ');
}
+/* Write string S of length LEN to TARGET and return the first position
+ after the written data.
+
+ NOTE: This function assumes that TARGET has enough room for S, the LEN
+ prefix and the required separators. The available buffer size
+ should be SVN_INT64_BUFFER_SIZE + LEN + 1 to avoid any chance of
+ overflow.
+ */
+static char *
+write_ncstring_quick(char *target,
+ const char *s,
+ apr_size_t len)
+{
+ /* Write string length. */
+ if (len < 10)
+ {
+ *target = (char)(len + '0');
+ target++;
+ }
+ else
+ {
+ target += svn__ui64toa(target, len);
+ }
+
+ /* Separator & contents. */
+ target[0] = ':';
+ memcpy(target + 1, s, len);
+ target[len + 1] = ' ';
+
+ /* First location after the string. */
+ return target + len + 2;
+}
+
+
static svn_error_t *
svn_ra_svn__write_ncstring(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *s,
apr_size_t len)
{
- if (len < 10)
- {
- SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0')));
- SVN_ERR(writebuf_writechar(conn, pool, ':'));
+ apr_size_t needed = SVN_INT64_BUFFER_SIZE + len + 1;
+
+ /* In most cases, there is enough left room in the WRITE_BUF
+ the we can serialize directly into it. */
+ if (conn->write_pos + needed < sizeof(conn->write_buf))
+ {
+ /* Quick path. */
+ conn->write_pos = write_ncstring_quick(conn->write_buf
+ + conn->write_pos, s, len)
+ - conn->write_buf;
}
else
- SVN_ERR(write_number(conn, pool, len, ':'));
+ {
+ /* Slower fallback code. */
+ SVN_ERR(write_number(conn, pool, len, ':'));
- SVN_ERR(writebuf_write(conn, pool, s, len));
- SVN_ERR(writebuf_writechar(conn, pool, ' '));
+ SVN_ERR(writebuf_write(conn, pool, s, len));
+ SVN_ERR(writebuf_writechar(conn, pool, ' '));
+ }
return SVN_NO_ERROR;
}
@@ -755,6 +901,52 @@ write_tuple_string_opt(svn_ra_svn_conn_t
return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR;
}
+/* Optimized sending code for the "(s?)" pattern. */
+static svn_error_t *
+write_tuple_string_opt_list(svn_ra_svn_conn_t *conn,
+ apr_pool_t *pool,
+ const svn_string_t *str)
+{
+ apr_size_t needed;
+
+ /* Special case. */
+ if (!str)
+ return writebuf_write(conn, pool, "( ) ", 4);
+
+ /* If there is at least this much the room left in the WRITE_BUF,
+ we can serialize directly into it. */
+ needed = 2 /* open list */
+ + SVN_INT64_BUFFER_SIZE /* string length + separator */
+ + str->len /* string contents */
+ + 2; /* close list */
+
+ if (conn->write_pos + needed <= sizeof(conn->write_buf))
+ {
+ /* Quick path. */
+ /* Open list. */
+ char *p = conn->write_buf + conn->write_pos;
+ p[0] = '(';
+ p[1] = ' ';
+
+ /* Write string. */
+ p = write_ncstring_quick(p + 2, str->data, str->len);
+
+ /* Close list. */
+ p[0] = ')';
+ p[1] = ' ';
+ conn->write_pos = p + 2 - conn->write_buf;
+ }
+ else
+ {
+ /* Standard code path (fallback). */
+ SVN_ERR(svn_ra_svn__start_list(conn, pool));
+ SVN_ERR(svn_ra_svn__write_string(conn, pool, str));
+ SVN_ERR(svn_ra_svn__end_list(conn, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
write_tuple_start_list(svn_ra_svn_conn_t *conn,
apr_pool_t *pool)
@@ -809,14 +1001,14 @@ static svn_error_t *
write_cmd_add_node(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
const char *copy_path,
svn_revnum_t copy_rev)
{
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, parent_token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_cstring_opt(conn, pool, copy_path));
SVN_ERR(write_tuple_revision_opt(conn, pool, copy_rev));
@@ -829,13 +1021,13 @@ static svn_error_t *
write_cmd_open_node(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
svn_revnum_t rev)
{
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, parent_token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
SVN_ERR(write_tuple_end_list(conn, pool));
@@ -846,15 +1038,13 @@ write_cmd_open_node(svn_ra_svn_conn_t *c
static svn_error_t *
write_cmd_change_node_prop(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *name,
const svn_string_t *value)
{
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_cstring(conn, pool, name));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, value));
- SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, value));
return SVN_NO_ERROR;
}
@@ -863,10 +1053,10 @@ static svn_error_t *
write_cmd_absent_node(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
return SVN_NO_ERROR;
}
@@ -939,7 +1129,7 @@ svn_ra_svn__write_tuple(svn_ra_svn_conn_
* Afterwards, *ITEM is of type 'SVN_RA_SVN_STRING', and its string
* data is allocated in POOL. */
static svn_error_t *read_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
- svn_ra_svn_item_t *item, apr_uint64_t len64)
+ svn_ra_svn__item_t *item, apr_uint64_t len64)
{
apr_size_t len = (apr_size_t)len64;
apr_size_t readbuf_len;
@@ -955,7 +1145,8 @@ static svn_error_t *read_string(svn_ra_s
if (conn->read_ptr + len <= conn->read_end)
{
item->kind = SVN_RA_SVN_STRING;
- item->u.string = svn_string_ncreate(conn->read_ptr, len, pool);
+ item->u.string.data = apr_pstrmemdup(pool, conn->read_ptr, len);
+ item->u.string.len = len;
conn->read_ptr += len;
}
else
@@ -996,7 +1187,8 @@ static svn_error_t *read_string(svn_ra_s
/* Return the string properly wrapped into an RA_SVN item. */
item->kind = SVN_RA_SVN_STRING;
- item->u.string = svn_stringbuf__morph_into_string(stringbuf);
+ item->u.string.data = stringbuf->data;
+ item->u.string.len = stringbuf->len;
}
return SVN_NO_ERROR;
@@ -1007,12 +1199,12 @@ static svn_error_t *read_string(svn_ra_s
* to 0 for the first call and is used to enforce a recursion limit
* on the parser. */
static svn_error_t *read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
- svn_ra_svn_item_t *item, char first_char,
+ svn_ra_svn__item_t *item, char first_char,
int level)
{
char c = first_char;
apr_uint64_t val;
- svn_ra_svn_item_t *listitem;
+ svn_ra_svn__item_t *listitem;
if (++level >= ITEM_NESTING_LIMIT)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -1060,17 +1252,40 @@ static svn_error_t *read_item(svn_ra_svn
char *p = buffer + 1;
buffer[0] = c;
- while (1)
+ if (conn->read_ptr + MAX_WORD_LENGTH <= conn->read_end)
{
- SVN_ERR(readbuf_getchar(conn, pool, p));
- if (!svn_ctype_isalnum(*p) && *p != '-')
- break;
+ /* Fast path: we can simply take a chunk from the read
+ * buffer and inspect it with no overflow checks etc.
+ *
+ * Copying these 24 bytes unconditionally is also faster
+ * than a variable-sized memcpy. Note that P is at BUFFER[1].
+ */
+ memcpy(p, conn->read_ptr, MAX_WORD_LENGTH - 1);
+ *end = 0;
+
+ /* This will terminate at P == END because of *END == NUL. */
+ while (svn_ctype_isalnum(*p) || *p == '-')
+ ++p;
- if (++p == end)
- return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
- _("Word is too long"));
+ /* Only now do we mark data as actually read. */
+ conn->read_ptr += p - buffer;
+ }
+ else
+ {
+ /* Slow path. Byte-by-byte copying and checking for
+ * input and output buffer boundaries. */
+ for (p = buffer + 1; p != end; ++p)
+ {
+ SVN_ERR(readbuf_getchar(conn, pool, p));
+ if (!svn_ctype_isalnum(*p) && *p != '-')
+ break;
+ }
}
+ if (p == end)
+ return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+ _("Word is too long"));
+
c = *p;
*p = '\0';
@@ -1079,48 +1294,64 @@ static svn_error_t *read_item(svn_ra_svn
}
else if (c == '(')
{
- /* Allocate an APR array with room for (initially) 4 items.
- * We do this manually because lists are the most frequent protocol
- * element, often used to frame a single, optional value. We save
- * about 20% of total protocol handling time. */
- char *buffer = apr_palloc(pool, sizeof(apr_array_header_t)
- + 4 * sizeof(svn_ra_svn_item_t));
- svn_ra_svn_item_t *data
- = (svn_ra_svn_item_t *)(buffer + sizeof(apr_array_header_t));
-
- item->kind = SVN_RA_SVN_LIST;
- item->u.list = (apr_array_header_t *)buffer;
- item->u.list->elts = (char *)data;
- item->u.list->pool = pool;
- item->u.list->elt_size = sizeof(*data);
- item->u.list->nelts = 0;
- item->u.list->nalloc = 4;
-
- listitem = data;
+ /* The largest struct that the protocol currently defines has 10
+ * elements (log-entry) and add some headroom for future extensions.
+ * At a maximum nesting level of 64 this use <= 18kB of stack.
+ *
+ * All system-defined data structures will fit into this and will be
+ * copied into ITEM after a single apr_palloc with no over-provision.
+ * Unbounded lists with more than 12 but less than 25 entries will
+ * also see only a single allocation from POOL. However, there will
+ * be some over-provision. Longer lists will see log N resizes and
+ * O(N) total cost.
+ */
+ svn_ra_svn__item_t stack_items[12];
+ svn_ra_svn__item_t *items = stack_items;
+ int capacity = sizeof(stack_items) / sizeof(stack_items[0]);
+ int count = 0;
/* Read in the list items. */
+ item->kind = SVN_RA_SVN_LIST;
while (1)
{
SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
if (c == ')')
break;
- /* increase array capacity if necessary */
- if (item->u.list->nelts == item->u.list->nalloc)
+ /* Auto-expand the list. */
+ if (count == capacity)
{
- data = apr_palloc(pool, 2 * item->u.list->nelts * sizeof(*data));
- memcpy(data, item->u.list->elts, item->u.list->nelts * sizeof(*data));
- item->u.list->elts = (char *)data;
- item->u.list->nalloc *= 2;
- listitem = data + item->u.list->nelts;
+ svn_ra_svn__item_t *new_items
+ = apr_palloc(pool, 2 * capacity * sizeof(*new_items));
+ memcpy(new_items, items, capacity * sizeof(*new_items));
+ items = new_items;
+ capacity = 2 * capacity;
}
- /* read next protocol item */
+ listitem = &items[count];
+ ++count;
+
SVN_ERR(read_item(conn, pool, listitem, c, level));
+ }
- listitem++;
- item->u.list->nelts++;
+ /* Store the list in ITEM - if not empty (= default). */
+ if (count)
+ {
+ item->u.list.nelts = count;
+
+ /* If we haven't allocated from POOL, yet, do it now. */
+ if (items == stack_items)
+ item->u.list.items = apr_pmemdup(pool, items,
+ count * sizeof(*items));
+ else
+ item->u.list.items = items;
+ }
+ else
+ {
+ item->u.list.items = NULL;
+ item->u.list.nelts = 0;
}
+
SVN_ERR(readbuf_getchar(conn, pool, &c));
}
@@ -1222,7 +1453,7 @@ read_command_only(svn_ra_svn_conn_t *con
svn_error_t *
svn_ra_svn__read_item(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- svn_ra_svn_item_t **item)
+ svn_ra_svn__item_t **item)
{
char c;
@@ -1272,29 +1503,32 @@ svn_ra_svn__skip_leading_garbage(svn_ra_
/* --- READING AND PARSING TUPLES --- */
-/* Parse a tuple of svn_ra_svn_item_t *'s. Advance *FMT to the end of the
+/* Parse a tuple of svn_ra_svn__item_t *'s. Advance *FMT to the end of the
* tuple specification and advance AP by the corresponding arguments. */
-static svn_error_t *vparse_tuple(const apr_array_header_t *items, apr_pool_t *pool,
- const char **fmt, va_list *ap)
+static svn_error_t *
+vparse_tuple(const svn_ra_svn__list_t *items,
+ apr_pool_t *pool,
+ const char **fmt,
+ va_list *ap)
{
int count, nesting_level;
- svn_ra_svn_item_t *elt;
+ svn_ra_svn__item_t *elt;
for (count = 0; **fmt && count < items->nelts; (*fmt)++, count++)
{
/* '?' just means the tuple may stop; skip past it. */
if (**fmt == '?')
(*fmt)++;
- elt = &APR_ARRAY_IDX(items, count, svn_ra_svn_item_t);
+ elt = &SVN_RA_SVN__LIST_ITEM(items, count);
if (**fmt == '(' && elt->kind == SVN_RA_SVN_LIST)
{
(*fmt)++;
- SVN_ERR(vparse_tuple(elt->u.list, pool, fmt, ap));
+ SVN_ERR(vparse_tuple(&elt->u.list, pool, fmt, ap));
}
else if (**fmt == 'c' && elt->kind == SVN_RA_SVN_STRING)
- *va_arg(*ap, const char **) = elt->u.string->data;
+ *va_arg(*ap, const char **) = elt->u.string.data;
else if (**fmt == 's' && elt->kind == SVN_RA_SVN_STRING)
- *va_arg(*ap, svn_string_t **) = elt->u.string;
+ *va_arg(*ap, svn_string_t **) = &elt->u.string;
else if (**fmt == 'w' && elt->kind == SVN_RA_SVN_WORD)
*va_arg(*ap, const char **) = elt->u.word;
else if (**fmt == 'b' && elt->kind == SVN_RA_SVN_WORD)
@@ -1329,7 +1563,7 @@ static svn_error_t *vparse_tuple(const a
break;
}
else if (**fmt == 'l' && elt->kind == SVN_RA_SVN_LIST)
- *va_arg(*ap, apr_array_header_t **) = elt->u.list;
+ *va_arg(*ap, svn_ra_svn__list_t **) = &elt->u.list;
else if (**fmt == ')')
return SVN_NO_ERROR;
else
@@ -1355,7 +1589,7 @@ static svn_error_t *vparse_tuple(const a
*va_arg(*ap, const char **) = NULL;
break;
case 'l':
- *va_arg(*ap, apr_array_header_t **) = NULL;
+ *va_arg(*ap, svn_ra_svn__list_t **) = NULL;
break;
case 'B':
case 'n':
@@ -1383,7 +1617,7 @@ static svn_error_t *vparse_tuple(const a
}
svn_error_t *
-svn_ra_svn__parse_tuple(const apr_array_header_t *list,
+svn_ra_svn__parse_tuple(const svn_ra_svn__list_t *list,
apr_pool_t *pool,
const char *fmt, ...)
{
@@ -1402,7 +1636,7 @@ svn_ra_svn__read_tuple(svn_ra_svn_conn_t
const char *fmt, ...)
{
va_list ap;
- svn_ra_svn_item_t *item;
+ svn_ra_svn__item_t *item;
svn_error_t *err;
SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
@@ -1410,7 +1644,7 @@ svn_ra_svn__read_tuple(svn_ra_svn_conn_t
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Malformed network data"));
va_start(ap, fmt);
- err = vparse_tuple(item->u.list, pool, &fmt, &ap);
+ err = vparse_tuple(&item->u.list, pool, &fmt, &ap);
va_end(ap);
return err;
}
@@ -1429,23 +1663,23 @@ svn_ra_svn__read_command_only(svn_ra_svn
svn_error_t *
-svn_ra_svn__parse_proplist(const apr_array_header_t *list,
+svn_ra_svn__parse_proplist(const svn_ra_svn__list_t *list,
apr_pool_t *pool,
apr_hash_t **props)
{
svn_string_t *name;
svn_string_t *value;
- svn_ra_svn_item_t *elt;
+ svn_ra_svn__item_t *elt;
int i;
*props = svn_hash__make(pool);
for (i = 0; i < list->nelts; i++)
{
- elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
+ elt = &SVN_RA_SVN__LIST_ITEM(list, i);
if (elt->kind != SVN_RA_SVN_LIST)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Proplist element not a list"));
- SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "ss",
+ SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, pool, "ss",
&name, &value));
apr_hash_set(*props, name->data, name->len, value);
}
@@ -1471,12 +1705,13 @@ svn_error_t *svn_ra_svn__locate_real_err
return this_link;
}
-svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params,
- apr_pool_t *pool)
+svn_error_t *
+svn_ra_svn__handle_failure_status(const svn_ra_svn__list_t *params,
+ apr_pool_t *pool)
{
const char *message, *file;
svn_error_t *err = NULL;
- svn_ra_svn_item_t *elt;
+ svn_ra_svn__item_t *elt;
int i;
apr_uint64_t apr_err, line;
apr_pool_t *subpool = svn_pool_create(pool);
@@ -1489,11 +1724,11 @@ svn_error_t *svn_ra_svn__handle_failure_
for (i = params->nelts - 1; i >= 0; i--)
{
svn_pool_clear(subpool);
- elt = &APR_ARRAY_IDX(params, i, svn_ra_svn_item_t);
+ elt = &SVN_RA_SVN__LIST_ITEM(params, i);
if (elt->kind != SVN_RA_SVN_LIST)
return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
_("Malformed error list"));
- SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, subpool, "nccn",
+ SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, subpool, "nccn",
&apr_err, &message, &file, &line));
/* The message field should have been optional, but we can't
easily change that, so "" means a nonexistent message. */
@@ -1530,7 +1765,7 @@ svn_ra_svn__read_cmd_response(svn_ra_svn
{
va_list ap;
const char *status;
- apr_array_header_t *params;
+ svn_ra_svn__list_t *params;
svn_error_t *err;
SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "wl", &status, ¶ms));
@@ -1579,8 +1814,8 @@ svn_ra_svn__handle_command(svn_boolean_t
{
const char *cmdname;
svn_error_t *err, *write_err;
- apr_array_header_t *params;
- const svn_ra_svn_cmd_entry_t *command;
+ svn_ra_svn__list_t *params;
+ const svn_ra_svn__cmd_entry_t *command;
*terminate = FALSE;
err = svn_ra_svn__read_tuple(conn, pool, "wl", &cmdname, ¶ms);
@@ -1599,7 +1834,21 @@ svn_ra_svn__handle_command(svn_boolean_t
command = svn_hash_gets(cmd_hash, cmdname);
if (command)
{
- err = (*command->handler)(conn, pool, params, baton);
+ /* Call the standard command handler.
+ * If that is not set, then this is a lecagy API call and we invoke
+ * the legacy command handler. */
+ if (command->handler)
+ {
+ err = (*command->handler)(conn, pool, params, baton);
+ }
+ else
+ {
+ apr_array_header_t *deprecated_params
+ = svn_ra_svn__to_public_array(params, pool);
+ err = (*command->deprecated_handler)(conn, pool, deprecated_params,
+ baton);
+ }
+
*terminate = command->terminate;
}
else
@@ -1624,13 +1873,13 @@ svn_ra_svn__handle_command(svn_boolean_t
svn_error_t *
svn_ra_svn__handle_commands2(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const svn_ra_svn_cmd_entry_t *commands,
+ const svn_ra_svn__cmd_entry_t *commands,
void *baton,
svn_boolean_t error_on_disconnect)
{
apr_pool_t *subpool = svn_pool_create(pool);
apr_pool_t *iterpool = svn_pool_create(subpool);
- const svn_ra_svn_cmd_entry_t *command;
+ const svn_ra_svn__cmd_entry_t *command;
apr_hash_t *cmd_hash = apr_hash_make(subpool);
for (command = commands; command->cmdname; command++)
@@ -1673,13 +1922,13 @@ svn_error_t *
svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
svn_revnum_t rev,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( open-root ( "));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
@@ -1690,14 +1939,14 @@ svn_ra_svn__write_cmd_delete_entry(svn_r
apr_pool_t *pool,
const char *path,
svn_revnum_t rev,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( delete-entry ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
@@ -1707,8 +1956,8 @@ svn_error_t *
svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
const char *copy_path,
svn_revnum_t copy_rev)
{
@@ -1724,8 +1973,8 @@ svn_error_t *
svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
svn_revnum_t rev)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( open-dir ( "));
@@ -1738,7 +1987,7 @@ svn_ra_svn__write_cmd_open_dir(svn_ra_sv
svn_error_t *
svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *name,
const svn_string_t *value)
{
@@ -1752,10 +2001,10 @@ svn_ra_svn__write_cmd_change_dir_prop(sv
svn_error_t *
svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( close-dir ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
@@ -1765,7 +2014,7 @@ svn_error_t *
svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token)
+ const svn_string_t *parent_token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( absent-dir ( "));
SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
@@ -1778,8 +2027,8 @@ svn_error_t *
svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
const char *copy_path,
svn_revnum_t copy_rev)
{
@@ -1795,8 +2044,8 @@ svn_error_t *
svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token,
- const char *token,
+ const svn_string_t *parent_token,
+ const svn_string_t *token,
svn_revnum_t rev)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( open-file ( "));
@@ -1809,7 +2058,7 @@ svn_ra_svn__write_cmd_open_file(svn_ra_s
svn_error_t *
svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *name,
const svn_string_t *value)
{
@@ -1823,11 +2072,11 @@ svn_ra_svn__write_cmd_change_file_prop(s
svn_error_t *
svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *text_checksum)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( close-file ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_cstring_opt(conn, pool, text_checksum));
SVN_ERR(write_tuple_end_list(conn, pool));
@@ -1840,7 +2089,7 @@ svn_error_t *
svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *parent_token)
+ const svn_string_t *parent_token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( absent-file ( "));
SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
@@ -1852,11 +2101,11 @@ svn_ra_svn__write_cmd_absent_file(svn_ra
svn_error_t *
svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const svn_string_t *chunk)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-chunk ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_string(conn, pool, chunk));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
@@ -1866,10 +2115,10 @@ svn_ra_svn__write_cmd_textdelta_chunk(sv
svn_error_t *
svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token)
+ const svn_string_t *token)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-end ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
return SVN_NO_ERROR;
@@ -1878,11 +2127,11 @@ svn_ra_svn__write_cmd_textdelta_end(svn_
svn_error_t *
svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
- const char *token,
+ const svn_string_t *token,
const char *base_checksum)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( apply-textdelta ( "));
- SVN_ERR(write_tuple_cstring(conn, pool, token));
+ SVN_ERR(write_tuple_string(conn, pool, token));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_cstring_opt(conn, pool, base_checksum));
SVN_ERR(write_tuple_end_list(conn, pool));
@@ -2020,9 +2269,7 @@ svn_ra_svn__write_cmd_change_rev_prop2(s
SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop2 ( "));
SVN_ERR(write_tuple_revision(conn, pool, rev));
SVN_ERR(write_tuple_cstring(conn, pool, name));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, value));
- SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, value));
SVN_ERR(write_tuple_start_list(conn, pool));
SVN_ERR(write_tuple_boolean(conn, pool, dont_care));
SVN_ERR(write_tuple_string_opt(conn, pool, old_value));
@@ -2274,14 +2521,12 @@ svn_error_t *
svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
const char *path,
- const char *token,
+ const svn_string_t *token,
svn_boolean_t break_lock)
{
SVN_ERR(writebuf_write_literal(conn, pool, "( unlock ( "));
SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_cstring_opt(conn, pool, token));
- SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, token));
SVN_ERR(write_tuple_boolean(conn, pool, break_lock));
SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
@@ -2431,6 +2676,49 @@ svn_error_t *svn_ra_svn__write_cmd_failu
return writebuf_write_literal(conn, pool, ") ) ");
}
+/* Initializer for static svn_string_t . */
+#define STATIC_SVN_STRING(x) { x, sizeof(x) - 1 }
+
+/* Return a pre-cooked serialized representation for the changed path
+ flags NODE_KIND, TEXT_MODIFIED and PROPS_MODIFIED. If we don't
+ have a suitable pre-cooked string, return an empty string. */
+static const svn_string_t *
+changed_path_flags(svn_node_kind_t node_kind,
+ svn_boolean_t text_modified,
+ svn_boolean_t props_modified)
+{
+ const static svn_string_t file_flags[4]
+ = { STATIC_SVN_STRING(" ) ( 4:file false false ) ) "),
+ STATIC_SVN_STRING(" ) ( 4:file false true ) ) "),
+ STATIC_SVN_STRING(" ) ( 4:file true false ) ) "),
+ STATIC_SVN_STRING(" ) ( 4:file true true ) ) ") };
+
+ const static svn_string_t dir_flags[4]
+ = { STATIC_SVN_STRING(" ) ( 3:dir false false ) ) "),
+ STATIC_SVN_STRING(" ) ( 3:dir false true ) ) "),
+ STATIC_SVN_STRING(" ) ( 3:dir true false ) ) "),
+ STATIC_SVN_STRING(" ) ( 3:dir true true ) ) ") };
+
+ const static svn_string_t no_flags = STATIC_SVN_STRING("");
+
+ /* Select the array based on the NODE_KIND. */
+ const svn_string_t *flags;
+ if (node_kind == svn_node_file)
+ flags = file_flags;
+ else if (node_kind == svn_node_dir)
+ flags = dir_flags;
+ else
+ return &no_flags;
+
+ /* Select the correct array entry. */
+ if (text_modified)
+ flags += 2;
+ if (props_modified)
+ flags++;
+
+ return flags;
+}
+
svn_error_t *
svn_ra_svn__write_data_log_changed_path(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
@@ -2442,21 +2730,77 @@ svn_ra_svn__write_data_log_changed_path(
svn_boolean_t text_modified,
svn_boolean_t props_modified)
{
- SVN_ERR(write_tuple_start_list(conn, pool));
+ apr_size_t path_len = strlen(path);
+ apr_size_t copyfrom_len = copyfrom_path ? strlen(copyfrom_path) : 0;
+ const svn_string_t *flags_str = changed_path_flags(node_kind,
+ text_modified,
+ props_modified);
+
+ /* How much buffer space do we need (worst case)? */
+ apr_size_t needed = 2 /* list start */
+ + path_len + SVN_INT64_BUFFER_SIZE
+ /* path */
+ + 2 /* action */
+ + 2 + copyfrom_len + 2 * SVN_INT64_BUFFER_SIZE
+ /* list start + copy-from info */
+ + flags_str->len; /* flags and closing lists */
+
+ /* If the remaining buffer is big enough and we've got all parts,
+ directly copy into the buffer. */
+ if ( (conn->write_pos + needed <= sizeof(conn->write_buf))
+ && (flags_str->len > 0))
+ {
+ /* Quick path. */
+ /* Open list. */
+ char *p = conn->write_buf + conn->write_pos;
+ p[0] = '(';
+ p[1] = ' ';
+
+ /* Write path. */
+ p = write_ncstring_quick(p + 2, path, path_len);
+
+ /* Action */
+ p[0] = action;
+ p[1] = ' ';
+ p[2] = '(';
+
+ /* Copy-from info (if given) */
+ if (copyfrom_path)
+ {
+ p[3] = ' ';
+ p = write_ncstring_quick(p + 4, copyfrom_path, copyfrom_len);
+ p += svn__ui64toa(p, copyfrom_rev);
+ }
+ else
+ {
+ p += 3;
+ }
- SVN_ERR(write_tuple_cstring(conn, pool, path));
- SVN_ERR(writebuf_writechar(conn, pool, action));
- SVN_ERR(writebuf_writechar(conn, pool, ' '));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
- SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
- SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
- SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
- SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
+ /* Close with flags. */
+ memcpy(p, flags_str->data, flags_str->len);
+ conn->write_pos = p + flags_str->len - conn->write_buf;
+ }
+ else
+ {
+ /* Standard code path (fallback). */
+ SVN_ERR(write_tuple_start_list(conn, pool));
- return writebuf_write_literal(conn, pool, ") ) ");
+ SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, path, path_len));
+ SVN_ERR(writebuf_writechar(conn, pool, action));
+ SVN_ERR(writebuf_writechar(conn, pool, ' '));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
+ SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
+ SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_start_list(conn, pool));
+ SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
+ SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
+ SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
+
+ SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
+ }
+
+ return SVN_NO_ERROR;
}
svn_error_t *
@@ -2471,15 +2815,9 @@ svn_ra_svn__write_data_log_entry(svn_ra_
unsigned revprop_count)
{
SVN_ERR(write_tuple_revision(conn, pool, revision));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, author));
- SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, date));
- SVN_ERR(write_tuple_end_list(conn, pool));
- SVN_ERR(write_tuple_start_list(conn, pool));
- SVN_ERR(write_tuple_string_opt(conn, pool, message));
- SVN_ERR(write_tuple_end_list(conn, pool));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, author));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, date));
+ SVN_ERR(write_tuple_string_opt_list(conn, pool, message));
SVN_ERR(write_tuple_boolean(conn, pool, has_children));
SVN_ERR(write_tuple_boolean(conn, pool, invalid_revnum));
SVN_ERR(svn_ra_svn__write_number(conn, pool, revprop_count));
@@ -2497,13 +2835,13 @@ svn_ra_svn__write_data_log_entry(svn_ra_
/* In *RESULT, return the SVN-style string at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_string(const apr_array_header_t *items,
+svn_ra_svn__read_string(const svn_ra_svn__list_t *items,
int idx,
svn_string_t **result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
- *result = elt->u.string;
+ *result = &elt->u.string;
return SVN_NO_ERROR;
}
@@ -2511,13 +2849,13 @@ svn_ra_svn__read_string(const apr_array_
/* In *RESULT, return the C-style string at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_cstring(const apr_array_header_t *items,
+svn_ra_svn__read_cstring(const svn_ra_svn__list_t *items,
int idx,
const char **result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
- *result = elt->u.string->data;
+ *result = elt->u.string.data;
return SVN_NO_ERROR;
}
@@ -2525,11 +2863,11 @@ svn_ra_svn__read_cstring(const apr_array
/* In *RESULT, return the word at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_word(const apr_array_header_t *items,
+svn_ra_svn__read_word(const svn_ra_svn__list_t *items,
int idx,
const char **result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
*result = elt->u.word;
@@ -2539,11 +2877,11 @@ svn_ra_svn__read_word(const apr_array_he
/* In *RESULT, return the revision at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_revision(const apr_array_header_t *items,
+svn_ra_svn__read_revision(const svn_ra_svn__list_t *items,
int idx,
svn_revnum_t *result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_NUMBER);
*result = (svn_revnum_t)elt->u.number;
@@ -2553,11 +2891,11 @@ svn_ra_svn__read_revision(const apr_arra
/* In *RESULT, return the boolean at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_boolean(const apr_array_header_t *items,
+svn_ra_svn__read_boolean(const svn_ra_svn__list_t *items,
int idx,
apr_uint64_t *result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
if (elt->u.word[0] == 't' && strcmp(elt->u.word, "true") == 0)
*result = TRUE;
@@ -2572,21 +2910,21 @@ svn_ra_svn__read_boolean(const apr_array
/* In *RESULT, return the tuple at index IDX in tuple ITEMS.
*/
static svn_error_t *
-svn_ra_svn__read_list(const apr_array_header_t *items,
+svn_ra_svn__read_list(const svn_ra_svn__list_t *items,
int idx,
- const apr_array_header_t **result)
+ const svn_ra_svn__list_t **result)
{
- svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+ svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(items, idx);
CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_LIST);
- *result = elt->u.list;
+ *result = &elt->u.list;
return SVN_NO_ERROR;
}
/* Verify the tuple ITEMS contains at least MIN and at most MAX elements.
*/
static svn_error_t *
-svn_ra_svn__read_check_array_size(const apr_array_header_t *items,
+svn_ra_svn__read_check_array_size(const svn_ra_svn__list_t *items,
int min,
int max)
{
@@ -2595,7 +2933,7 @@ svn_ra_svn__read_check_array_size(const
}
svn_error_t *
-svn_ra_svn__read_data_log_changed_entry(const apr_array_header_t *items,
+svn_ra_svn__read_data_log_changed_entry(const svn_ra_svn__list_t *items,
svn_string_t **cpath,
const char **action,
const char **copy_path,
@@ -2604,7 +2942,7 @@ svn_ra_svn__read_data_log_changed_entry(
apr_uint64_t *text_mods,
apr_uint64_t *prop_mods)
{
- const apr_array_header_t *sub_items;
+ const svn_ra_svn__list_t *sub_items;
/* initialize optional values */
*copy_path = NULL;
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_ra_svn/ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_ra_svn/ra_svn.h?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_ra_svn/ra_svn.h (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_ra_svn/ra_svn.h Fri Sep 11 15:51:30 2015
@@ -165,8 +165,9 @@ svn_error_t *svn_ra_svn__locate_real_err
* command response indicating failure). The error chain will be
* in the same order as the errors indicated in @a params. Use
* @a pool for temporary allocations. */
-svn_error_t *svn_ra_svn__handle_failure_status(const apr_array_header_t *params,
- apr_pool_t *pool);
+svn_error_t *
+svn_ra_svn__handle_failure_status(const svn_ra_svn__list_t *params,
+ apr_pool_t *pool);
/* Returns a stream that reads/writes from/to SOCK. */
svn_ra_svn__stream_t *svn_ra_svn__stream_from_sock(apr_socket_t *sock,
@@ -220,7 +221,7 @@ svn_ra_svn__stream_data_available(svn_ra
* tokens. */
svn_error_t *
svn_ra_svn__do_cyrus_auth(svn_ra_svn__session_baton_t *sess,
- const apr_array_header_t *mechlist,
+ const svn_ra_svn__list_t *mechlist,
const char *realm, apr_pool_t *pool);
/* Same as svn_ra_svn__do_cyrus_auth, but uses the built-in implementation of
@@ -229,7 +230,7 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__se
* mechanism with the server. */
svn_error_t *
svn_ra_svn__do_internal_auth(svn_ra_svn__session_baton_t *sess,
- const apr_array_header_t *mechlist,
+ const svn_ra_svn__list_t *mechlist,
const char *realm, apr_pool_t *pool);
/* Having picked a mechanism, start authentication by writing out an
@@ -239,8 +240,8 @@ svn_error_t *svn_ra_svn__auth_response(s
apr_pool_t *pool,
const char *mech, const char *mech_arg);
-/* Looks for MECH as a word in MECHLIST (an array of svn_ra_svn_item_t). */
-svn_boolean_t svn_ra_svn__find_mech(const apr_array_header_t *mechlist,
+/* Looks for MECH as a word in MECHLIST. */
+svn_boolean_t svn_ra_svn__find_mech(const svn_ra_svn__list_t *mechlist,
const char *mech);
/* Initialize the SASL library. */
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_repos/deprecated.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_repos/deprecated.c Fri Sep 11 15:51:30 2015
@@ -731,6 +731,33 @@ repos_notify_handler(void *baton,
}
}
+svn_error_t *
+svn_repos_dump_fs3(svn_repos_t *repos,
+ svn_stream_t *stream,
+ svn_revnum_t start_rev,
+ svn_revnum_t end_rev,
+ svn_boolean_t incremental,
+ svn_boolean_t use_deltas,
+ svn_repos_notify_func_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_repos_dump_fs4(repos,
+ stream,
+ start_rev,
+ end_rev,
+ incremental,
+ use_deltas,
+ TRUE,
+ TRUE,
+ notify_func,
+ notify_baton,
+ cancel_func,
+ cancel_baton,
+ pool));
+}
svn_error_t *
svn_repos_dump_fs2(svn_repos_t *repos,
@@ -774,9 +801,9 @@ svn_repos_verify_fs2(svn_repos_t *repos,
end_rev,
FALSE,
FALSE,
- FALSE,
notify_func,
notify_baton,
+ NULL, NULL,
cancel_func,
cancel_baton,
pool));
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_repos/dump.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_repos/dump.c Fri Sep 11 15:51:30 2015
@@ -1919,33 +1919,44 @@ get_dump_editor(const svn_delta_editor_t
/* Helper for svn_repos_dump_fs.
Write a revision record of REV in FS to writable STREAM, using POOL.
+ Dump revision properties as well if INCLUDE_REVPROPS has been set.
*/
static svn_error_t *
write_revision_record(svn_stream_t *stream,
svn_fs_t *fs,
svn_revnum_t rev,
+ svn_boolean_t include_revprops,
apr_pool_t *pool)
{
apr_hash_t *props;
apr_time_t timetemp;
svn_string_t *datevalue;
- SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool));
+ if (include_revprops)
+ {
+ SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool));
- /* Run revision date properties through the time conversion to
- canonicalize them. */
- /* ### Remove this when it is no longer needed for sure. */
- datevalue = svn_hash_gets(props, SVN_PROP_REVISION_DATE);
- if (datevalue)
- {
- SVN_ERR(svn_time_from_cstring(&timetemp, datevalue->data, pool));
- datevalue = svn_string_create(svn_time_to_cstring(timetemp, pool),
- pool);
- svn_hash_sets(props, SVN_PROP_REVISION_DATE, datevalue);
+ /* Run revision date properties through the time conversion to
+ canonicalize them. */
+ /* ### Remove this when it is no longer needed for sure. */
+ datevalue = svn_hash_gets(props, SVN_PROP_REVISION_DATE);
+ if (datevalue)
+ {
+ SVN_ERR(svn_time_from_cstring(&timetemp, datevalue->data, pool));
+ datevalue = svn_string_create(svn_time_to_cstring(timetemp, pool),
+ pool);
+ svn_hash_sets(props, SVN_PROP_REVISION_DATE, datevalue);
+ }
+ }
+ else
+ {
+ /* Although we won't use it, we still need this container for the
+ call below. */
+ props = apr_hash_make(pool);
}
SVN_ERR(svn_repos__dump_revision_record(stream, rev, NULL, props,
- TRUE /*props_section_always*/,
+ include_revprops,
pool));
return SVN_NO_ERROR;
}
@@ -1954,12 +1965,14 @@ write_revision_record(svn_stream_t *stre
/* The main dumper. */
svn_error_t *
-svn_repos_dump_fs3(svn_repos_t *repos,
+svn_repos_dump_fs4(svn_repos_t *repos,
svn_stream_t *stream,
svn_revnum_t start_rev,
svn_revnum_t end_rev,
svn_boolean_t incremental,
svn_boolean_t use_deltas,
+ svn_boolean_t include_revprops,
+ svn_boolean_t include_changes,
svn_repos_notify_func_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
@@ -1970,7 +1983,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
void *dump_edit_baton = NULL;
svn_revnum_t rev;
svn_fs_t *fs = svn_repos_fs(repos);
- apr_pool_t *subpool = svn_pool_create(pool);
+ apr_pool_t *iterpool = svn_pool_create(pool);
svn_revnum_t youngest;
const char *uuid;
int version;
@@ -2029,18 +2042,20 @@ svn_repos_dump_fs3(svn_repos_t *repos,
svn_fs_root_t *to_root;
svn_boolean_t use_deltas_for_rev;
- svn_pool_clear(subpool);
+ svn_pool_clear(iterpool);
/* Check for cancellation. */
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
/* Write the revision record. */
- SVN_ERR(write_revision_record(stream, fs, rev, subpool));
+ SVN_ERR(write_revision_record(stream, fs, rev, include_revprops,
+ iterpool));
/* When dumping revision 0, we just write out the revision record.
- The parser might want to use its properties. */
- if (rev == 0)
+ The parser might want to use its properties.
+ If we don't want revision changes at all, skip in any case. */
+ if (rev == 0 || !include_changes)
goto loop_end;
/* Fetch the editor which dumps nodes to a file. Regardless of
@@ -2052,10 +2067,10 @@ svn_repos_dump_fs3(svn_repos_t *repos,
&found_old_mergeinfo, NULL,
notify_func, notify_baton,
start_rev, use_deltas_for_rev, FALSE, FALSE,
- subpool));
+ iterpool));
/* Drive the editor in one way or another. */
- SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, subpool));
+ SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool));
/* If this is the first revision of a non-incremental dump,
we're in for a full tree dump. Otherwise, we want to simply
@@ -2064,7 +2079,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
{
/* Compare against revision 0, so everything appears to be added. */
svn_fs_root_t *from_root;
- SVN_ERR(svn_fs_revision_root(&from_root, fs, 0, subpool));
+ SVN_ERR(svn_fs_revision_root(&from_root, fs, 0, iterpool));
SVN_ERR(svn_repos_dir_delta2(from_root, "", "",
to_root, "",
dump_editor, dump_edit_baton,
@@ -2074,25 +2089,25 @@ svn_repos_dump_fs3(svn_repos_t *repos,
svn_depth_infinity,
FALSE, /* don't send entry props */
FALSE, /* don't ignore ancestry */
- subpool));
+ iterpool));
}
else
{
/* The normal case: compare consecutive revs. */
SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
dump_editor, dump_edit_baton,
- NULL, NULL, subpool));
+ NULL, NULL, iterpool));
/* While our editor close_edit implementation is a no-op, we still
do this for completeness. */
- SVN_ERR(dump_editor->close_edit(dump_edit_baton, subpool));
+ SVN_ERR(dump_editor->close_edit(dump_edit_baton, iterpool));
}
loop_end:
if (notify_func)
{
notify->revision = rev;
- notify_func(notify_baton, notify, subpool);
+ notify_func(notify_baton, notify, iterpool);
}
}
@@ -2103,12 +2118,12 @@ svn_repos_dump_fs3(svn_repos_t *repos,
warning, since the inline warnings already issued might easily be
missed. */
- notify = svn_repos_notify_create(svn_repos_notify_dump_end, subpool);
- notify_func(notify_baton, notify, subpool);
+ notify = svn_repos_notify_create(svn_repos_notify_dump_end, iterpool);
+ notify_func(notify_baton, notify, iterpool);
if (found_old_reference)
{
- notify_warning(subpool, notify_func, notify_baton,
+ notify_warning(iterpool, notify_func, notify_baton,
svn_repos_notify_warning_found_old_reference,
_("The range of revisions dumped "
"contained references to "
@@ -2120,7 +2135,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
in dumped mergeinfo. */
if (found_old_mergeinfo)
{
- notify_warning(subpool, notify_func, notify_baton,
+ notify_warning(iterpool, notify_func, notify_baton,
svn_repos_notify_warning_found_old_mergeinfo,
_("The range of revisions dumped "
"contained mergeinfo "
@@ -2129,7 +2144,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
}
}
- svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -2265,24 +2280,6 @@ verify_close_directory(void *dir_baton,
return close_directory(dir_baton, pool);
}
-static void
-notify_verification_error(svn_revnum_t rev,
- svn_error_t *err,
- svn_repos_notify_func_t notify_func,
- void *notify_baton,
- apr_pool_t *pool)
-{
- svn_repos_notify_t *notify_failure;
-
- if (notify_func == NULL)
- return;
-
- notify_failure = svn_repos_notify_create(svn_repos_notify_failure, pool);
- notify_failure->err = err;
- notify_failure->revision = rev;
- notify_func(notify_baton, notify_failure, pool);
-}
-
/* Verify revision REV in file system FS. */
static svn_error_t *
verify_one_revision(svn_fs_t *fs,
@@ -2359,15 +2356,42 @@ verify_fs_notify_func(svn_revnum_t revis
notify_baton->notify, pool);
}
+static svn_error_t *
+report_error(svn_revnum_t revision,
+ svn_error_t *verify_err,
+ svn_repos_verify_callback_t verify_callback,
+ void *verify_baton,
+ apr_pool_t *pool)
+{
+ if (verify_callback)
+ {
+ svn_error_t *cb_err;
+
+ /* The caller provided us with a callback, so make him responsible
+ for what's going to happen with the error. */
+ cb_err = verify_callback(verify_baton, revision, verify_err, pool);
+ svn_error_clear(verify_err);
+ SVN_ERR(cb_err);
+
+ return SVN_NO_ERROR;
+ }
+ else
+ {
+ /* No callback -- no second guessing. Just return the error. */
+ return svn_error_trace(verify_err);
+ }
+}
+
svn_error_t *
svn_repos_verify_fs3(svn_repos_t *repos,
svn_revnum_t start_rev,
svn_revnum_t end_rev,
- svn_boolean_t keep_going,
svn_boolean_t check_normalization,
svn_boolean_t metadata_only,
svn_repos_notify_func_t notify_func,
void *notify_baton,
+ svn_repos_verify_callback_t verify_callback,
+ void *verify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
@@ -2380,8 +2404,6 @@ svn_repos_verify_fs3(svn_repos_t *repos,
svn_fs_progress_notify_func_t verify_notify = NULL;
struct verify_fs_notify_func_baton_t *verify_notify_baton = NULL;
svn_error_t *err;
- svn_boolean_t failed_metadata = FALSE;
- svn_revnum_t failed_revisions = 0;
/* Determine the current youngest revision of the filesystem. */
SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -2430,20 +2452,8 @@ svn_repos_verify_fs3(svn_repos_t *repos,
}
else if (err)
{
- notify_verification_error(SVN_INVALID_REVNUM, err, notify_func,
- notify_baton, iterpool);
-
- if (!keep_going)
- {
- /* Return the error, the caller doesn't want us to continue. */
- return svn_error_trace(err);
- }
- else
- {
- /* Clear the error and keep going. */
- failed_metadata = TRUE;
- svn_error_clear(err);
- }
+ SVN_ERR(report_error(SVN_INVALID_REVNUM, err, verify_callback,
+ verify_baton, iterpool));
}
if (!metadata_only)
@@ -2463,20 +2473,8 @@ svn_repos_verify_fs3(svn_repos_t *repos,
}
else if (err)
{
- notify_verification_error(rev, err, notify_func, notify_baton,
- iterpool);
-
- if (!keep_going)
- {
- /* Return the error, the caller doesn't want us to continue. */
- return svn_error_trace(err);
- }
- else
- {
- /* Clear the error and keep going. */
- ++failed_revisions;
- svn_error_clear(err);
- }
+ SVN_ERR(report_error(rev, err, verify_callback, verify_baton,
+ iterpool));
}
else if (notify_func)
{
@@ -2495,40 +2493,5 @@ svn_repos_verify_fs3(svn_repos_t *repos,
svn_pool_destroy(iterpool);
- /* Summarize the results. */
- if (failed_metadata || 0 != failed_revisions)
- {
- const char *const repos_path =
- svn_dirent_local_style(svn_repos_path(repos, pool), pool);
-
- if (0 == failed_revisions)
- {
- return svn_error_createf(
- SVN_ERR_REPOS_VERIFY_FAILED, NULL,
- _("Metadata verification failed on repository '%s'"),
- repos_path);
- }
- else
- {
- const char* format_string;
-
- if (failed_metadata)
- format_string = apr_psprintf(
- pool, _("Verification of metadata and"
- " %%%s out of %%%s revisions"
- " failed on repository '%%s'"),
- SVN_REVNUM_T_FMT, SVN_REVNUM_T_FMT);
- else
- format_string = apr_psprintf(
- pool, _("Verification of %%%s out of %%%s revisions"
- " failed on repository '%%s'"),
- SVN_REVNUM_T_FMT, SVN_REVNUM_T_FMT);
-
- return svn_error_createf(
- SVN_ERR_REPOS_VERIFY_FAILED, NULL, format_string,
- failed_revisions, end_rev - start_rev + 1, repos_path);
- }
- }
-
return SVN_NO_ERROR;
}
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_repos/fs-wrap.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_repos/fs-wrap.c Fri Sep 11 15:51:30 2015
@@ -975,15 +975,18 @@ pack_notify_func(void *baton,
{
struct pack_notify_baton *pnb = baton;
svn_repos_notify_t *notify;
+ svn_repos_notify_action_t repos_action;
/* Simple conversion works for these values. */
SVN_ERR_ASSERT(pack_action >= svn_fs_pack_notify_start
- && pack_action <= svn_fs_pack_notify_end_revprop);
+ && pack_action <= svn_fs_pack_notify_noop);
- notify = svn_repos_notify_create(pack_action
- + svn_repos_notify_pack_shard_start
- - svn_fs_pack_notify_start,
- pool);
+ repos_action = pack_action == svn_fs_pack_notify_noop
+ ? svn_repos_notify_pack_noop
+ : pack_action + svn_repos_notify_pack_shard_start
+ - svn_fs_pack_notify_start;
+
+ notify = svn_repos_notify_create(repos_action, pool);
notify->shard = shard;
pnb->notify_func(pnb->notify_baton, notify, pool);
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_repos/load-fs-vtable.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_repos/load-fs-vtable.c Fri Sep 11 15:51:30 2015
@@ -624,14 +624,6 @@ maybe_add_with_history(struct node_baton
}
static svn_error_t *
-magic_header_record(int version,
- void *parse_baton,
- apr_pool_t *pool)
-{
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
uuid_record(const char *uuid,
void *parse_baton,
apr_pool_t *pool)
@@ -1194,7 +1186,7 @@ svn_repos_get_fs_build_parser5(const svn
if (SVN_IS_VALID_REVNUM(start_rev))
SVN_ERR_ASSERT(start_rev <= end_rev);
- parser->magic_header_record = magic_header_record;
+ parser->magic_header_record = NULL;
parser->uuid_record = uuid_record;
parser->new_revision_record = new_revision_record;
parser->new_node_record = new_node_record;
@@ -1271,3 +1263,215 @@ svn_repos_load_fs5(svn_repos_t *repos,
return svn_repos_parse_dumpstream3(dumpstream, parser, parse_baton, FALSE,
cancel_func, cancel_baton, pool);
}
+
+/*----------------------------------------------------------------------*/
+
+/** The same functionality for revprops only **/
+
+/* Implement svn_repos_parse_fns3_t.new_revision_record.
+ *
+ * Because the revision is supposed to already exist, we don't need to
+ * start transactions etc. */
+static svn_error_t *
+revprops_new_revision_record(void **revision_baton,
+ apr_hash_t *headers,
+ void *parse_baton,
+ apr_pool_t *pool)
+{
+ struct parse_baton *pb = parse_baton;
+ struct revision_baton *rb;
+
+ rb = make_revision_baton(headers, pb, pool);
+
+ /* If we're skipping this revision, try to notify someone. */
+ if (rb->skipped && pb->notify_func)
+ {
+ /* ### TODO: Use proper scratch pool instead of pb->notify_pool */
+ svn_repos_notify_t *notify = svn_repos_notify_create(
+ svn_repos_notify_load_skipped_rev,
+ pb->notify_pool);
+
+ notify->old_revision = rb->rev;
+ pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
+ svn_pool_clear(pb->notify_pool);
+ }
+
+ /* If we're parsing revision 0, only the revision props are (possibly)
+ interesting to us: when loading the stream into an empty
+ filesystem, then we want new filesystem's revision 0 to have the
+ same props. Otherwise, we just ignore revision 0 in the stream. */
+
+ *revision_baton = rb;
+ return SVN_NO_ERROR;
+}
+
+/* Implement svn_repos_parse_fns3_t.close_revision.
+ *
+ * Simply set the revprops we previously parsed and send notifications.
+ * This is the place where we will detect missing revisions. */
+static svn_error_t *
+revprops_close_revision(void *baton)
+{
+ struct revision_baton *rb = baton;
+ struct parse_baton *pb = rb->pb;
+ apr_hash_t *orig_props;
+ apr_hash_t *new_props;
+ apr_array_header_t *diff;
+ int i;
+
+ /* If we're skipping this revision we're done here. */
+ if (rb->skipped)
+ return SVN_NO_ERROR;
+
+ /* If the dumpstream doesn't have an 'svn:date' property and we
+ aren't ignoring the dates in the dumpstream altogether, remove
+ any 'svn:date' revision property that was set by FS layer when
+ the TXN was created. */
+ if (! (pb->ignore_dates || rb->datestamp))
+ {
+ svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
+ prop->name = SVN_PROP_REVISION_DATE;
+ prop->value = NULL;
+ }
+
+ SVN_ERR(svn_fs_revision_proplist(&orig_props, pb->fs, rb->rev, rb->pool));
+ new_props = svn_prop_array_to_hash(rb->revprops, rb->pool);
+ SVN_ERR(svn_prop_diffs(&diff, new_props, orig_props, rb->pool));
+
+ for (i = 0; i < diff->nelts; i++)
+ {
+ const svn_prop_t *prop = &APR_ARRAY_IDX(diff, i, svn_prop_t);
+
+ SVN_ERR(change_rev_prop(pb->repos, rb->rev, prop->name, prop->value,
+ pb->validate_props, rb->pool));
+ }
+
+ if (pb->notify_func)
+ {
+ /* ### TODO: Use proper scratch pool instead of pb->notify_pool */
+ svn_repos_notify_t *notify = svn_repos_notify_create(
+ svn_repos_notify_load_revprop_set,
+ pb->notify_pool);
+
+ notify->new_revision = rb->rev;
+ notify->old_revision = SVN_INVALID_REVNUM;
+ pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
+ svn_pool_clear(pb->notify_pool);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Set *CALLBACKS and *PARSE_BATON to a vtable parser which commits new
+ * revisions to the fs in REPOS. Allocate the objects in RESULT_POOL.
+ *
+ * START_REV and END_REV act as filters, the lower and upper (inclusive)
+ * range values of revisions in DUMPSTREAM which will be loaded. Either
+ * both of these values are #SVN_INVALID_REVNUM (in which case no
+ * revision-based filtering occurs at all), or both are valid revisions
+ * (where START_REV is older than or equivalent to END_REV).
+ *
+ * START_REV and END_REV act as filters, the lower and upper (inclusive)
+ * range values of revisions which will
+ * be loaded. Either both of these values are #SVN_INVALID_REVNUM (in
+ * which case no revision-based filtering occurs at all), or both are
+ * valid revisions (where START_REV is older than or equivalent to
+ * END_REV). They refer to dump stream revision numbers rather than
+ * committed revision numbers.
+ *
+ * If VALIDATE_PROPS is set, then validate Subversion revision properties
+ * (those in the svn: namespace) against established rules for those things.
+ *
+ * If IGNORE_DATES is set, ignore any revision datestamps found in
+ * DUMPSTREAM, keeping whatever timestamps the revisions currently have.
+ */
+static svn_error_t *
+build_revprop_parser(const svn_repos_parse_fns3_t **callbacks,
+ void **parse_baton,
+ svn_repos_t *repos,
+ svn_revnum_t start_rev,
+ svn_revnum_t end_rev,
+ svn_boolean_t validate_props,
+ svn_boolean_t ignore_dates,
+ svn_repos_notify_func_t notify_func,
+ void *notify_baton,
+ apr_pool_t *result_pool)
+{
+ svn_repos_parse_fns3_t *parser = apr_pcalloc(result_pool, sizeof(*parser));
+ struct parse_baton *pb = apr_pcalloc(result_pool, sizeof(*pb));
+
+ SVN_ERR_ASSERT((SVN_IS_VALID_REVNUM(start_rev) &&
+ SVN_IS_VALID_REVNUM(end_rev))
+ || ((! SVN_IS_VALID_REVNUM(start_rev)) &&
+ (! SVN_IS_VALID_REVNUM(end_rev))));
+ if (SVN_IS_VALID_REVNUM(start_rev))
+ SVN_ERR_ASSERT(start_rev <= end_rev);
+
+ parser->magic_header_record = NULL;
+ parser->uuid_record = uuid_record;
+ parser->new_revision_record = revprops_new_revision_record;
+ parser->new_node_record = NULL;
+ parser->set_revision_property = set_revision_property;
+ parser->set_node_property = NULL;
+ parser->remove_node_props = NULL;
+ parser->set_fulltext = NULL;
+ parser->close_node = NULL;
+ parser->close_revision = revprops_close_revision;
+ parser->delete_node_property = NULL;
+ parser->apply_textdelta = NULL;
+
+ pb->repos = repos;
+ pb->fs = svn_repos_fs(repos);
+ pb->use_history = FALSE;
+ pb->validate_props = validate_props;
+ pb->notify_func = notify_func;
+ pb->notify_baton = notify_baton;
+ pb->uuid_action = svn_repos_load_uuid_ignore; /* Never touch the UUID. */
+ pb->parent_dir = NULL;
+ pb->pool = result_pool;
+ pb->notify_pool = svn_pool_create(result_pool);
+ pb->rev_map = NULL;
+ pb->oldest_dumpstream_rev = SVN_INVALID_REVNUM;
+ pb->last_rev_mapped = SVN_INVALID_REVNUM;
+ pb->start_rev = start_rev;
+ pb->end_rev = end_rev;
+ pb->use_pre_commit_hook = FALSE;
+ pb->use_post_commit_hook = FALSE;
+ pb->ignore_dates = ignore_dates;
+
+ *callbacks = parser;
+ *parse_baton = pb;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_repos_load_fs_revprops(svn_repos_t *repos,
+ svn_stream_t *dumpstream,
+ svn_revnum_t start_rev,
+ svn_revnum_t end_rev,
+ svn_boolean_t validate_props,
+ svn_boolean_t ignore_dates,
+ svn_repos_notify_func_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ const svn_repos_parse_fns3_t *parser;
+ void *parse_baton;
+
+ /* This is really simple. */
+
+ SVN_ERR(build_revprop_parser(&parser, &parse_baton,
+ repos,
+ start_rev, end_rev,
+ validate_props,
+ ignore_dates,
+ notify_func,
+ notify_baton,
+ scratch_pool));
+
+ return svn_repos_parse_dumpstream3(dumpstream, parser, parse_baton, FALSE,
+ cancel_func, cancel_baton, scratch_pool);
+}
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_repos/load.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_repos/load.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_repos/load.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_repos/load.c Fri Sep 11 15:51:30 2015
@@ -385,7 +385,135 @@ parse_format_version(int *version,
return SVN_NO_ERROR;
}
+/*----------------------------------------------------------------------*/
+
+/** Dummy callback implementations for functions not provided by the user **/
+
+static svn_error_t *
+dummy_handler_magic_header_record(int version,
+ void *parse_baton,
+ apr_pool_t *pool)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_uuid_record(const char *uuid,
+ void *parse_baton,
+ apr_pool_t *pool)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_new_revision_record(void **revision_baton,
+ apr_hash_t *headers,
+ void *parse_baton,
+ apr_pool_t *pool)
+{
+ *revision_baton = NULL;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_new_node_record(void **node_baton,
+ apr_hash_t *headers,
+ void *revision_baton,
+ apr_pool_t *pool)
+{
+ *node_baton = NULL;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_set_revision_property(void *revision_baton,
+ const char *name,
+ const svn_string_t *value)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_set_node_property(void *node_baton,
+ const char *name,
+ const svn_string_t *value)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_delete_node_property(void *node_baton,
+ const char *name)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_remove_node_props(void *node_baton)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_set_fulltext(svn_stream_t **stream,
+ void *node_baton)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_apply_textdelta(svn_txdelta_window_handler_t *handler,
+ void **handler_baton,
+ void *node_baton)
+{
+ /* Only called by parse_text_block() and that tests for NULL handlers. */
+ *handler = NULL;
+ *handler_baton = NULL;
+ return SVN_NO_ERROR;
+}
+static svn_error_t *
+dummy_handler_close_node(void *node_baton)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+dummy_handler_close_revision(void *revision_baton)
+{
+ return SVN_NO_ERROR;
+}
+
+/* Helper macro to copy the function pointer SOURCE->NAME to DEST->NAME.
+ * If the source pointer is NULL, pick the corresponding dummy handler
+ * instead. */
+#define SET_VTABLE_ENTRY(dest, source, name) \
+ dest->name = provided->name ? provided->name : dummy_handler_##name
+
+/* Return a copy of PROVIDED with all NULL callbacks replaced by a dummy
+ * handler. Allocate the result in RESULT_POOL. */
+static const svn_repos_parse_fns3_t *
+complete_vtable(const svn_repos_parse_fns3_t *provided,
+ apr_pool_t *result_pool)
+{
+ svn_repos_parse_fns3_t *completed = apr_pcalloc(result_pool,
+ sizeof(*completed));
+
+ SET_VTABLE_ENTRY(completed, provided, magic_header_record);
+ SET_VTABLE_ENTRY(completed, provided, uuid_record);
+ SET_VTABLE_ENTRY(completed, provided, new_revision_record);
+ SET_VTABLE_ENTRY(completed, provided, new_node_record);
+ SET_VTABLE_ENTRY(completed, provided, set_revision_property);
+ SET_VTABLE_ENTRY(completed, provided, set_node_property);
+ SET_VTABLE_ENTRY(completed, provided, delete_node_property);
+ SET_VTABLE_ENTRY(completed, provided, remove_node_props);
+ SET_VTABLE_ENTRY(completed, provided, set_fulltext);
+ SET_VTABLE_ENTRY(completed, provided, apply_textdelta);
+ SET_VTABLE_ENTRY(completed, provided, close_node);
+ SET_VTABLE_ENTRY(completed, provided, close_revision);
+
+ return completed;
+}
/*----------------------------------------------------------------------*/
@@ -410,6 +538,10 @@ svn_repos_parse_dumpstream3(svn_stream_t
apr_pool_t *nodepool = svn_pool_create(pool);
int version;
+ /* Make sure we can blindly invoke callbacks. */
+ parse_fns = complete_vtable(parse_fns, pool);
+
+ /* Start parsing process. */
SVN_ERR(svn_stream_readline(stream, &linebuf, "\n", &eof, linepool));
if (eof)
return stream_ran_dry();
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_repos/log.c?rev=1702504&r1=1702503&r2=1702504&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_repos/log.c Fri Sep 11 15:51:30 2015
@@ -1907,8 +1907,7 @@ store_search(svn_mergeinfo_t processed,
const char *path = APR_ARRAY_IDX(paths, i, const char *);
svn_rangelist_t *ranges = apr_array_make(processed_pool, 1,
sizeof(svn_merge_range_t*));
- svn_merge_range_t *range = apr_palloc(processed_pool,
- sizeof(svn_merge_range_t));
+ svn_merge_range_t *range = apr_palloc(processed_pool, sizeof(*range));
range->start = start;
range->end = end;
@@ -2176,7 +2175,7 @@ do_logs(svn_fs_t *fs,
if (rev_mergeinfo)
{
struct added_deleted_mergeinfo *add_and_del_mergeinfo =
- apr_hash_get(rev_mergeinfo, ¤t, sizeof(svn_revnum_t));
+ apr_hash_get(rev_mergeinfo, ¤t, sizeof(current));
added_mergeinfo = add_and_del_mergeinfo->added_mergeinfo;
deleted_mergeinfo = add_and_del_mergeinfo->deleted_mergeinfo;
has_children = (apr_hash_count(added_mergeinfo) > 0