subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1659511 - /subversion/branches/fsx-1.10/subversion/libsvn_fs_x/dag_cache.c
Date Fri, 13 Feb 2015 11:23:26 GMT
Author: stefan2
Date: Fri Feb 13 11:23:26 2015
New Revision: 1659511

URL: http://svn.apache.org/r1659511
Log:
On the fsx-1.10 branch:
Move typical operations on normalized paths into separate functions.
This also does away with quirks and inefficiencies.

* subversion/libsvn_fs_x/dag_cache.c
  (): Explain that the underlying C string in a normalizes path is
      actually NUL-terminated.
  (next_entry_name,
   extract_last_segment): New utilities for normalized paths.
  (walk_dag_path): Greatly simplify using the new utils.

Modified:
    subversion/branches/fsx-1.10/subversion/libsvn_fs_x/dag_cache.c

Modified: subversion/branches/fsx-1.10/subversion/libsvn_fs_x/dag_cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/libsvn_fs_x/dag_cache.c?rev=1659511&r1=1659510&r2=1659511&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/libsvn_fs_x/dag_cache.c (original)
+++ subversion/branches/fsx-1.10/subversion/libsvn_fs_x/dag_cache.c Fri Feb 13 11:23:26 2015
@@ -98,7 +98,9 @@ root_change_set(svn_fs_root_t *root)
 
    Another optimization is that we don't NUL-terminate the path but strictly
    use its length info.  That way, it can be traversed easily without
-   chopping it up and patching it together again.
+   chopping it up and patching it together again.  ultimately, however,
+   the path string is NUL-terminated because we wrapped a NUL-terminated
+   C string.
  */
 
 /* Set *RESULT to a normalized version of PATH without actually copying any
@@ -124,6 +126,98 @@ normalize_path(svn_string_t *result,
   return result;
 }
 
+/* Extend PATH, i.e. increase its LEN, to cover the next segment.  Skip
+   sequences of '/'.  Store the segment in ENTRY and return a pointer to
+   it C string representation.  If no segment has been found (end of path),
+   return NULL. */
+static const char *
+next_entry_name(svn_string_t *path,
+                svn_stringbuf_t *entry)
+{
+  const char *segment_start;
+  const char *segment_end;
+
+  /* Moving to the next segment, skip separators
+     (normalized does not imply canonical). */
+  segment_start = path->data + path->len;
+  while (*segment_start == '/')
+    ++segment_start;
+
+  /* End of path? */
+  if (*segment_start == '\0')
+    return NULL;
+
+  /* Find the end of this segment.  Note that strchr would not give us the
+     length of the last segment. */
+  segment_end = segment_start;
+  while (*segment_end != '/' && *segment_end != '\0')
+    ++segment_end;
+
+  /* Copy the segment into the result buffer. */
+  svn_stringbuf_setempty(entry);
+  svn_stringbuf_appendbytes(entry, segment_start,
+                            segment_end - segment_start);
+
+  /* Extend the "visible" part of the path to the end of that segment. */
+  path->len = segment_end - path->data;
+
+  /* Indicate that we found something. */
+  return entry->data;
+}
+
+/* Split the normalized PATH into its last segment the corresponding parent
+   directory.  Store them in ENTRY and DIRECTORY, respectively.
+
+   If PATH is empty, return FALSE and produce no output.
+   Otherwise, return TRUE.
+ */
+static svn_boolean_t
+extract_last_segment(const svn_string_t *path,
+                     svn_string_t *directory,
+                     svn_stringbuf_t *entry)
+{
+  const char *segment_start;
+  const char *parent_end;
+
+  /* Edge case.  We can't navigate in empty paths. */
+  if (path->len == 0)
+    return FALSE;
+
+  /* Find the start of the last segment.  Note that normalized paths never
+     start nor end with a '/'. */
+  segment_start = path->data + path->len - 1;
+  while (*segment_start != '/' && segment_start != path->data)
+    --segment_start;
+
+  /* At root level already, i.e. no parent? */
+  if (segment_start == path->data)
+    {
+      /* Construct result. */
+      directory->data = "";
+      directory->len = 0;
+
+      svn_stringbuf_setempty(entry);
+      svn_stringbuf_appendbytes(entry, path->data, path->len);
+
+      return TRUE;
+    }
+
+  /* Find the end of the parent directory. */
+  parent_end = segment_start;
+  while (parent_end[-1] == '/')
+    --parent_end;
+
+  /* Construct result. */
+  directory->data = path->data;
+  directory->len = parent_end - path->data;
+
+  ++segment_start; /* previously pointed to the last '/'. */
+  svn_stringbuf_setempty(entry);
+  svn_stringbuf_appendbytes(entry, segment_start,
+                            path->len - (segment_start - path->data));
+
+  return TRUE;
+}
 
 
 /*** Node Caching ***/
@@ -895,11 +989,11 @@ walk_dag_path(dag_node_t **node_p,
               apr_pool_t *scratch_pool)
 {
   dag_node_t *here = NULL; /* The directory we're currently looking at.  */
-  const char *rest; /* The portion of PATH we haven't traversed yet. */
-  const char *next;
   apr_pool_t *iterpool;
   svn_fs_x__change_set_t change_set = root_change_set(root);
   const char *entry;
+  svn_string_t directory;
+  svn_stringbuf_t *entry_buffer;
 
   /* Special case: root directory.
      We will later assume that all paths have at least one parent level,
@@ -935,26 +1029,19 @@ walk_dag_path(dag_node_t **node_p,
      node.  We will often have recently accessed either a sibling or
      said parent directory itself for the same revision.  ENTRY will
      point to the last '/' in PATH. */
-  entry = path->data + path->len - 1;
-  while (*entry != '/' && entry != path->data)
-    --entry;
-
-  if (entry != path->data) /* root nodes are covered anyway */
-    {
-      /* Temporarily hide the last segment from PATH and search the cache
-         for our directory. */
-      apr_size_t path_len = path->len;
-      path->len = entry - path->data;
-      here = dag_node_cache_get(root, path);
-      path->len = path_len;
+  entry_buffer = svn_stringbuf_create_ensure(64, scratch_pool);
+  if (extract_last_segment(path, &directory, entry_buffer))
+    {
+      here = dag_node_cache_get(root, &directory);
 
       /* Did the shortcut work? */
       if (here)
-        return svn_error_trace(dag_step(node_p, root, here, entry + 1, path,
+        return svn_error_trace(dag_step(node_p, root, here,
+                                        entry_buffer->data, path,
                                         change_set, scratch_pool));
     }
 
-  /* Now there is something to iterate over.  Thus, create the ITERPOOL. */
+  /* Now there is something to iterate over. Thus, create the ITERPOOL. */
   iterpool = svn_pool_create(scratch_pool);
 
   /* Make a parent_path item for the root node, using its own current
@@ -965,30 +1052,15 @@ walk_dag_path(dag_node_t **node_p,
   /* Whenever we are at the top of this loop:
      - HERE is our current directory,
      - REST is the path we're going to find in HERE. */
-  for (rest = path->data; rest; rest = next)
+  for (entry = next_entry_name(path, entry_buffer);
+       entry;
+       entry = next_entry_name(path, entry_buffer))
     {
       svn_pool_clear(iterpool);
 
-      /* Parse out the next entry from the path.  */
-      entry = svn_fs__next_entry_name(&next, rest, iterpool);
-
-      /* Update the path traversed thus far. */
-      if (path->len)
-        ++path->len;
-      path->len += strlen(entry);
-
-      /* Given the behavior of svn_fs__next_entry_name(), ENTRY may be an
-         empty string when the path either starts or ends with a slash.
-         In either case, we stay put: the current directory stays the
-         same, and we add nothing to the parent path.  We only need to
-         process non-empty path segments.
-
-         Also note that HERE is allocated from the DAG node cache and will
-         therefore survive the ITERPOOL cleanup.
-      */
-      if (*entry != '\0')
-        SVN_ERR(dag_step(&here, root, here, entry, path, change_set,
-                         iterpool));
+      /* Note that HERE is allocated from the DAG node cache and will
+         therefore survive the ITERPOOL cleanup. */
+      SVN_ERR(dag_step(&here, root, here, entry, path, change_set, iterpool));
     }
 
   svn_pool_destroy(iterpool);



Mime
View raw message