You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/08/14 16:21:50 UTC

svn commit: r1695924 - /subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c

Author: stefan2
Date: Fri Aug 14 14:21:49 2015
New Revision: 1695924

URL: http://svn.apache.org/r1695924
Log:
On the svn-mergeinfo-normalizer branch:
Continue documentation effort. No functional change.

* tools/client-side/svn-mergeinfo-normalizer/log.c
  (): Add docstrings and commentary.

Modified:
    subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c

Modified: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c?rev=1695924&r1=1695923&r2=1695924&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c Fri Aug 14 14:21:49 2015
@@ -40,36 +40,64 @@
 #include "svn_private_config.h"
 
 
-/*** Code. ***/
 
+/* Describes all changes of a single revision.
+ * Note that all strings are shared within a given svn_min__log_t instance.
+ */
 typedef struct log_entry_t
 {
+  /* Revision being described. */
   svn_revnum_t revision;
+
+  /* FS path that is equal or a parent of any in PATHS. */
   const char *common_base;
+
+  /* Sorted list of all FS paths touched. Elements are const char*. */
   apr_array_header_t *paths;
 } log_entry_t;
 
+/* Describes a deletion.
+ * Note that replacements are treated as additions + deletions.
+ */
 typedef struct deletion_t
 {
+  /* Path being deleted (or replaced). */
   const char *path;
+
+  /* Revision in which this deletion happened.*/
   svn_revnum_t revision;
 } deletion_t;
 
+/* Note that all FS paths are internalized and shared within this object.
+ */
 struct svn_min__log_t
 {
+  /* Dictionary of all FS paths used in this log. */
   apr_hash_t *unique_paths;
 
+  /* Oldest revision we received. */
   svn_revnum_t first_rev;
+
+  /* Latest revision we received. */
   svn_revnum_t head_rev;
+
+  /* Log contents we received.  Entries are log_entry_t *. */
   apr_array_header_t *entries;
 
+  /* List of all copy operations we encountered, sorted by target&rev. */
   apr_array_header_t *copies;
+
+  /* Like COPIES but sorted by source&source-rev. */
   apr_array_header_t *copies_by_source;
+
+  /* List of all deletions we encountered, sorted by path&rev. */
   apr_array_header_t *deletions;
 
+  /* If set, don't show progress nor summary. */
   svn_boolean_t quiet;
 };
 
+/* Comparison function defining the order in svn_min__log_t.COPIES. */
 static int
 copy_order(const void *lhs,
            const void *rhs)
@@ -87,6 +115,8 @@ copy_order(const void *lhs,
   return lhs_copy->revision == rhs_copy->revision ? 0 : 1;
 }
 
+/* Comparison function defining the order in svn_min__log_t.COPIES_BY_SOURCE.
+ */
 static int
 copy_by_source_order(const void *lhs,
                      const void *rhs)
@@ -104,6 +134,7 @@ copy_by_source_order(const void *lhs,
   return lhs_copy->copyfrom_revision == rhs_copy->copyfrom_revision ? 0 : 1;
 }
 
+/* Comparison function defining the order in svn_min__log_t.DELETIONS. */
 static int
 deletion_order(const void *lhs,
                const void *rhs)
@@ -121,6 +152,8 @@ deletion_order(const void *lhs,
   return lhs_deletion->revision == rhs_deletion->revision ? 0 : 1;
 }
 
+/* Return the string stored in UNIQUE_PATHS with the value PATH of PATH_LEN
+ * characters.  If the hash does not have a matching entry, add one. */
 static const char *
 internalize(apr_hash_t *unique_paths,
             const char *path,
@@ -137,6 +170,8 @@ internalize(apr_hash_t *unique_paths,
   return result;
 }
 
+/* Implements svn_log_entry_receiver_t.  Copies the info of LOG_ENTRY into
+ * (svn_min__log_t *)BATON. */
 static svn_error_t *
 log_entry_receiver(void *baton,
                    svn_log_entry_t *log_entry,
@@ -149,9 +184,11 @@ log_entry_receiver(void *baton,
   const char *common_base;
   int count;
 
+  /* Don't care about empty revisions. Skip them. */
   if (!log_entry->changed_paths || !apr_hash_count(log_entry->changed_paths))
     return SVN_NO_ERROR;
 
+  /* Copy changed paths list. Collect deletions and copies. */
   entry = apr_pcalloc(result_pool, sizeof(*entry));
   entry->revision = log_entry->revision;
   entry->paths = apr_array_make(result_pool,
@@ -191,6 +228,7 @@ log_entry_receiver(void *baton,
         }
     }
 
+  /* Determine the common base of all changed paths. */
   count = entry->paths->nelts;
   if (count == 1)
     {
@@ -208,12 +246,15 @@ log_entry_receiver(void *baton,
                                        strlen(common_base));
     }
 
+  /* Done with that reivison. */
   APR_ARRAY_PUSH(log->entries, log_entry_t *) = entry;
 
+  /* Update log-global state. */
   log->first_rev = log_entry->revision;
   if (log->head_rev == SVN_INVALID_REVNUM)
     log->head_rev = log_entry->revision;
 
+  /* Show progress. */
   if (log->entries->nelts % 1000 == 0 && !log->quiet)
     {
       SVN_ERR(svn_cmdline_printf(scratch_pool, "."));
@@ -223,6 +264,8 @@ log_entry_receiver(void *baton,
   return SVN_NO_ERROR;
 }
 
+/* Print some statistics about LOG to console. Use SCRATCH_POOL for
+ * temporary allocations. */
 static svn_error_t *
 print_log_stats(svn_min__log_t *log,
                 apr_pool_t *scratch_pool)
@@ -251,7 +294,6 @@ print_log_stats(svn_min__log_t *log,
   return SVN_NO_ERROR;
 }
 
-/* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
 svn_min__log(svn_min__log_t **log,
              const char *url,
@@ -262,6 +304,9 @@ svn_min__log(svn_min__log_t **log,
   svn_client_ctx_t *ctx = baton->ctx;
   svn_min__log_t *result;
 
+  /* Prepare API parameters for fetching the full log for URL,
+   * including changed paths, excluding revprops.
+   */
   apr_array_header_t *targets;
   apr_array_header_t *revisions;
   apr_array_header_t *revprops;
@@ -277,6 +322,7 @@ svn_min__log(svn_min__log_t **log,
 
   revprops = apr_array_make(scratch_pool, 0, sizeof(const char *));
 
+  /* The log objec to fill. */
   result = apr_pcalloc(result_pool, sizeof(*result));
   result->unique_paths = svn_hash__make(scratch_pool);
   result->first_rev = SVN_INVALID_REVNUM;
@@ -308,6 +354,7 @@ svn_min__log(svn_min__log_t **log,
                           ctx,
                           scratch_pool));
 
+  /* Complete arrays in RESULT. */
   result->copies_by_source = apr_array_copy(result_pool, result->copies);
 
   svn_sort__array_reverse(result->entries, scratch_pool);
@@ -315,6 +362,7 @@ svn_min__log(svn_min__log_t **log,
   svn_sort__array(result->copies_by_source, copy_by_source_order);
   svn_sort__array(result->deletions, deletion_order);
 
+  /* Show that we are done. */
   if (!baton->opt_state->quiet)
     {
       SVN_ERR(svn_cmdline_printf(scratch_pool, "\n"));
@@ -327,11 +375,14 @@ svn_min__log(svn_min__log_t **log,
   return SVN_NO_ERROR;
 }
 
+/* Append REVISION with the INHERITABLE setting to RANGES.  RANGES must be
+ * sorted and REVISION must be larger than the largest revision in RANGES. */
 static void
 append_rev_to_ranges(svn_rangelist_t *ranges,
                      svn_revnum_t revision,
                      svn_boolean_t inheritable)
 {
+  /* In many cases, we can save memory by simply extending the last range. */
   svn_merge_range_t *range;
   if (ranges->nelts)
     {
@@ -343,6 +394,7 @@ append_rev_to_ranges(svn_rangelist_t *ra
         }
     }
 
+  /* We need to add a new range. */
   range = apr_pcalloc(ranges->pool, sizeof(*range));
   range->start = revision - 1;
   range->end = revision;
@@ -351,6 +403,9 @@ append_rev_to_ranges(svn_rangelist_t *ra
   APR_ARRAY_PUSH(ranges, svn_merge_range_t *) = range;
 }
 
+/* Comparison function comparing the log_entry_t * in *LHS with the
+ * svn_revnum_t in *rhs.
+ */
 static int
 compare_rev_log_entry(const void *lhs,
                       const void *rhs)
@@ -364,11 +419,14 @@ compare_rev_log_entry(const void *lhs,
   return entry->revision == revision ? 0 : 1;
 }
 
+/* Restrict RANGE to the range of revisions covered by LOG. Cut-off from
+ * both sides will be added to RANGES. */
 static void
 restrict_range(svn_min__log_t *log,
                svn_merge_range_t *range,
                svn_rangelist_t *ranges)
 {
+  /* Cut off at the earliest revision. */
   if (range->start + 1 < log->first_rev)
     {
       svn_merge_range_t *new_range
@@ -379,6 +437,7 @@ restrict_range(svn_min__log_t *log,
       range->start = new_range->end;
     }
 
+  /* Cut off at log HEAD. */
   if (range->end > log->head_rev)
     {
       svn_merge_range_t *new_range
@@ -390,6 +449,8 @@ restrict_range(svn_min__log_t *log,
     }
 }
 
+/* Return TRUE if PATH is either equal to, a parent of or sub-path of
+ * CHANGED_PATH. */
 static svn_boolean_t
 is_relevant(const char *changed_path,
             const char *path)
@@ -398,6 +459,9 @@ is_relevant(const char *changed_path,
        || svn_dirent_is_ancestor(path, changed_path);
 }
 
+/* Return TRUE if PATH is either equal to, a parent of or sub-path of
+ * SUB_TREE.  Ignore BATON but keep it for a unified signature to be
+ * used with filter_ranges. */
 static svn_boolean_t
 in_subtree(const char *changed_path,
            const char *sub_tree,
@@ -406,6 +470,9 @@ in_subtree(const char *changed_path,
   return svn_dirent_is_ancestor(sub_tree, changed_path);
 }
 
+/* Return TRUE if
+ * - CHANGED_PATH is is either equal to or a sub-node of PATH, and
+ * - CHNAGED_PATH is outside the sub-tree given as BATON. */
 static svn_boolean_t
 below_path_outside_subtree(const char *changed_path,
                            const char *path,
@@ -419,6 +486,10 @@ below_path_outside_subtree(const char *c
         && strcmp(path, changed_path);
 }
 
+/* In LOG, scan the revisions given in RANGES and return the revision /
+ * ranges that are relevant to PATH with respect to the PATH_RELEVANT
+ * criterion using BATON.  Keep revisions that lie outside what is covered
+ * by LOG. Allocate the result in RESULT_POOL. */
 static svn_rangelist_t *
 filter_ranges(svn_min__log_t *log,
               const char *path,
@@ -431,16 +502,19 @@ filter_ranges(svn_min__log_t *log,
   svn_rangelist_t *result;
   int i, k, l;
 
+  /* Auto-complete parameters. */
   if (!SVN_IS_VALID_REVNUM(log->first_rev))
     return svn_rangelist_dup(ranges, result_pool);
 
   result = apr_array_make(result_pool, 0, ranges->elt_size);
   for (i = 0; i < ranges->nelts; ++i)
     {
+      /* Next revision range to scan. */
       svn_merge_range_t range
         = *APR_ARRAY_IDX(ranges, i, const svn_merge_range_t *);
       restrict_range(log, &range, result);
 
+      /* Find the range start and scan the range linearly. */
       ++range.start;
       for (k = svn_sort__bsearch_lower_bound(log->entries, &range.start,
                                              compare_rev_log_entry);
@@ -452,15 +526,16 @@ filter_ranges(svn_min__log_t *log,
           if (entry->revision > range.end)
             break;
 
+          /* Skip revisions no relevant to PATH. */
           if (!is_relevant(entry->common_base, path))
             continue;
 
+          /* Look for any changed path that meets the filter criterion. */
           for (l = 0; l < entry->paths->nelts; ++l)
             {
               const char *changed_path
                 = APR_ARRAY_IDX(entry->paths, l, const char *);
 
-              /* Is this a change _below_ PATH but not within SUBTREE? */
               if (path_relavent(changed_path, path, baton))
                 {
                   append_rev_to_ranges(result, entry->revision,
@@ -507,9 +582,12 @@ svn_min__find_deletion(svn_min__log_t *l
   to_find->path = path;
   to_find->revision = end_rev;
 
+  /* Auto-complete parameters. */
   if (!SVN_IS_VALID_REVNUM(start_rev))
     start_rev = log->head_rev;
 
+  /* Walk up the tree and find the latest deletion of PATH or any of
+   * its parents. */
   while (!svn_fspath__is_root(to_find->path, strlen(to_find->path)))
     {
       int i;
@@ -549,6 +627,7 @@ svn_min__find_deletions(svn_min__log_t *
   to_find->path = path;
   to_find->revision = 0;
 
+  /* Find deletions for PATH and its parents. */
   if (!svn_fspath__is_root(to_find->path, strlen(to_find->path)))
     {
       int i;
@@ -568,6 +647,7 @@ svn_min__find_deletions(svn_min__log_t *
       to_find->path = svn_fspath__dirname(to_find->path, scratch_pool);
     }
 
+  /* Remove any duplicates (unlikely but possible). */
   svn_sort__array(result, svn_sort_compare_revisions);
   for (source = 1, dest = 0; source < result->nelts; ++source)
     {
@@ -586,13 +666,10 @@ svn_min__find_deletions(svn_min__log_t *
   return result;
 }
 
-typedef struct segment_t
-{
-  const char *path;
-  svn_revnum_t start;
-  svn_revnum_t end;
-} segment_t;
-
+/* Starting at REVISION, scan LOG for the next (in REVISION or older) copy
+ * that creates PATH explicitly or implicitly by creating a parent of it.
+ * Return the copy operation found or NULL if none exists.  Use SCRATCH_POOL
+ * for temporary allocations. */
 static const svn_min__copy_t *
 next_copy(svn_min__log_t *log,
           const char *path,
@@ -605,7 +682,7 @@ next_copy(svn_min__log_t *log,
   svn_min__copy_t *to_find = apr_pcalloc(scratch_pool, sizeof(*to_find));
   to_find->path = path;
   to_find->revision = revision;
- 
+
   idx = svn_sort__bsearch_lower_bound(log->copies, &to_find, copy_order);
   if (idx < log->copies->nelts)
     {
@@ -649,9 +726,11 @@ svn_min__find_copy(svn_min__log_t *log,
 {
   const svn_min__copy_t *copy;
 
+  /* Auto-complete parameters. */
   if (!SVN_IS_VALID_REVNUM(start_rev))
     start_rev = log->head_rev;
 
+  /* The actual lookup. */
   copy = next_copy(log, path, start_rev, scratch_pool);
   if (copy && copy->revision >= end_rev)
     return copy->revision;
@@ -710,6 +789,21 @@ svn_min__get_copies(svn_min__log_t *log,
   return result;
 }
 
+/* A history segment.  Simply a FS path plus the revision range that it is
+ * part of the history of the node. */
+typedef struct segment_t
+{
+  /* FS path at which the node lives in this segment */
+  const char *path;
+
+  /* Revision that it appears in or that the history was truncated to. */
+  svn_revnum_t start;
+
+  /* Revision from which the node was copied to the next segment or the
+   * revision that the history was truncated to. */
+  svn_revnum_t end;
+} segment_t;
+
 apr_array_header_t *
 svn_min__get_history(svn_min__log_t *log,
                      const char *path,
@@ -723,9 +817,12 @@ svn_min__get_history(svn_min__log_t *log
   apr_array_header_t *result = apr_array_make(result_pool, 16,
                                               sizeof(segment_t *));
 
+  /* Auto-complete parameters. */
   if (!SVN_IS_VALID_REVNUM(start_rev))
     start_rev = log->head_rev;
 
+  /* Simply follow all copies, each time adding a segment from "here" to
+   * the next copy. */
   for (copy = next_copy(log, path, start_rev, scratch_pool);
        copy && start_rev >= end_rev;
        copy = next_copy(log, path, start_rev, scratch_pool))
@@ -743,6 +840,7 @@ svn_min__get_history(svn_min__log_t *log
                               scratch_pool);
     }
 
+  /* The final segment has no copy-from. */
   if (start_rev >= end_rev)
     {
       segment = apr_pcalloc(result_pool, sizeof(*segment));