On Tue, Feb 15, 2011 at 2:53 PM, Stefan Sperling <s...@elego.de> wrote: > On Tue, Feb 15, 2011 at 01:30:45PM +0100, Stefan Sperling wrote: >> On Mon, Feb 14, 2011 at 09:48:35PM +0100, Branko Čibej wrote: >> > On 14.02.2011 13:37, Stefan Sperling wrote: >> > > On Tue, Feb 08, 2011 at 11:50:36PM +0100, Branko Čibej wrote: >> > >> Well, here it is, I fixed the thinko in the actual_props query and got >> > >> all prop_tests to pass with this version. >> > > Just FYI, the patch doesn't apply to HEAD. I'll try to adjust it when >> > > I find time. But maybe you'll be quicker than me? :) >> > >> > It got clobbered by Hyrum's changes for pdh checking, if I read the >> > conflict diff correctly. Should really be just the one conflict in >> > wc_db.c, probably. I'll see if I can find time to update the patch, but >> > I can't promise anything, got my hands full right now. >> >> Updated version: > > The patch was missing a bump of SVN_WC__VERSION so auto-upgrade didn't work. > Update below. > > I think we should commit this and continue working on it. > Is it OK to bump the WC format now?
I've not reviewed the patch, but to the question about bumping the wc format, I think you're safe to do so (so long as the upgrade code is properly implemented / tested, etc). The current working copy much more gracefully handles upgrades, and is *should* Just Work. -Hyrum > > Here's a log message: > > [[[ > Improve performance of svn proplist in a similar way as was done in r1039808. > But, this time, avoid problems with callbacks invoked during sqlite > transactions by storing results in a temporary table and invoking > callbacks during a query on the temporary table. > > Patch by: brane > > * subversion/libsvn_wc/props.c > (read_dir_props): Adjust caller of svn_wc__db_read_props_of_immediates(). > (svn_wc__prop_list_recursive): Reimplement using new wc_db APIs. > > * subversion/libsvn_wc/wc.h > (SVN_WC__VERSION): Bump to 25 (format 25 adds NODES_CURRENT view). > > * subversion/libsvn_wc/wc-queries.sql > (STMT_CLEAR_NODE_PROPS_CACHE, STMT_CACHE_NODE_PROPS_RECURSIVE, > STMT_CACHE_ACTUAL_PROPS_RECURSIVE, STMT_CACHE_NODE_PROPS_OF_CHILDREN, > STMT_CACHE_ACTUAL_PROPS_OF_CHILDREN, > STMT_SELECT_RELEVANT_PROPS_FROM_CACHE): New queries. > > * subversion/libsvn_wc/wc-metadata.sql > (NODES_CURRENT): A view on the NODES table that shows only the nodes > with the highest op_depth. > (STMT_UPGRADE_TO_25): Upgrade statement which creates NODES_CURRENT. > > * subversion/libsvn_wc/wc_db.c > (maybe_add_child_props, read_props_of_children): Remove. > (cache_props_baton_t): New baton type used by cache_props_recursive(). > (cache_props_recursive): New. Helper for read_props_recursive(). > (read_props_recursive): New. Recursively reads properties from wc_db. > Recursion can be limited by depth. Uses the new queries to create > a temporary table containing information about properties and pass > the results to the receiver callback. > (svn_wc__db_read_props_of_files, > svn_wc__db_read_props_of_immediates): Call read_props_recursive() instead > of read_props_of_children(). Add support for cancellation. > > * subversion/libsvn_wc/wc_db.h > (svn_wc__db_read_props_of_files, > svn_wc__db_read_props_of_immediates): Update declarations. > (svn_wc__db_read_props_recursive): Declare. > > * subversion/libsvn_wc/upgrade.c > (bump_to_25): New. > (svn_wc__upgrade_sdb): Upgrade to format 25. > ]]] > > Index: subversion/libsvn_wc/props.c > =================================================================== > --- subversion/libsvn_wc/props.c (revision 1070853) > +++ subversion/libsvn_wc/props.c (working copy) > @@ -1711,6 +1711,7 @@ read_dir_props(const char *local_abspath, > SVN_ERR(svn_wc__db_read_props_of_immediates(b->db, local_abspath, > b->receiver_func, > b->receiver_baton, > + NULL, NULL, > scratch_pool)); > return SVN_NO_ERROR; > } > @@ -1725,47 +1726,41 @@ svn_wc__prop_list_recursive(svn_wc_context_t *wc_c > void *cancel_baton, > apr_pool_t *scratch_pool) > { > - struct read_dir_props_baton read_dir_baton; > - > - if (depth <= svn_depth_immediates) > + switch (depth) > { > - apr_hash_t *props; > + case svn_depth_empty: > + { > + apr_hash_t *props; > > - SVN_ERR(svn_wc__db_read_props(&props, wc_ctx->db, local_abspath, > - scratch_pool, scratch_pool)); > - if (receiver_func && props && apr_hash_count(props) > 0) > - SVN_ERR((*receiver_func)(receiver_baton, local_abspath, props, > - scratch_pool)); > - if (depth == svn_depth_empty) > - return SVN_NO_ERROR; > - } > - > - if (depth == svn_depth_files) > - { > + SVN_ERR(svn_wc__db_read_props(&props, wc_ctx->db, local_abspath, > + scratch_pool, scratch_pool)); > + if (receiver_func && props && apr_hash_count(props) > 0) > + SVN_ERR((*receiver_func)(receiver_baton, local_abspath, props, > + scratch_pool)); > + } > + break; > + case svn_depth_files: > SVN_ERR(svn_wc__db_read_props_of_files(wc_ctx->db, local_abspath, > receiver_func, receiver_baton, > + cancel_func, cancel_baton, > scratch_pool)); > - return SVN_NO_ERROR; > - } > - > - if (depth == svn_depth_immediates) > - { > + break; > + case svn_depth_immediates: > SVN_ERR(svn_wc__db_read_props_of_immediates(wc_ctx->db, local_abspath, > - receiver_func, > - receiver_baton, > + receiver_func, > receiver_baton, > + cancel_func, cancel_baton, > scratch_pool)); > - return SVN_NO_ERROR; > + break; > + case svn_depth_infinity: > + SVN_ERR(svn_wc__db_read_props_recursive(wc_ctx->db, local_abspath, > + receiver_func, receiver_baton, > + cancel_func, cancel_baton, > + scratch_pool)); > + break; > + default: > + SVN_ERR_MALFUNCTION(); > } > > - read_dir_baton.db = wc_ctx->db; > - read_dir_baton.root_abspath = local_abspath; > - read_dir_baton.receiver_func = receiver_func; > - read_dir_baton.receiver_baton = receiver_baton; > - > - SVN_ERR(svn_wc__internal_walk_children(wc_ctx->db, local_abspath, FALSE, > - read_dir_props, &read_dir_baton, > - depth, cancel_func, cancel_baton, > - scratch_pool)); > return SVN_NO_ERROR; > } > > Index: subversion/libsvn_wc/wc.h > =================================================================== > --- subversion/libsvn_wc/wc.h (revision 1070853) > +++ subversion/libsvn_wc/wc.h (working copy) > @@ -141,7 +141,7 @@ extern "C" { > * Please document any further format changes here. > */ > > -#define SVN_WC__VERSION 24 > +#define SVN_WC__VERSION 25 > > > /* Formats <= this have no concept of "revert text-base/props". */ > Index: subversion/libsvn_wc/wc-queries.sql > =================================================================== > --- subversion/libsvn_wc/wc-queries.sql (revision 1070853) > +++ subversion/libsvn_wc/wc-queries.sql (working copy) > @@ -741,7 +741,62 @@ SELECT 1 FROM nodes WHERE op_depth > 0; > UPDATE nodes SET checksum = ?4 > WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3; > > +/* ------------------------------------------------------------------------- > */ > +/* PROOF OF CONCEPT: Complex queries for callback walks, caching results > + in a temporary table. */ > > +-- STMT_CLEAR_NODE_PROPS_CACHE > +DROP TABLE IF EXISTS temp__node_props_cache; > + > +-- STMT_CACHE_NODE_PROPS_RECURSIVE > +CREATE TEMPORARY TABLE temp__node_props_cache AS > + SELECT local_relpath, kind, properties FROM nodes_current > + WHERE wc_id = ?1 > + AND (?2 = '' OR local_relpath = ?2 OR local_relpath LIKE ?2 || '/%') > + AND local_relpath NOT IN ( > + SELECT local_relpath FROM actual_node WHERE wc_id = ?1) > + AND (presence = 'normal' OR presence = 'incomplete'); > +CREATE UNIQUE INDEX temp__node_props_cache_unique > + ON temp__node_props_cache (local_relpath); > + > +-- STMT_CACHE_ACTUAL_PROPS_RECURSIVE > +INSERT INTO temp__node_props_cache (local_relpath, kind, properties) > + SELECT A.local_relpath, N.kind, A.properties > + FROM actual_node AS A JOIN nodes_current AS N > + ON A.wc_id = N.wc_id AND A.local_relpath = N.local_relpath > + AND (N.presence = 'normal' OR N.presence = 'incomplete') > + WHERE A.wc_id = ?1 > + AND (?2 = '' OR A.local_relpath = ?2 OR A.local_relpath LIKE ?2 || '/%') > + AND A.local_relpath NOT IN > + (SELECT local_relpath FROM temp__node_props_cache); > + > +-- STMT_CACHE_NODE_PROPS_OF_CHILDREN > +CREATE TEMPORARY TABLE temp__node_props_cache AS > + SELECT local_relpath, kind, properties FROM nodes_current > + WHERE wc_id = ?1 > + AND (local_relpath = ?2 OR parent_relpath = ?2) > + AND local_relpath NOT IN ( > + SELECT local_relpath FROM actual_node WHERE wc_id = ?1) > + AND (presence = 'normal' OR presence = 'incomplete'); > +CREATE UNIQUE INDEX temp__node_props_cache_unique > + ON temp__node_props_cache (local_relpath); > + > +-- STMT_CACHE_ACTUAL_PROPS_OF_CHILDREN > +INSERT INTO temp__node_props_cache (local_relpath, kind, properties) > + SELECT A.local_relpath, N.kind, A.properties > + FROM actual_node AS A JOIN nodes_current AS N > + ON A.wc_id = N.wc_id AND A.local_relpath = N.local_relpath > + AND (N.presence = 'normal' OR N.presence = 'incomplete') > + WHERE A.wc_id = ?1 > + AND (A.local_relpath = ?2 OR A.parent_relpath = ?2) > + AND A.local_relpath NOT IN > + (SELECT local_relpath FROM temp__node_props_cache); > + > +-- STMT_SELECT_RELEVANT_PROPS_FROM_CACHE > +SELECT local_relpath, kind, properties FROM temp__node_props_cache > +ORDER BY local_relpath; > + > + > /* ------------------------------------------------------------------------- > */ > > /* Grab all the statements related to the schema. */ > Index: subversion/libsvn_wc/wc-metadata.sql > =================================================================== > --- subversion/libsvn_wc/wc-metadata.sql (revision 1070853) > +++ subversion/libsvn_wc/wc-metadata.sql (working copy) > @@ -483,6 +483,16 @@ CREATE TABLE NODES ( > > CREATE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath, op_depth); > > +/* Many queries have to filter the nodes table to pick only that version > + of each node with the highest (most "current") op_depth. This view > + does the heavy lifting for such queries. */ > +CREATE VIEW NODES_CURRENT AS > + SELECT * FROM nodes > + JOIN (SELECT wc_id, local_relpath, MAX(op_depth) AS op_depth FROM nodes > + GROUP BY wc_id, local_relpath) AS filter > + ON nodes.wc_id = filter.wc_id > + AND nodes.local_relpath = filter.local_relpath > + AND nodes.op_depth = filter.op_depth; > > -- STMT_CREATE_NODES_TRIGGERS > > @@ -595,7 +605,22 @@ UPDATE pristine SET refcount = > > PRAGMA user_version = 24; > > +/* ------------------------------------------------------------------------- > */ > > +/* Format 25 introduces the NODES_CURRENT view. */ > + > +-- STMT_UPGRADE_TO_25 > +DROP VIEW IF EXISTS NODES_CURRENT; > +CREATE VIEW NODES_CURRENT AS > + SELECT * FROM nodes > + JOIN (SELECT wc_id, local_relpath, MAX(op_depth) AS op_depth FROM nodes > + GROUP BY wc_id, local_relpath) AS filter > + ON nodes.wc_id = filter.wc_id > + AND nodes.local_relpath = filter.local_relpath > + AND nodes.op_depth = filter.op_depth; > + > +PRAGMA user_version = 25; > + > /* ------------------------------------------------------------------------- > */ > > /* Format YYY introduces new handling for conflict information. */ > Index: subversion/libsvn_wc/wc_db.c > =================================================================== > --- subversion/libsvn_wc/wc_db.c (revision 1070853) > +++ subversion/libsvn_wc/wc_db.c (working copy) > @@ -5175,166 +5175,144 @@ svn_wc__db_read_props(apr_hash_t **props, > return SVN_NO_ERROR; > } > > -/* Parse a node's PROP_DATA (which is PROP_DATA_LEN bytes long) > - * into a hash table keyed by property names and containing property values. > - * > - * If parsing succeeds, and the set of properties is not empty, > - * add the hash table to PROPS_PER_CHILD, keyed by the absolute path > - * of the node CHILD_RELPATH within the working copy at WCROOT_ABSPATH. > - * > - * If the set of properties is empty, and PROPS_PER_CHILD already contains > - * an entry for the node, clear the entry. This facilitates overriding > - * properties retrieved from the NODES table with empty sets of properties > - * stored in the ACTUAL_NODE table. */ > +/* Call RECEIVER_FUNC, passing RECEIVER_BATON, an absolute path, and > + * a hash table mapping <tt>char *</tt> names onto svn_string_t * > + * values for any properties of immediate or recursive child nodes of > + * LOCAL_ABSPATH, the actual query being determined by STMT_IDX. > + * If FILES_ONLY is true, only report properties for file child nodes. > + * Check for cancellation between calls of RECEIVER_FUNC. > + */ > +typedef struct cache_props_baton_t > +{ > + int stmt_node_props_ndx; > + int stmt_actual_props_ndx; > + apr_int64_t wc_id; > + const char *local_relpath; > + svn_cancel_func_t cancel_func; > + void *cancel_baton; > +} cache_props_baton_t; > + > static svn_error_t * > -maybe_add_child_props(apr_hash_t *props_per_child, > - const char *prop_data, > - apr_size_t prop_data_len, > - const char *child_relpath, > - const char *wcroot_abspath, > - apr_pool_t *result_pool, > +cache_props_recursive(void *cb_baton, > + svn_sqlite__db_t *db, > apr_pool_t *scratch_pool) > { > - const char *child_abspath; > - apr_hash_t *props; > - svn_skel_t *prop_skel; > + cache_props_baton_t *baton = cb_baton; > + svn_sqlite__stmt_t *stmt; > > - prop_skel = svn_skel__parse(prop_data, prop_data_len, scratch_pool); > - if (svn_skel__list_length(prop_skel) == 0) > - return SVN_NO_ERROR; > + SVN_ERR(svn_sqlite__get_statement(&stmt, db, baton->stmt_node_props_ndx)); > + SVN_ERR(svn_sqlite__bindf(stmt, "is", baton->wc_id, baton->local_relpath)); > + SVN_ERR(svn_sqlite__step_done(stmt)); > > - child_abspath = svn_dirent_join(wcroot_abspath, child_relpath, > result_pool); > - SVN_ERR(svn_skel__parse_proplist(&props, prop_skel, result_pool)); > - if (apr_hash_count(props)) > - apr_hash_set(props_per_child, child_abspath, APR_HASH_KEY_STRING, props); > - else > - apr_hash_set(props_per_child, child_abspath, APR_HASH_KEY_STRING, NULL); > + if (baton->cancel_func) > + SVN_ERR(baton->cancel_func(baton->cancel_baton)); > + > + SVN_ERR(svn_sqlite__get_statement(&stmt, db, > baton->stmt_actual_props_ndx)); > + SVN_ERR(svn_sqlite__bindf(stmt, "is", baton->wc_id, baton->local_relpath)); > + SVN_ERR(svn_sqlite__step_done(stmt)); > > return SVN_NO_ERROR; > } > > -/* Call RECEIVER_FUNC, passing RECEIVER_BATON, an absolute path, and > - * a hash table mapping <tt>char *</tt> names onto svn_string_t * > - * values for any properties of immediate child nodes of LOCAL_ABSPATH. > - * If FILES_ONLY is true, only report properties for file child nodes. > - */ > static svn_error_t * > -read_props_of_children(svn_wc__db_t *db, > - const char *local_abspath, > - svn_boolean_t files_only, > - svn_wc__proplist_receiver_t receiver_func, > - void *receiver_baton, > - apr_pool_t *scratch_pool) > +read_props_recursive(svn_wc__db_t *db, > + const char *local_abspath, > + svn_boolean_t files_only, > + svn_boolean_t immediates_only, > + svn_wc__proplist_receiver_t receiver_func, > + void *receiver_baton, > + svn_cancel_func_t cancel_func, > + void *cancel_baton, > + apr_pool_t *scratch_pool) > { > svn_wc__db_wcroot_t *wcroot; > - const char *local_relpath; > - const char *prev_child_relpath; > svn_sqlite__stmt_t *stmt; > + cache_props_baton_t baton; > svn_boolean_t have_row; > - apr_hash_t *props_per_child; > - apr_hash_t *files; > - apr_hash_t *not_present; > - apr_hash_index_t *hi; > + int row_number; > apr_pool_t *iterpool; > > SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); > SVN_ERR_ASSERT(receiver_func); > > - SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, > - local_abspath, > - svn_sqlite__mode_readwrite, > - scratch_pool, scratch_pool)); > + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, > &baton.local_relpath, > + db, local_abspath, > + svn_sqlite__mode_readwrite, > + scratch_pool, scratch_pool)); > VERIFY_USABLE_WCROOT(wcroot); > > - props_per_child = apr_hash_make(scratch_pool); > - not_present = apr_hash_make(scratch_pool); > - if (files_only) > - files = apr_hash_make(scratch_pool); > + SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, > + STMT_CLEAR_NODE_PROPS_CACHE)); > + > + if (immediates_only) > + { > + baton.stmt_node_props_ndx = STMT_CACHE_NODE_PROPS_OF_CHILDREN; > + baton.stmt_actual_props_ndx = STMT_CACHE_ACTUAL_PROPS_OF_CHILDREN; > + } > else > - files = NULL; > + { > + baton.stmt_node_props_ndx = STMT_CACHE_NODE_PROPS_RECURSIVE; > + baton.stmt_actual_props_ndx = STMT_CACHE_ACTUAL_PROPS_RECURSIVE; > + } > + baton.wc_id = wcroot->wc_id; > + baton.cancel_func = cancel_func; > + baton.cancel_baton = cancel_baton; > + SVN_ERR(svn_sqlite__with_transaction(wcroot->sdb, > + cache_props_recursive, > + &baton, scratch_pool)); > > + iterpool = svn_pool_create(scratch_pool); > + > SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, > - STMT_SELECT_NODE_PROPS_OF_CHILDREN)); > - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); > + STMT_SELECT_RELEVANT_PROPS_FROM_CACHE)); > SVN_ERR(svn_sqlite__step(&have_row, stmt)); > - prev_child_relpath = NULL; > - while (have_row) > + for (row_number = 0; have_row; ++row_number) > { > - svn_wc__db_status_t child_presence; > - const char *child_relpath; > const char *prop_data; > apr_size_t len; > > - child_relpath = svn_sqlite__column_text(stmt, 2, scratch_pool); > - > - if (prev_child_relpath && strcmp(child_relpath, prev_child_relpath) == > 0) > + if (files_only && row_number > 0) > { > - /* Same child, but lower op_depth -- skip this row. */ > - SVN_ERR(svn_sqlite__step(&have_row, stmt)); > - continue; > - } > - prev_child_relpath = child_relpath; > + svn_wc__db_kind_t child_kind; > > - child_presence = svn_sqlite__column_token(stmt, 1, presence_map); > - if (child_presence != svn_wc__db_status_normal) > - { > - apr_hash_set(not_present, child_relpath, APR_HASH_KEY_STRING, ""); > - SVN_ERR(svn_sqlite__step(&have_row, stmt)); > - continue; > - } > - > - prop_data = svn_sqlite__column_blob(stmt, 0, &len, NULL); > - if (prop_data) > - { > - if (files_only) > + child_kind = svn_sqlite__column_token(stmt, 1, kind_map); > + if (child_kind != svn_wc__db_kind_file && > + child_kind != svn_wc__db_kind_symlink) > { > - svn_wc__db_kind_t child_kind; > - > - child_kind = svn_sqlite__column_token(stmt, 3, kind_map); > - if (child_kind != svn_wc__db_kind_file && > - child_kind != svn_wc__db_kind_symlink) > - { > - SVN_ERR(svn_sqlite__step(&have_row, stmt)); > - continue; > - } > - apr_hash_set(files, child_relpath, APR_HASH_KEY_STRING, NULL); > + SVN_ERR(svn_sqlite__step(&have_row, stmt)); > + continue; > } > - > - SVN_ERR(maybe_add_child_props(props_per_child, prop_data, len, > - child_relpath, wcroot->abspath, > - scratch_pool, scratch_pool)); > } > > - SVN_ERR(svn_sqlite__step(&have_row, stmt)); > - } > + svn_pool_clear(iterpool); > > - SVN_ERR(svn_sqlite__reset(stmt)); > + /* see if someone wants to cancel this operation. */ > + if (cancel_func) > + SVN_ERR(cancel_func(cancel_baton)); > > - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, > - STMT_SELECT_ACTUAL_PROPS_OF_CHILDREN)); > - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); > - SVN_ERR(svn_sqlite__step(&have_row, stmt)); > - while (have_row) > - { > - const char *child_relpath; > - const char *prop_data; > - apr_size_t len; > - > - prop_data = svn_sqlite__column_blob(stmt, 0, &len, NULL); > + prop_data = svn_sqlite__column_blob(stmt, 2, &len, NULL); > if (prop_data) > { > - child_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool); > + svn_skel_t *prop_skel; > > - if (apr_hash_get(not_present, child_relpath, APR_HASH_KEY_STRING) > || > - (files_only && > - apr_hash_get(files, child_relpath, APR_HASH_KEY_STRING) == > NULL)) > + prop_skel = svn_skel__parse(prop_data, len, iterpool); > + if (svn_skel__list_length(prop_skel) != 0) > { > - SVN_ERR(svn_sqlite__step(&have_row, stmt)); > - continue; > + const char *child_relpath; > + const char *child_abspath; > + apr_hash_t *props; > + > + child_relpath = svn_sqlite__column_text(stmt, 0, NULL); > + child_abspath = svn_dirent_join(wcroot->abspath, > + child_relpath, iterpool); > + SVN_ERR(svn_skel__parse_proplist(&props, prop_skel, iterpool)); > + if (receiver_func && apr_hash_count(props) != 0) > + { > + SVN_ERR((*receiver_func)(receiver_baton, > + child_abspath, props, > + iterpool)); > + } > } > - SVN_ERR(maybe_add_child_props(props_per_child, prop_data, len, > - child_relpath, wcroot->abspath, > - scratch_pool, scratch_pool)); > } > > SVN_ERR(svn_sqlite__step(&have_row, stmt)); > @@ -5342,22 +5320,10 @@ static svn_error_t * > > SVN_ERR(svn_sqlite__reset(stmt)); > > - iterpool = svn_pool_create(scratch_pool); > - for (hi = apr_hash_first(scratch_pool, props_per_child); > - hi; > - hi = apr_hash_next(hi)) > - { > - const char *child_abspath = svn__apr_hash_index_key(hi); > - apr_hash_t *child_props = svn__apr_hash_index_val(hi); > - > - svn_pool_clear(iterpool); > - > - if (child_props) > - SVN_ERR((*receiver_func)(receiver_baton, child_abspath, child_props, > - iterpool)); > - } > svn_pool_destroy(iterpool); > > + SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, > + STMT_CLEAR_NODE_PROPS_CACHE)); > return SVN_NO_ERROR; > } > > @@ -5366,11 +5332,15 @@ svn_wc__db_read_props_of_files(svn_wc__db_t *db, > const char *local_abspath, > svn_wc__proplist_receiver_t receiver_func, > void *receiver_baton, > + svn_cancel_func_t cancel_func, > + void *cancel_baton, > apr_pool_t *scratch_pool) > { > - return svn_error_return(read_props_of_children(db, local_abspath, TRUE, > - receiver_func, > receiver_baton, > - scratch_pool)); > + SVN_ERR(read_props_recursive(db, local_abspath, TRUE, TRUE, > + receiver_func, receiver_baton, > + cancel_func, cancel_baton, > + scratch_pool)); > + return SVN_NO_ERROR; > } > > svn_error_t * > @@ -5378,13 +5348,32 @@ svn_wc__db_read_props_of_immediates(svn_wc__db_t * > const char *local_abspath, > svn_wc__proplist_receiver_t receiver_func, > void *receiver_baton, > + svn_cancel_func_t cancel_func, > + void *cancel_baton, > apr_pool_t *scratch_pool) > { > - return svn_error_return(read_props_of_children(db, local_abspath, FALSE, > - receiver_func, > receiver_baton, > - scratch_pool)); > + SVN_ERR(read_props_recursive(db, local_abspath, FALSE, TRUE, > + receiver_func, receiver_baton, > + cancel_func, cancel_baton, > + scratch_pool)); > + return SVN_NO_ERROR; > } > > +svn_error_t * > +svn_wc__db_read_props_recursive(svn_wc__db_t *db, > + const char *local_abspath, > + svn_wc__proplist_receiver_t receiver_func, > + void *receiver_baton, > + svn_cancel_func_t cancel_func, > + void *cancel_baton, > + apr_pool_t *scratch_pool) > +{ > + SVN_ERR(read_props_recursive(db, local_abspath, FALSE, FALSE, > + receiver_func, receiver_baton, > + cancel_func, cancel_baton, > + scratch_pool)); > + return SVN_NO_ERROR; > +} > > static svn_error_t * > db_read_pristine_props(apr_hash_t **props, > Index: subversion/libsvn_wc/wc_db.h > =================================================================== > --- subversion/libsvn_wc/wc_db.h (revision 1070853) > +++ subversion/libsvn_wc/wc_db.h (working copy) > @@ -1588,9 +1588,10 @@ svn_wc__db_read_props(apr_hash_t **props, > svn_error_t * > svn_wc__db_read_props_of_files(svn_wc__db_t *db, > const char *local_abspath, > - svn_wc__proplist_receiver_t > - receiver_func, > + svn_wc__proplist_receiver_t receiver_func, > void *receiver_baton, > + svn_cancel_func_t cancel_func, > + void *cancel_baton, > apr_pool_t *scratch_pool); > > /* Call RECEIVER_FUNC, passing RECEIVER_BATON, an absolute path, and > @@ -1600,11 +1601,25 @@ svn_wc__db_read_props_of_files(svn_wc__db_t *db, > svn_error_t * > svn_wc__db_read_props_of_immediates(svn_wc__db_t *db, > const char *local_abspath, > - svn_wc__proplist_receiver_t > - receiver_func, > + svn_wc__proplist_receiver_t > receiver_func, > void *receiver_baton, > + svn_cancel_func_t cancel_func, > + void *cancel_baton, > apr_pool_t *scratch_pool); > > +/* Call RECEIVER_FUNC, passing RECEIVER_BATON, an absolute path, and > + * a hash table mapping <tt>char *</tt> names onto svn_string_t * > + * values for any properties of all (recursive) child nodes of LOCAL_ABSPATH. > + */ > +svn_error_t * > +svn_wc__db_read_props_recursive(svn_wc__db_t *db, > + const char *local_abspath, > + svn_wc__proplist_receiver_t receiver_func, > + void *receiver_baton, > + svn_cancel_func_t cancel_func, > + void *cancel_baton, > + apr_pool_t *scratch_pool); > + > /* Set *PROPS to the properties of the node LOCAL_ABSPATH in the WORKING > tree (looking through to the BASE tree as required). > > Index: subversion/libsvn_wc/upgrade.c > =================================================================== > --- subversion/libsvn_wc/upgrade.c (revision 1070853) > +++ subversion/libsvn_wc/upgrade.c (working copy) > @@ -1137,7 +1137,14 @@ bump_to_24(void *baton, svn_sqlite__db_t *sdb, apr > return SVN_NO_ERROR; > } > > +static svn_error_t * > +bump_to_25(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) > +{ > + SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_25)); > + return SVN_NO_ERROR; > +} > > + > struct upgrade_data_t { > svn_sqlite__db_t *sdb; > const char *root_abspath; > @@ -1402,6 +1409,12 @@ svn_wc__upgrade_sdb(int *result_format, > *result_format = 24; > /* FALLTHROUGH */ > > + case 24: > + SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_25, &bb, > + scratch_pool)); > + *result_format = 25; > + /* FALLTHROUGH */ > + > /* ### future bumps go here. */ > #if 0 > case XXX-1: >