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
