[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: Hyrum K Wright <hyrum_at_hyrumwright.org>
Date: Tue, 15 Feb 2011 15:35:43 +0000

On Tue, Feb 15, 2011 at 2:53 PM, Stefan Sperling <stsp_at_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:
>
Received on 2011-02-15 16:36:26 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.