You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ko...@apache.org on 2022/11/25 17:13:55 UTC

svn commit: r1905528 - in /subversion/branches/pristines-on-demand-on-mwf/subversion: include/ libsvn_client/ libsvn_ra/ libsvn_ra_local/ libsvn_ra_serf/ libsvn_ra_svn/

Author: kotkov
Date: Fri Nov 25 17:13:55 2022
New Revision: 1905528

URL: http://svn.apache.org/viewvc?rev=1905528&view=rev
Log:
On the 'pristines-on-demand-on-mwf' branch: Rework the RA part of the
text-base fetching.

This changeset solves a performance issue where fetching a single text-base
over ra_serf required two requests (PROPFIND + GET) instead of one (GET).

It also lays the groundwork for reusing RA sessions.  Such reuse was partly
blocked by having to open a session that is not associated with a specific
working copy, because otherwise a content fetch would first try the local
pristine cache — which is a waste of resources for the case when we are
fetching the pristines ourselves.

* subversion/include/svn_ra.h
  (svn_ra_fetch_file_contents): New.

* subversion/libsvn_ra/ra_loader.h
  (svn_ra__vtable_t.fetch_file_contents): New

* subversion/libsvn_ra/ra_loader.c
  (svn_ra_fetch_file_contents): Call the new vtable member.

* subversion/libsvn_ra_local/ra_plugin.c
  (get_file): Factor out this helper function.  Always close the stream.
  (svn_ra_local__get_file): Call the helper function, disowning the stream
   to keep the current behavior.
  (svn_ra_local__fetch_file_contents): New, implemented with a call to the
   new helper function.
  (ra_local_vtable): Add new function to vtable.

* subversion/libsvn_ra_svn/client.c
  (get_file): Factor out this helper function.  Always close the stream.
  (ra_svn_get_file): Call the helper function, disowning the stream
   to keep the current behavior.
  (ra_svn_fetch_file_contents): New, implemented with a call to the
   new helper function.
  (ra_svn_vtable): Add new function to vtable.

* subversion/libsvn_ra_serf/ra_serf.h
  (svn_ra_serf__fetch_file_contents): New.

* subversion/libsvn_ra_serf/get_file.c
  (svn_ra_serf__fetch_file_contents): New.

* subversion/libsvn_ra_serf/serf.c
  (serf_vtable): Add new function to vtable.

* subversion/libsvn_client/textbase.c
  (textbase_hydrate_cb): Use the new RA function to fetch the contents.

Modified:
    subversion/branches/pristines-on-demand-on-mwf/subversion/include/svn_ra.h
    subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_client/textbase.c
    subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.c
    subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.h
    subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_local/ra_plugin.c
    subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/get_file.c
    subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/ra_serf.h
    subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/serf.c
    subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_svn/client.c

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/include/svn_ra.h
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/include/svn_ra.h?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/include/svn_ra.h (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/include/svn_ra.h Fri Nov 25 17:13:55 2022
@@ -2164,6 +2164,29 @@ svn_ra_get_inherited_props(svn_ra_sessio
                            apr_pool_t *scratch_pool);
 
 /**
+ * Fetch the contents of file @a path at @a revision.  Interpret @a path
+ * relative to the URL in @a session.  @a revision must be a valid revision
+ * number.  Use @a scratch_pool for scratch allocations.
+ *
+ * The contents of the file will be pushed to @a stream, and the stream will
+ * be closed when finished.  If the closure is not desired, then you can use
+ * svn_stream_disown() to protect the stream from being closed.  The stream
+ * handlers for @a stream may not perform any RA operations using @a session.
+ *
+ * The contents may be expected to be fetched directly from the remote
+ * endpoint, rather from any local caches such as the one provided by
+ * #svn_ra_get_wc_contents_func_t.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_ra_fetch_file_contents(svn_ra_session_t *session,
+                           const char *path,
+                           svn_revnum_t revision,
+                           svn_stream_t *stream,
+                           apr_pool_t *scratch_pool);
+
+/**
  * @defgroup Capabilities Dynamically query the server's capabilities.
  *
  * @{

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_client/textbase.c
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_client/textbase.c?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_client/textbase.c (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_client/textbase.c Fri Nov 25 17:13:55 2022
@@ -49,7 +49,6 @@ textbase_hydrate_cb(void *baton,
   struct textbase_hydrate_baton_t *b = baton;
   const char *url;
   const char *old_url;
-  svn_error_t *err;
 
   url = svn_path_url_add_component2(repos_root_url, repos_relpath,
                                     scratch_pool);
@@ -87,11 +86,10 @@ textbase_hydrate_cb(void *baton,
 
   SVN_ERR(svn_client__ensure_ra_session_url(&old_url, b->ra_session, url,
                                             scratch_pool));
-  err = svn_ra_get_file(b->ra_session, "", revision, contents,
-                        NULL, NULL, scratch_pool);
-  err = svn_error_compose_create(err, svn_stream_close(contents));
+  SVN_ERR(svn_ra_fetch_file_contents(b->ra_session, "", revision, contents,
+                                     scratch_pool));
 
-  return svn_error_trace(err);
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.c?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.c Fri Nov 25 17:13:55 2022
@@ -1369,6 +1369,18 @@ svn_ra_get_inherited_props(svn_ra_sessio
 }
 
 svn_error_t *
+svn_ra_fetch_file_contents(svn_ra_session_t *session,
+                           const char *path,
+                           svn_revnum_t revision,
+                           svn_stream_t *stream,
+                           apr_pool_t *scratch_pool)
+{
+  SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
+  return session->vtable->fetch_file_contents(session, path, revision, stream,
+                                              scratch_pool);
+}
+
+svn_error_t *
 svn_ra__get_commit_ev2(svn_editor_t **editor,
                        svn_ra_session_t *session,
                        apr_hash_t *revprop_table,

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.h?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra/ra_loader.h Fri Nov 25 17:13:55 2022
@@ -345,6 +345,13 @@ typedef struct svn_ra__vtable_t {
                        void *receiver_baton,
                        apr_pool_t *scratch_pool);
 
+  /* See svn_ra_fetch_file_contents(). */
+  svn_error_t *(*fetch_file_contents)(svn_ra_session_t *session,
+                                      const char *path,
+                                      svn_revnum_t revision,
+                                      svn_stream_t *stream,
+                                      apr_pool_t *scratch_pool);
+
   /* Experimental support below here */
 
   /* See svn_ra__register_editor_shim_callbacks() */

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_local/ra_plugin.c?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_local/ra_plugin.c Fri Nov 25 17:13:55 2022
@@ -1255,13 +1255,13 @@ get_node_props(apr_hash_t **props,
 
 /* Getting just one file. */
 static svn_error_t *
-svn_ra_local__get_file(svn_ra_session_t *session,
-                       const char *path,
-                       svn_revnum_t revision,
-                       svn_stream_t *stream,
-                       svn_revnum_t *fetched_rev,
-                       apr_hash_t **props,
-                       apr_pool_t *pool)
+get_file(svn_ra_session_t *session,
+         const char *path,
+         svn_revnum_t revision,
+         svn_stream_t *stream,
+         svn_revnum_t *fetched_rev,
+         apr_hash_t **props,
+         apr_pool_t *pool)
 {
   svn_fs_root_t *root;
   svn_stream_t *contents;
@@ -1306,11 +1306,8 @@ svn_ra_local__get_file(svn_ra_session_t
          stored checksum, and all we're doing here is writing bytes in
          a loop.  Truly, Nothing Can Go Wrong :-).  But RA layers that
          go over a network should confirm the checksum.
-
-         Note: we are not supposed to close the passed-in stream, so
-         disown the thing.
       */
-      SVN_ERR(svn_stream_copy3(contents, svn_stream_disown(stream, pool),
+      SVN_ERR(svn_stream_copy3(contents, stream,
                                sess->callbacks
                                  ? sess->callbacks->cancel_func : NULL,
                                sess->callback_baton,
@@ -1866,6 +1863,38 @@ svn_ra_local__list(svn_ra_session_t *ses
                                         sess->callback_baton, pool));
 }
 
+static svn_error_t *
+svn_ra_local__get_file(svn_ra_session_t *session,
+                       const char *path,
+                       svn_revnum_t revision,
+                       svn_stream_t *stream,
+                       svn_revnum_t *fetched_rev,
+                       apr_hash_t **props,
+                       apr_pool_t *pool)
+{
+  /* We are not supposed to close the passed-in stream, so disown it. */
+  if (stream)
+    stream = svn_stream_disown(stream, pool);
+
+  SVN_ERR(get_file(session, path, revision, stream, fetched_rev,
+                   props, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+svn_ra_local__fetch_file_contents(svn_ra_session_t *session,
+                                  const char *path,
+                                  svn_revnum_t revision,
+                                  svn_stream_t *stream,
+                                  apr_pool_t *scratch_pool)
+{
+  SVN_ERR(get_file(session, path, revision, stream, NULL,
+                   NULL, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /*----------------------------------------------------------------*/
 
 static const svn_version_t *
@@ -1917,6 +1946,7 @@ static const svn_ra__vtable_t ra_local_v
   svn_ra_local__get_inherited_props,
   NULL /* set_svn_ra_open */,
   svn_ra_local__list ,
+  svn_ra_local__fetch_file_contents,
   svn_ra_local__register_editor_shim_callbacks,
   svn_ra_local__get_commit_ev2,
   NULL /* replay_range_ev2 */

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/get_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/get_file.c?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/get_file.c (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/get_file.c Fri Nov 25 17:13:55 2022
@@ -428,3 +428,59 @@ svn_ra_serf__get_file(svn_ra_session_t *
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_ra_serf__fetch_file_contents(svn_ra_session_t *ra_session,
+                                 const char *path,
+                                 svn_revnum_t revision,
+                                 svn_stream_t *stream,
+                                 apr_pool_t *scratch_pool)
+{
+  svn_ra_serf__session_t *session = ra_session->priv;
+  const char *fetch_url;
+  stream_ctx_t *stream_ctx;
+  svn_ra_serf__handler_t *handler;
+  svn_error_t *err;
+
+  fetch_url = svn_path_url_add_component2(session->session_url.path, path,
+                                          scratch_pool);
+
+  SVN_ERR(svn_ra_serf__get_stable_url(&fetch_url, NULL, session,
+                                      fetch_url, revision,
+                                      scratch_pool, scratch_pool));
+
+  /* Create the fetch context. */
+  stream_ctx = apr_pcalloc(scratch_pool, sizeof(*stream_ctx));
+  stream_ctx->result_stream = stream;
+  stream_ctx->session = session;
+
+  handler = svn_ra_serf__create_handler(session, scratch_pool);
+
+  handler->method = "GET";
+  handler->path = fetch_url;
+
+  handler->custom_accept_encoding = TRUE;
+  handler->no_dav_headers = TRUE;
+
+  handler->header_delegate = headers_fetch;
+  handler->header_delegate_baton = stream_ctx;
+
+  handler->response_handler = handle_stream;
+  handler->response_baton = stream_ctx;
+
+  handler->response_error = cancel_fetch;
+  handler->response_error_baton = stream_ctx;
+
+  stream_ctx->handler = handler;
+
+  err = svn_ra_serf__context_run_one(handler, scratch_pool);
+
+  err = svn_error_compose_create(err, svn_stream_close(stream));
+
+  if (err)
+    return svn_error_trace(err);
+  else if (handler->sline.code != 200)
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/ra_serf.h?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/ra_serf.h Fri Nov 25 17:13:55 2022
@@ -1511,6 +1511,14 @@ svn_error_t *
 svn_ra_serf__register_editor_shim_callbacks(svn_ra_session_t *session,
                                     svn_delta_shim_callbacks_t *callbacks);
 
+/* Implements svn_ra__vtable_t.fetch_file_contents(). */
+svn_error_t *
+svn_ra_serf__fetch_file_contents(svn_ra_session_t *session,
+                                 const char *path,
+                                 svn_revnum_t revision,
+                                 svn_stream_t *stream,
+                                 apr_pool_t *scratch_pool);
+
 /*** Authentication handler declarations ***/
 
 /**

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/serf.c?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_serf/serf.c Fri Nov 25 17:13:55 2022
@@ -1068,6 +1068,7 @@ static const svn_ra__vtable_t serf_vtabl
   svn_ra_serf__get_inherited_props,
   NULL /* set_svn_ra_open */,
   svn_ra_serf__list,
+  svn_ra_serf__fetch_file_contents,
   svn_ra_serf__register_editor_shim_callbacks,
   NULL /* commit_ev2 */,
   NULL /* replay_range_ev2 */

Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_svn/client.c?rev=1905528&r1=1905527&r2=1905528&view=diff
==============================================================================
--- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_ra_svn/client.c Fri Nov 25 17:13:55 2022
@@ -1436,11 +1436,11 @@ parse_iproplist(apr_array_header_t **inh
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *ra_svn_get_file(svn_ra_session_t *session, const char *path,
-                                    svn_revnum_t rev, svn_stream_t *stream,
-                                    svn_revnum_t *fetched_rev,
-                                    apr_hash_t **props,
-                                    apr_pool_t *pool)
+static svn_error_t *get_file(svn_ra_session_t *session, const char *path,
+                             svn_revnum_t rev, svn_stream_t *stream,
+                             svn_revnum_t *fetched_rev,
+                             apr_hash_t **props,
+                             apr_pool_t *pool)
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
@@ -1497,6 +1497,8 @@ static svn_error_t *ra_svn_get_file(svn_
     }
   svn_pool_destroy(iterpool);
 
+  SVN_ERR(svn_stream_close(stream));
+
   SVN_ERR(svn_ra_svn__read_cmd_response(conn, pool, ""));
 
   if (expected_checksum)
@@ -3258,6 +3260,34 @@ ra_svn_list(svn_ra_session_t *session,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *ra_svn_get_file(svn_ra_session_t *session, const char *path,
+                                    svn_revnum_t rev, svn_stream_t *stream,
+                                    svn_revnum_t *fetched_rev,
+                                    apr_hash_t **props,
+                                    apr_pool_t *pool)
+{
+  /* We are not supposed to close the passed-in stream, so disown it. */
+  if (stream)
+    stream = svn_stream_disown(stream, pool);
+
+  SVN_ERR(get_file(session, path, rev, stream, fetched_rev,
+                   props, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *ra_svn_fetch_file_contents(svn_ra_session_t *session,
+                                               const char *path,
+                                               svn_revnum_t rev,
+                                               svn_stream_t *stream,
+                                               apr_pool_t *scratch_pool)
+{
+  SVN_ERR(get_file(session, path, rev, stream, NULL,
+                   NULL, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 static const svn_ra__vtable_t ra_svn_vtable = {
   svn_ra_svn_version,
   ra_svn_get_description,
@@ -3298,6 +3328,7 @@ static const svn_ra__vtable_t ra_svn_vta
   ra_svn_get_inherited_props,
   NULL /* ra_set_svn_ra_open */,
   ra_svn_list,
+  ra_svn_fetch_file_contents,
   ra_svn_register_editor_shim_callbacks,
   NULL /* commit_ev2 */,
   NULL /* replay_range_ev2 */