[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: SQLite and callbacks

From: Stefan Sperling <stsp_at_elego.de>
Date: Tue, 15 Feb 2011 15:53:36 +0100

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?

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:
Received on 2011-02-15 15:54:24 CET

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.