You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by sb...@apache.org on 2012/06/15 11:11:59 UTC

svn commit: r1350545 - in /subversion/trunk/subversion: include/svn_repos.h libsvn_repos/deprecated.c libsvn_repos/load-fs-vtable.c libsvn_repos/load.c svndumpfilter/main.c svnrdump/load_editor.c

Author: sbutler
Date: Fri Jun 15 09:11:58 2012
New Revision: 1350545

URL: http://svn.apache.org/viewvc?rev=1350545&view=rev
Log:
Prepare to handle dump format v3 in svndumpfilter.

This revision sets up the boilerplate for backward compatibility.
Later revisions will add a new parser callback for the version number,
and a new option to allow treating text-deltas as text (instead of
applying them immediately).

* subversion/include/svn_repos.h
  (svn_repos_parse_fns3_t): New struct.  Tweak the callback declarations
   to reflect the usual ordering in dump files.
  (svn_repos_parse_dumpstream3): New API using the new struct.  No 
   real changes yet.
  (svn_repos_get_fs_build_parser4): Modify this new-in-1.8 function to
   use the new struct.
  (svn_repos_parse_fns2_t,
   svn_repos_parse_dumpstream2,
   svn_repos_get_fs_build_parser3): Deprecate.
  (svn_repos_get_fs_build_parser2): Move below below the newly-
   deprecated svn_repos_parse_fns2_t declaration.

* subversion/svndumpfilter/main.c
  (filtering_vtable,
   do_filter): Use the new API.

* subversion/svnrdump/load_editor.c
  (svn_rdump__load_dumpstream): Use the new API.

* subversion/libsvn_repos/deprecated.c
  (fns2_from_fns3,
   fns3_from_fns2): New functions.
  (svn_repos_get_fs_build_parser3): Use the new API.

* subversion/libsvn_repos/load.c
  (parse_property_block,
   parse_text_block,
   svn_repos_parse_dumpstream3): Use the new API.

* subversion/libsvn_repos/load-fs-vtable.c
  (svn_repos_get_fs_build_parser4,
   svn_repos_load_fs4): Use the new API.

Modified:
    subversion/trunk/subversion/include/svn_repos.h
    subversion/trunk/subversion/libsvn_repos/deprecated.c
    subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c
    subversion/trunk/subversion/libsvn_repos/load.c
    subversion/trunk/subversion/svndumpfilter/main.c
    subversion/trunk/subversion/svnrdump/load_editor.c

Modified: subversion/trunk/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_repos.h?rev=1350545&r1=1350544&r2=1350545&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_repos.h (original)
+++ subversion/trunk/subversion/include/svn_repos.h Fri Jun 15 09:11:58 2012
@@ -2705,12 +2705,21 @@ svn_repos_load_fs(svn_repos_t *repos,
 
 
 /**
- * A vtable that is driven by svn_repos_parse_dumpstream2().
+ * A vtable that is driven by svn_repos_parse_dumpstream3().
+ * ### TODO: Add a new callback for the dumpfile version header.
  *
- * @since New in 1.1.
+ * @since New in 1.8.
  */
-typedef struct svn_repos_parse_fns2_t
+typedef struct svn_repos_parse_fns3_t
 {
+  /** The parser has discovered a new uuid record within the parsing
+   * session represented by @a parse_baton.  The uuid's value is
+   * @a uuid, and it is allocated in @a pool.
+   */
+  svn_error_t *(*uuid_record)(const char *uuid,
+                              void *parse_baton,
+                              apr_pool_t *pool);
+
   /** The parser has discovered a new revision record within the
    * parsing session represented by @a parse_baton.  All the headers are
    * placed in @a headers (allocated in @a pool), which maps <tt>const
@@ -2723,14 +2732,6 @@ typedef struct svn_repos_parse_fns2_t
                                       void *parse_baton,
                                       apr_pool_t *pool);
 
-  /** The parser has discovered a new uuid record within the parsing
-   * session represented by @a parse_baton.  The uuid's value is
-   * @a uuid, and it is allocated in @a pool.
-   */
-  svn_error_t *(*uuid_record)(const char *uuid,
-                              void *parse_baton,
-                              apr_pool_t *pool);
-
   /** The parser has discovered a new node record within the current
    * revision represented by @a revision_baton.  All the headers are
    * placed in @a headers (as with @c new_revision_record), allocated in
@@ -2793,22 +2794,26 @@ typedef struct svn_repos_parse_fns2_t
    */
   svn_error_t *(*close_revision)(void *revision_baton);
 
-} svn_repos_parse_fns2_t;
-
-/** @deprecated Provided for backward compatibility with the 1.2 API. */
-typedef svn_repos_parse_fns2_t svn_repos_parser_fns2_t;
+} svn_repos_parse_fns3_t;
 
 
 /**
  * Read and parse dumpfile-formatted @a stream, calling callbacks in
  * @a parse_fns/@a parse_baton, and using @a pool for allocations.
  *
+ * ### TODO: Add a boolean option to treat text-deltas as text, because
+ * a dump-filtering tool shouldn't apply the deltas.
+ *
  * If @a cancel_func is not @c NULL, it is called periodically with
  * @a cancel_baton as argument to see if the client wishes to cancel
  * the dump.
  *
  * This parser has built-in knowledge of the dumpfile format, but only
- * in a general sense:
+ * in a limited sense:
+ *
+ *    * ### TODO: it recognizes the "magic" format-version header.
+ *
+ *    * it recognizes the UUID header.
  *
  *    * it recognizes revision and node records by looking for either
  *      a REVISION_NUMBER or NODE_PATH headers.
@@ -2822,11 +2827,11 @@ typedef svn_repos_parse_fns2_t svn_repos
  * This is enough knowledge to make it easy on vtable implementors,
  * but still allow expansion of the format:  most headers are ignored.
  *
- * @since New in 1.1.
+ * @since New in 1.8.
  */
 svn_error_t *
-svn_repos_parse_dumpstream2(svn_stream_t *stream,
-                            const svn_repos_parse_fns2_t *parse_fns,
+svn_repos_parse_dumpstream3(svn_stream_t *stream,
+                            const svn_repos_parse_fns3_t *parse_fns,
                             void *parse_baton,
                             svn_cancel_func_t cancel_func,
                             void *cancel_baton,
@@ -2868,7 +2873,7 @@ svn_repos_parse_dumpstream2(svn_stream_t
  * @since New in 1.8.
  */
 svn_error_t *
-svn_repos_get_fs_build_parser4(const svn_repos_parse_fns2_t **parser,
+svn_repos_get_fs_build_parser4(const svn_repos_parse_fns3_t **parser,
                                void **parse_baton,
                                svn_repos_t *repos,
                                svn_revnum_t start_rev,
@@ -2881,44 +2886,59 @@ svn_repos_get_fs_build_parser4(const svn
                                void *notify_baton,
                                apr_pool_t *pool);
 
+
 /**
- * Similar to svn_repos_get_fs_build_parser4(), but with @a start_rev
- * and @a end_rev always passed as #SVN_INVALID_REVNUM.
+ * A vtable that is driven by svn_repos_parse_dumpstream2().
+ * Similar to #svn_repos_parse_fns3_t except that it lacks
+ * the delete_node_property and apply_textdelta callbacks.
  *
  * @deprecated Provided for backward compatibility with the 1.7 API.
- * @since New in 1.7.
  */
-SVN_DEPRECATED
-svn_error_t *
-svn_repos_get_fs_build_parser3(const svn_repos_parse_fns2_t **parser,
-                               void **parse_baton,
-                               svn_repos_t *repos,
-                               svn_boolean_t use_history,
-                               svn_boolean_t validate_props,
-                               enum svn_repos_load_uuid uuid_action,
-                               const char *parent_dir,
-                               svn_repos_notify_func_t notify_func,
-                               void *notify_baton,
-                               apr_pool_t *pool);
+typedef struct svn_repos_parse_fns2_t
+{
+  /** Same as #svn_repos_parse_fns3_t.new_revision_record. */
+  svn_error_t *(*new_revision_record)(void **revision_baton,
+                                      apr_hash_t *headers,
+                                      void *parse_baton,
+                                      apr_pool_t *pool);
+  /** Same as #svn_repos_parse_fns3_t.uuid_record. */
+  svn_error_t *(*uuid_record)(const char *uuid,
+                              void *parse_baton,
+                              apr_pool_t *pool);
+  /** Same as #svn_repos_parse_fns3_t.new_node_record. */
+  svn_error_t *(*new_node_record)(void **node_baton,
+                                  apr_hash_t *headers,
+                                  void *revision_baton,
+                                  apr_pool_t *pool);
+  /** Same as #svn_repos_parse_fns3_t.set_revision_property. */
+  svn_error_t *(*set_revision_property)(void *revision_baton,
+                                        const char *name,
+                                        const svn_string_t *value);
+  /** Same as #svn_repos_parse_fns3_t.set_node_property. */
+  svn_error_t *(*set_node_property)(void *node_baton,
+                                    const char *name,
+                                    const svn_string_t *value);
+  /** Same as #svn_repos_parse_fns3_t.delete_node_property. */
+  svn_error_t *(*delete_node_property)(void *node_baton,
+                                       const char *name);
+  /** Same as #svn_repos_parse_fns3_t.remove_node_props. */
+  svn_error_t *(*remove_node_props)(void *node_baton);
+  /** Same as #svn_repos_parse_fns3_t.set_fulltext. */
+  svn_error_t *(*set_fulltext)(svn_stream_t **stream,
+                               void *node_baton);
+  /** Same as #svn_repos_parse_fns3_t.apply_textdelta. */
+  svn_error_t *(*apply_textdelta)(svn_txdelta_window_handler_t *handler,
+                                  void **handler_baton,
+                                  void *node_baton);
+  /** Same as #svn_repos_parse_fns3_t.close_node. */
+  svn_error_t *(*close_node)(void *node_baton);
+  /** Same as #svn_repos_parse_fns3_t.close_revision. */
+  svn_error_t *(*close_revision)(void *revision_baton);
+} svn_repos_parse_fns2_t;
+
+/** @deprecated Provided for backward compatibility with the 1.7 API. */
+typedef svn_repos_parse_fns2_t svn_repos_parser_fns2_t;
 
-/**
- * Similar to svn_repos_get_fs_build_parser3(), but with @a outstream
- * in place if a #svn_repos_notify_func_t and baton and with
- * @a validate_props always FALSE.
- *
- * @since New in 1.1.
- * @deprecated Provided for backward compatibility with the 1.6 API.
- */
-SVN_DEPRECATED
-svn_error_t *
-svn_repos_get_fs_build_parser2(const svn_repos_parse_fns2_t **parser,
-                               void **parse_baton,
-                               svn_repos_t *repos,
-                               svn_boolean_t use_history,
-                               enum svn_repos_load_uuid uuid_action,
-                               svn_stream_t *outstream,
-                               const char *parent_dir,
-                               apr_pool_t *pool);
 
 /**
  * A vtable that is driven by svn_repos_parse_dumpstream().
@@ -2964,6 +2984,21 @@ typedef struct svn_repos_parse_fns_t
 
 
 /**
+ * Similar to svn_repos_parse_dumpstream3(), but uses the more limited
+ * #svn_repos_parser_fns2_t vtable type.
+ *
+ * @deprecated Provided for backward compatibility with the 1.7 API.
+ */
+SVN_DEPRECATED
+svn_error_t *
+svn_repos_parse_dumpstream2(svn_stream_t *stream,
+                            const svn_repos_parser_fns2_t *parse_fns,
+                            void *parse_baton,
+                            svn_cancel_func_t cancel_func,
+                            void *cancel_baton,
+                            apr_pool_t *pool);
+
+/**
  * Similar to svn_repos_parse_dumpstream2(), but uses the more limited
  * #svn_repos_parser_fns_t vtable type.
  *
@@ -2978,6 +3013,45 @@ svn_repos_parse_dumpstream(svn_stream_t 
                            void *cancel_baton,
                            apr_pool_t *pool);
 
+/**
+ * Similar to svn_repos_get_fs_build_parser4(), but with @a start_rev
+ * and @a end_rev always passed as #SVN_INVALID_REVNUM, and yielding
+ * the more limited svn_repos_parse_fns2_t.
+ *
+ * @since New in 1.7.
+ * @deprecated Provided for backward compatibility with the 1.7 API.
+ */
+SVN_DEPRECATED
+svn_error_t *
+svn_repos_get_fs_build_parser3(const svn_repos_parse_fns2_t **parser,
+                               void **parse_baton,
+                               svn_repos_t *repos,
+                               svn_boolean_t use_history,
+                               svn_boolean_t validate_props,
+                               enum svn_repos_load_uuid uuid_action,
+                               const char *parent_dir,
+                               svn_repos_notify_func_t notify_func,
+                               void *notify_baton,
+                               apr_pool_t *pool);
+
+/**
+ * Similar to svn_repos_get_fs_build_parser3(), but with @a outstream
+ * in place if a #svn_repos_notify_func_t and baton and with
+ * @a validate_props always FALSE.
+ *
+ * @since New in 1.1.
+ * @deprecated Provided for backward compatibility with the 1.6 API.
+ */
+SVN_DEPRECATED
+svn_error_t *
+svn_repos_get_fs_build_parser2(const svn_repos_parse_fns2_t **parser,
+                               void **parse_baton,
+                               svn_repos_t *repos,
+                               svn_boolean_t use_history,
+                               enum svn_repos_load_uuid uuid_action,
+                               svn_stream_t *outstream,
+                               const char *parent_dir,
+                               apr_pool_t *pool);
 
 /**
  * Similar to svn_repos_get_fs_build_parser2(), but yields the more

Modified: subversion/trunk/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/deprecated.c?rev=1350545&r1=1350544&r2=1350545&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/trunk/subversion/libsvn_repos/deprecated.c Fri Jun 15 09:11:58 2012
@@ -775,6 +775,27 @@ fns_from_fns2(const svn_repos_parse_fns2
   return fns;
 }
 
+static svn_repos_parser_fns2_t *
+fns2_from_fns3(const svn_repos_parse_fns3_t *fns3,
+              apr_pool_t *pool)
+{
+  svn_repos_parser_fns2_t *fns2;
+
+  fns2 = apr_palloc(pool, sizeof(*fns2));
+  fns2->new_revision_record = fns3->new_revision_record;
+  fns2->uuid_record = fns3->uuid_record;
+  fns2->new_node_record = fns3->new_node_record;
+  fns2->set_revision_property = fns3->set_revision_property;
+  fns2->set_node_property = fns3->set_node_property;
+  fns2->remove_node_props = fns3->remove_node_props;
+  fns2->set_fulltext = fns3->set_fulltext;
+  fns2->close_node = fns3->close_node;
+  fns2->close_revision = fns3->close_revision;
+  fns2->delete_node_property = fns3->delete_node_property;
+  fns2->apply_textdelta = fns3->apply_textdelta;
+  return fns2;
+}
+
 static svn_repos_parse_fns2_t *
 fns2_from_fns(const svn_repos_parser_fns_t *fns,
               apr_pool_t *pool)
@@ -796,6 +817,41 @@ fns2_from_fns(const svn_repos_parser_fns
   return fns2;
 }
 
+static svn_repos_parse_fns3_t *
+fns3_from_fns2(const svn_repos_parser_fns2_t *fns2,
+               apr_pool_t *pool)
+{
+  svn_repos_parse_fns3_t *fns3;
+
+  fns3 = apr_palloc(pool, sizeof(*fns3));
+  fns3->uuid_record = fns2->uuid_record;
+  fns3->new_revision_record = fns2->new_revision_record;
+  fns3->new_node_record = fns2->new_node_record;
+  fns3->set_revision_property = fns2->set_revision_property;
+  fns3->set_node_property = fns2->set_node_property;
+  fns3->remove_node_props = fns2->remove_node_props;
+  fns3->set_fulltext = fns2->set_fulltext;
+  fns3->close_node = fns2->close_node;
+  fns3->close_revision = fns2->close_revision;
+  fns3->delete_node_property = fns2->delete_node_property;
+  fns3->apply_textdelta = fns2->apply_textdelta;
+  return fns3;
+}
+
+svn_error_t *
+svn_repos_parse_dumpstream2(svn_stream_t *stream,
+                            const svn_repos_parser_fns2_t *parse_fns,
+                            void *parse_baton,
+                            svn_cancel_func_t cancel_func,
+                            void *cancel_baton,
+                            apr_pool_t *pool)
+{
+  svn_repos_parse_fns3_t *fns3 = fns3_from_fns2(parse_fns, pool);
+
+  return svn_repos_parse_dumpstream3(stream, fns3, parse_baton,
+                                     cancel_func, cancel_baton, pool);
+}
+
 svn_error_t *
 svn_repos_parse_dumpstream(svn_stream_t *stream,
                            const svn_repos_parser_fns_t *parse_fns,
@@ -837,11 +893,17 @@ svn_repos_get_fs_build_parser3(const svn
                                void *notify_baton,
                                apr_pool_t *pool)
 {
-  return svn_repos_get_fs_build_parser4(callbacks, parse_baton, repos,
-                                        SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
-                                        use_history, validate_props,
-                                        uuid_action, parent_dir,
-                                        notify_func, notify_baton, pool);
+  const svn_repos_parse_fns3_t *fns3;
+
+  SVN_ERR(svn_repos_get_fs_build_parser4(&fns3, parse_baton, repos,
+                                         SVN_INVALID_REVNUM,
+                                         SVN_INVALID_REVNUM,
+                                         use_history, validate_props,
+                                         uuid_action, parent_dir,
+                                         notify_func, notify_baton, pool));
+
+  *callbacks = fns2_from_fns3(fns3, pool);
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c?rev=1350545&r1=1350544&r2=1350545&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c Fri Jun 15 09:11:58 2012
@@ -1016,7 +1016,7 @@ close_revision(void *baton)
 
 
 svn_error_t *
-svn_repos_get_fs_build_parser4(const svn_repos_parse_fns2_t **callbacks,
+svn_repos_get_fs_build_parser4(const svn_repos_parse_fns3_t **callbacks,
                                void **parse_baton,
                                svn_repos_t *repos,
                                svn_revnum_t start_rev,
@@ -1029,7 +1029,7 @@ svn_repos_get_fs_build_parser4(const svn
                                void *notify_baton,
                                apr_pool_t *pool)
 {
-  svn_repos_parse_fns2_t *parser = apr_pcalloc(pool, sizeof(*parser));
+  svn_repos_parse_fns3_t *parser = apr_pcalloc(pool, sizeof(*parser));
   struct parse_baton *pb = apr_pcalloc(pool, sizeof(*pb));
 
   if (parent_dir)
@@ -1042,9 +1042,9 @@ svn_repos_get_fs_build_parser4(const svn
   if (SVN_IS_VALID_REVNUM(start_rev))
     SVN_ERR_ASSERT(start_rev <= end_rev);
 
+  parser->uuid_record = uuid_record;
   parser->new_revision_record = new_revision_record;
   parser->new_node_record = new_node_record;
-  parser->uuid_record = uuid_record;
   parser->set_revision_property = set_revision_property;
   parser->set_node_property = set_node_property;
   parser->remove_node_props = remove_node_props;
@@ -1116,6 +1116,6 @@ svn_repos_load_fs4(svn_repos_t *repos,
   pb->use_pre_commit_hook = use_pre_commit_hook;
   pb->use_post_commit_hook = use_post_commit_hook;
 
-  return svn_repos_parse_dumpstream2(dumpstream, parser, parse_baton,
+  return svn_repos_parse_dumpstream3(dumpstream, parser, parse_baton,
                                      cancel_func, cancel_baton, pool);
 }

Modified: subversion/trunk/subversion/libsvn_repos/load.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/load.c?rev=1350545&r1=1350544&r2=1350545&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/load.c (original)
+++ subversion/trunk/subversion/libsvn_repos/load.c Fri Jun 15 09:11:58 2012
@@ -181,7 +181,7 @@ read_key_or_val(char **pbuf,
 static svn_error_t *
 parse_property_block(svn_stream_t *stream,
                      svn_filesize_t content_length,
-                     const svn_repos_parse_fns2_t *parse_fns,
+                     const svn_repos_parse_fns3_t *parse_fns,
                      void *record_baton,
                      void *parse_baton,
                      svn_boolean_t is_node,
@@ -299,7 +299,7 @@ static svn_error_t *
 parse_text_block(svn_stream_t *stream,
                  svn_filesize_t content_length,
                  svn_boolean_t is_delta,
-                 const svn_repos_parse_fns2_t *parse_fns,
+                 const svn_repos_parse_fns3_t *parse_fns,
                  void *record_baton,
                  char *buffer,
                  apr_size_t buflen,
@@ -406,8 +406,8 @@ parse_format_version(const char *version
 /** The public routines **/
 
 svn_error_t *
-svn_repos_parse_dumpstream2(svn_stream_t *stream,
-                            const svn_repos_parse_fns2_t *parse_fns,
+svn_repos_parse_dumpstream3(svn_stream_t *stream,
+                            const svn_repos_parse_fns3_t *parse_fns,
                             void *parse_baton,
                             svn_cancel_func_t cancel_func,
                             void *cancel_baton,

Modified: subversion/trunk/subversion/svndumpfilter/main.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svndumpfilter/main.c?rev=1350545&r1=1350544&r2=1350545&view=diff
==============================================================================
--- subversion/trunk/subversion/svndumpfilter/main.c (original)
+++ subversion/trunk/subversion/svndumpfilter/main.c Fri Jun 15 09:11:58 2012
@@ -878,10 +878,10 @@ close_revision(void *revision_baton)
 
 
 /* Filtering vtable */
-svn_repos_parse_fns2_t filtering_vtable =
+svn_repos_parse_fns3_t filtering_vtable =
   {
-    new_revision_record,
     uuid_record,
+    new_revision_record,
     new_node_record,
     set_revision_property,
     set_node_property,
@@ -1144,7 +1144,7 @@ do_filter(apr_getopt_t *os,
     }
 
   SVN_ERR(parse_baton_initialize(&pb, opt_state, do_exclude, pool));
-  SVN_ERR(svn_repos_parse_dumpstream2(pb->in_stream, &filtering_vtable, pb,
+  SVN_ERR(svn_repos_parse_dumpstream3(pb->in_stream, &filtering_vtable, pb,
                                       NULL, NULL, pool));
 
   /* The rest of this is just reporting.  If we aren't reporting, get

Modified: subversion/trunk/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnrdump/load_editor.c?rev=1350545&r1=1350544&r2=1350545&view=diff
==============================================================================
--- subversion/trunk/subversion/svnrdump/load_editor.c (original)
+++ subversion/trunk/subversion/svnrdump/load_editor.c Fri Jun 15 09:11:58 2012
@@ -1146,7 +1146,7 @@ svn_rdump__load_dumpstream(svn_stream_t 
                            void *cancel_baton,
                            apr_pool_t *pool)
 {
-  svn_repos_parse_fns2_t *parser;
+  svn_repos_parse_fns3_t *parser;
   struct parse_baton *parse_baton;
   const svn_string_t *lock_string;
   svn_boolean_t be_atomic;
@@ -1185,7 +1185,7 @@ svn_rdump__load_dumpstream(svn_stream_t 
   parse_baton->last_rev_mapped = SVN_INVALID_REVNUM;
   parse_baton->oldest_dumpstream_rev = SVN_INVALID_REVNUM;
 
-  err = svn_repos_parse_dumpstream2(stream, parser, parse_baton,
+  err = svn_repos_parse_dumpstream3(stream, parser, parse_baton,
                                     cancel_func, cancel_baton, pool);
 
   /* If all goes well, or if we're cancelled cleanly, don't leave a