Author: stefan2
Date: Mon Aug 18 15:50:44 2014
New Revision: 1618641

URL: http://svn.apache.org/r1618641
Log:
Within FSFS, replace the use of svn__strtol with a variant that
provides overflow detection.  FSFS needs a locale-independent
and preferrably quick number parser.

This is to eventually get rid of svn__strtol.

* subversion/libsvn_fs_fs/id.c
  (fast__strtol): New local function, mainly taken form string.c
                  but with overflow checks and state return added.
  (part_parse,
   txn_id_parse,
   svn_fs_fs__id_parse): Update callers.

Modified:
    subversion/trunk/subversion/libsvn_fs_fs/id.c

Modified: subversion/trunk/subversion/libsvn_fs_fs/id.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/id.c?rev=1618641&r1=1618640&r2=1618641&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/id.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/id.c Mon Aug 18 15:50:44 2014
@@ -48,12 +48,55 @@ typedef struct fs_fs__id_t
 
 
 
+/** Like strtol but with a fixed base of 10, locale independent and limited
+ * to non-negative values.  Overflows are indicated by a FALSE return value
+ * in which case *RESULT_P will not be modified.
+ *
+ * This allows the compiler to generate massively faster code.
+ * (E.g. Avoiding locale specific processing).  ID parsing is one of the
+ * most CPU consuming parts of FSFS data access.  Better be quick.
+ */
+static svn_boolean_t
+fast__strtol(long *result_p,
+             const char* buffer,
+             const char** end)
+{
+  /* We allow positive values only.  Unsigned arithmetics tend to be faster
+   * as they allow for a wider range of compiler-side optimizations. */
+  unsigned long result = 0;
+  while (1)
+    {
+      unsigned long c = (unsigned char)*buffer - (unsigned char)'0';
+      unsigned long next;
+
+      /* This implies the NUL check. */
+      if (c > 9)
+        break;
+
+      next = result * 10 + c;
+
+      /* Overflow check. */
+      if (next < result)
+        return FALSE;
+
+      result = next;
+      ++buffer;
+    }
+
+  *end = buffer;
+  *result_p = (long)result;
+
+  return TRUE;
+}
+
 /* Parse the NUL-terminated ID part at DATA and write the result into *PART.
  * Return TRUE if no errors were detected. */
 static svn_boolean_t
 part_parse(svn_fs_fs__id_part_t *part,
            const char *data)
 {
+  const char *end;
+
   /* special case: ID inside some transaction */
   if (data[0] == '_')
     {
@@ -78,12 +121,7 @@ part_parse(svn_fs_fs__id_part_t *part,
       return *data == '\0';
     }
 
-  {
-    const char *end;
-    part->revision = svn__strtol(data+1, &end);
-  }
-
-  return TRUE;
+  return fast__strtol(&part->revision, data+1, &end);
 }
 
 /* Parse the transaction id in DATA and store the result in *TXN_ID.
@@ -94,7 +132,9 @@ txn_id_parse(svn_fs_fs__id_part_t *txn_i
              const char *data)
 {
   const char *end;
-  txn_id->revision = svn__strtol(data, &end);
+  if (!fast__strtol(&txn_id->revision, data, &end))
+    return FALSE;
+
   data = strchr(end, '-');
   if (data == NULL)
     return FALSE;
@@ -489,7 +529,8 @@ svn_fs_fs__id_parse(char *data,
       str = svn_cstring_tokenize("/", &data);
       if (str == NULL)
         return NULL;
-      id->private_id.rev_item.revision = svn__strtol(str, &tmp);
+      if (!fast__strtol(&id->private_id.rev_item.revision, str, &tmp))
+        return NULL;
 
       err = svn_cstring_atoi64(&val, data);
       if (err)


Reply via email to