Author: stefan2
Date: Sun Feb  8 16:18:47 2015
New Revision: 1658202

URL: http://svn.apache.org/r1658202
Log:
Speed up ra_svn's editor command processing.  Instead of iterating
through a list of commands to find the appropriate handler to call,
use a simple hashed array with a trivial mapping function.

* subversion/libsvn_ra_svn/editorp.c
  (cmd_t): New. Entry type of the new table.
  (CMD_HASH_SIZE): New. Dimension of the new table.
  (cmd_hash): The new hashed table itself.
  (cmd_hash_initialized): New control flag.

  (cmd_hash_func): New. The hash / mapping function used.
  (init_cmd_hash): Table constructor.
  (cmd_lookup): Update the command lookup logic.
  (svn_ra_svn_drive_editor2): Properly initialize the command hash
                              table upon first use.

Modified:
    subversion/branches/ra-svn-tuning/subversion/libsvn_ra_svn/editorp.c

Modified: subversion/branches/ra-svn-tuning/subversion/libsvn_ra_svn/editorp.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-svn-tuning/subversion/libsvn_ra_svn/editorp.c?rev=1658202&r1=1658201&r2=1658202&view=diff
==============================================================================
--- subversion/branches/ra-svn-tuning/subversion/libsvn_ra_svn/editorp.c 
(original)
+++ subversion/branches/ra-svn-tuning/subversion/libsvn_ra_svn/editorp.c Sun 
Feb  8 16:18:47 2015
@@ -39,8 +39,10 @@
 #include "svn_pools.h"
 #include "svn_private_config.h"
 
+#include "private/svn_atomic.h"
 #include "private/svn_fspath.h"
 #include "private/svn_editor.h"
+#include "private/svn_subr_private.h"
 
 #include "ra_svn.h"
 
@@ -923,18 +925,90 @@ static const struct {
   { NULL }
 };
 
+/* All editor commands are kept in a collision-free hash table. */
+
+/* Hash table entry.
+   It is similar to ra_svn_edit_cmds but uses our SVN string type. */
+typedef struct cmd_t {
+  svn_string_t cmd;
+  cmd_handler_t handler;
+} cmd_t;
+
+/* The actual hash table.  It will be filled once before first usage.
+
+   If you add more commands, you may have to tweak the table size to
+   eliminate collisions.  Alternatively, you may modify the hash function.
+
+   Be sure to initialize all elements with 0 as the has conflict detection
+   will rely on it (see init_cmd_hash).
+ */
+#define CMD_HASH_SIZE 67
+static cmd_t cmd_hash[CMD_HASH_SIZE] = { { { NULL } } };
+
+/* Init flag that controls CMD_HASH's atomic initialization. */
+static volatile svn_atomic_t cmd_hash_initialized = FALSE;
+
+/* Super-fast hash function that works very well with the structure of our
+   command words.  It produces no conflicts for them.
+
+   Return the index within CMD_HASH that a command NAME of LEN chars would
+   be found.  LEN > 0.
+ */
+static apr_size_t
+cmd_hash_func(const char *name,
+              apr_size_t len)
+{
+  apr_size_t value =     (apr_byte_t)(name[0] - 'a') % 8
+                   + 1 * (apr_byte_t)(name[len - 1] - 'a') % 8
+                   + 10 * (len - 7);
+  return value % CMD_HASH_SIZE;
+}
+
+/* svn_atomic__init_once callback that fills the CMD_HASH table.  It will
+   error out on hash collisions.  BATON and POOL are not used. */
+static svn_error_t *
+init_cmd_hash(void *baton,
+              apr_pool_t *pool)
+{
+  int i;
+  for (i = 0; ra_svn_edit_cmds[i].cmd; i++)
+    {
+      apr_size_t len = strlen(ra_svn_edit_cmds[i].cmd);
+      apr_size_t value = cmd_hash_func(ra_svn_edit_cmds[i].cmd, len);
+      SVN_ERR_ASSERT(cmd_hash[value].cmd.data == NULL);
+
+      cmd_hash[value].cmd.data = ra_svn_edit_cmds[i].cmd;
+      cmd_hash[value].cmd.len = len;
+      cmd_hash[value].handler = ra_svn_edit_cmds[i].handler;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Return the command handler function for the command name CMD.
    Return NULL if no such handler exists */
 static cmd_handler_t
 cmd_lookup(const char *cmd)
 {
-  int i;
+  apr_size_t value;
+  apr_size_t len = strlen(cmd);
 
-  for (i = 0; ra_svn_edit_cmds[i].cmd; i++)
-    if (strcmp(cmd, ra_svn_edit_cmds[i].cmd) == 0)
-      return ra_svn_edit_cmds[i].handler;
+  /* Malicious data that our hash function may not like? */
+  if (len == 0)
+    return NULL;
+
+  /* Hash lookup. */
+  value = cmd_hash_func(cmd, len);
 
-  return NULL;
+  /* Hit? */
+  if (cmd_hash[value].cmd.len != len)
+    return NULL;
+
+  if (memcmp(cmd_hash[value].cmd.data, cmd, len))
+    return NULL;
+
+  /* Yes! */
+  return cmd_hash[value].handler;
 }
 
 static svn_error_t *blocked_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
@@ -968,6 +1042,9 @@ svn_error_t *svn_ra_svn_drive_editor2(sv
   svn_error_t *err, *write_err;
   apr_array_header_t *params;
 
+  SVN_ERR(svn_atomic__init_once(&cmd_hash_initialized, init_cmd_hash, NULL,
+                                pool));
+
   state.editor = editor;
   state.edit_baton = edit_baton;
   state.tokens = apr_hash_make(pool);


Reply via email to