All pastes #18169 Raw Edit

Miscellany

public text v1 · immutable
#18169 ·published 2005-07-20 19:53 UTC
rendered paste body
[[[
Plug a memory leak by avoiding repeated failing attempts at apr_xlate setup.

Review by: jerenkrantz
Suggested by: jerenkrantz
              dberlin
              ghudson
              brane
              striker

* subversion/libsvn_subr/utf.c
  (enotimpl_handle_node): New file-static variable.
  (get_xlate_handle_node): Use enotimpl_handle_node to determine
  whether to even bother calling apr_xlate_open again.  Update and fix
  doc string, which was wrong before anyway.
]]]


Index: subversion/libsvn_subr/utf.c
===================================================================
--- subversion/libsvn_subr/utf.c	(revision 15373)
+++ subversion/libsvn_subr/utf.c	(working copy)
@@ -68,6 +68,17 @@
    memory leak. */
 static apr_hash_t *xlate_handle_hash = NULL;
 
+/* Non-NULL iff apr_xlate_open() ever returned APR_ENOTIMPL.  Since
+   there would be no point ever calling apr_xlate_open() again in this
+   process, we can save ourself some setup work (including memory
+   allocations) by caching a handle_node to return in that case;
+   enotimpl_handle_node->handle will be NULL, of course.
+   apr_xlate_open() could return APR_ENOTIMPL because APR_HAS_XLATE is
+   not defined, or for some other reason.  For our purposes it doesn't
+   matter, we just want to remember that it is not implemented for
+   this process. */
+static xlate_handle_node_t *enotimpl_handle_node = NULL;
+
 /* Clean up the xlate handle cache. */
 static apr_status_t
 xlate_cleanup (void *arg)
@@ -122,12 +133,13 @@
     }
 }
 
-/* Return an apr_xlate handle for converting from FROMPAGE to
-   TOPAGE. Create one if it doesn't exist in USERDATA_KEY. If
-   unable to find a handle, or unable to create one because
-   apr_xlate_open returned APR_EINVAL, then set *RET to null and
-   return SVN_NO_ERROR; if fail for some other reason, return
-   error. */
+/* Set *RET to an apr_xlate handle for converting from FROMPAGE to
+   TOPAGE, creating the handle if it doesn't exist in USERDATA_KEY.
+   If unable to find a handle, or unable to create one because
+   apr_xlate_open returned APR_EINVAL or APR_ENOTIMPL, then
+   *RET->handle will be NULL (and in the ENOTIMPL case, allocate *RET
+   itself in a child of the top-level pool, not in POOL).  If fail for
+   any other reason, return error. */
 static svn_error_t *
 get_xlate_handle_node (xlate_handle_node_t **ret,
                        const char *topage, const char *frompage,
@@ -199,6 +211,14 @@
   if (userdata_key && xlate_handle_hash)
     pool = apr_hash_pool_get (xlate_handle_hash);
 
+  /* If we failed due to ENOTIMPL before, then we'd certainly fail
+     now, so just return without trying. */
+  if (enotimpl_handle_node)
+    {
+      *ret = enotimpl_handle_node;
+      return SVN_NO_ERROR;
+    }
+  
   /* Try to create a handle. */
   *ret = apr_palloc (pool, sizeof(xlate_handle_node_t));
   apr_err = apr_xlate_open (&(*ret)->handle, topage, frompage, pool);
@@ -229,6 +249,19 @@
 
   if (APR_STATUS_IS_EINVAL (apr_err) || APR_STATUS_IS_ENOTIMPL (apr_err))
     {
+      if (APR_STATUS_IS_ENOTIMPL (apr_err))
+        {
+          /* Remember for next time that we needn't bother trying.
+             Use the top-level pool because we have no lifetime
+             guarantees about our local pool parameter. */
+          enotimpl_handle_node = apr_palloc (svn_pool_create (NULL),
+                                             sizeof (*enotimpl_handle_node));
+          enotimpl_handle_node->handle = NULL;
+          enotimpl_handle_node->frompage = NULL;
+          enotimpl_handle_node->topage = NULL;
+          enotimpl_handle_node->next = NULL;
+        }
+
       (*ret)->handle = NULL;
       return SVN_NO_ERROR;
     }