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 2013/12/25 03:01:25 UTC

svn commit: r1553346 - /subversion/trunk/tools/server-side/fsfs-stats.c

Author: stefan2
Date: Wed Dec 25 02:01:25 2013
New Revision: 1553346

URL: http://svn.apache.org/r1553346
Log:
Add support for format7 repositories to the fsfs-stats tool.

Logically addressed revs are much easier and quicker to process
because the P2L index already contains a list of all noderevs
and change lists to read.  There is no need to read the DAG
recursively anymore (thus, no delta caching necessary etc.)

* tools/server-side/fsfs-stats.c
  (fs_open): Accept format7 repositories as well.
  (parse_representation): Don't read delta base info in log. addressing
                          mode since we can access all items directly
                          instead of discovering them in the DAG.
  (read_noderev): Same here for reading directories recursively.
  (read_pack_file): Rename to ...
  (read_phys_pack_file): ... this.
  (read_revision_file): Rename to ...
  (read_phys_revision_file): ... this.
  (read_item,
   read_log_rev_or_packfile,
   read_log_pack_file,
   read_log_revision_file): New functions to process logically addressed
                            revision contents.
  (read_revisions): Call the appropriate processing functions depending
                    on addressing mode.

Modified:
    subversion/trunk/tools/server-side/fsfs-stats.c

Modified: subversion/trunk/tools/server-side/fsfs-stats.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/server-side/fsfs-stats.c?rev=1553346&r1=1553345&r2=1553346&view=diff
==============================================================================
--- subversion/trunk/tools/server-side/fsfs-stats.c (original)
+++ subversion/trunk/tools/server-side/fsfs-stats.c Wed Dec 25 02:01:25 2013
@@ -44,10 +44,13 @@
 #include "private/svn_dep_compat.h"
 #include "private/svn_cache.h"
 
-#include "../libsvn_fs_fs/fs.h"
-#include "../libsvn_fs_fs/pack.h"
-#include "../libsvn_fs_fs/rev_file.h"
-#include "../libsvn_fs/fs-loader.h"
+#include "../../subversion/libsvn_fs_fs/fs.h"
+#include "../../subversion/libsvn_fs_fs/index.h"
+#include "../../subversion/libsvn_fs_fs/pack.h"
+#include "../../subversion/libsvn_fs_fs/rev_file.h"
+#include "../../subversion/libsvn_fs_fs/util.h"
+
+#include "../../subversion/libsvn_fs/fs-loader.h"
 
 #ifndef _
 #define _(x) x
@@ -629,7 +632,7 @@ fs_open(fs_t **fs, const char *path, apr
 
   /* Check the FS format number. */
   ffd = (*fs)->fs->fsap_data;
-  if ((ffd->format != 4) && (ffd->format != 6))
+  if ((ffd->format != 4) && (ffd->format != 6) && (ffd->format != 7))
     return svn_error_create(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL, NULL);
 
   return SVN_NO_ERROR;
@@ -816,13 +819,18 @@ parse_representation(rep_stats_t **repre
       result->expanded_size = (apr_size_t)(expanded_size ? expanded_size : size);
       result->offset = (apr_size_t)offset;
       result->size = (apr_size_t)size;
-      SVN_ERR(read_rep_base(&result->delta_base, &header_size,
-                            &is_plain, fs, file_content,
-                            (apr_size_t)offset,
-                            pool, scratch_pool));
 
-      result->header_size = header_size;
-      result->is_plain = is_plain;
+      if (!svn_fs_fs__use_log_addressing(fs->fs, revision))
+        {
+          SVN_ERR(read_rep_base(&result->delta_base, &header_size,
+                                &is_plain, fs, file_content,
+                                (apr_size_t)offset,
+                                pool, scratch_pool));
+
+          result->header_size = header_size;
+          result->is_plain = is_plain;
+        }
+
       svn_sort__array_insert(&result, revision_info->representations, idx);
     }
 
@@ -1184,7 +1192,8 @@ read_noderev(fs_t *fs,
 
   /* if this is a directory and has not been processed, yet, read and
    * process it recursively */
-  if (is_dir && text && text->ref_count == 1)
+  if (   is_dir && text && text->ref_count == 1
+      && !svn_fs_fs__use_log_addressing(fs->fs, revision_info->revision))
     SVN_ERR(parse_dir(fs, file_content, text, revision_info,
                       pool, scratch_pool));
 
@@ -1232,13 +1241,13 @@ print_progress(svn_revnum_t revision)
   fflush(stdout);
 }
 
-/* Read the content of the pack file staring at revision BASE and store it
- * in FS.  Use POOL for allocations.
+/* Read the content of the pack file staring at revision BASE physical
+ * addressing mode and store it in FS.  Use POOL for allocations.
  */
 static svn_error_t *
-read_pack_file(fs_t *fs,
-               svn_revnum_t base,
-               apr_pool_t *pool)
+read_phys_pack_file(fs_t *fs,
+                    svn_revnum_t base,
+                    apr_pool_t *pool)
 {
   apr_pool_t *local_pool = svn_pool_create(pool);
   apr_pool_t *iter_pool = svn_pool_create(local_pool);
@@ -1300,13 +1309,13 @@ read_pack_file(fs_t *fs,
   return SVN_NO_ERROR;
 }
 
-/* Read the content of the file for REVSION and store its contents in FS.
- * Use POOL for allocations.
+/* Read the content of the file for REVISION in physical addressing mode
+ * and store its contents in FS.  Use POOL for allocations.
  */
 static svn_error_t *
-read_revision_file(fs_t *fs,
-                   svn_revnum_t revision,
-                   apr_pool_t *pool)
+read_phys_revision_file(fs_t *fs,
+                        svn_revnum_t revision,
+                        apr_pool_t *pool)
 {
   apr_size_t root_node_offset;
   apr_pool_t *local_pool = svn_pool_create(pool);
@@ -1357,6 +1366,160 @@ read_revision_file(fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* Read the item described by ENTRY from the REV_FILE in FS and return
+ * the respective byte sequence in *CONTENTS allocated in POOL.
+ */
+static svn_error_t *
+read_item(svn_stringbuf_t **contents,
+          fs_t *fs,
+          svn_fs_fs__revision_file_t *rev_file,
+          svn_fs_fs__p2l_entry_t *entry,
+          apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fs->fsap_data;
+
+  svn_stringbuf_t *item = svn_stringbuf_create_ensure(entry->size, pool);
+  item->len = entry->size;
+  item->data[item->len] = 0;
+
+  SVN_ERR(svn_io_file_aligned_seek(rev_file->file, ffd->block_size, NULL,
+                                   entry->offset, pool));
+  SVN_ERR(svn_io_file_read_full2(rev_file->file, item->data, item->len,
+                                 NULL, NULL, pool));
+
+  *contents = item;
+
+  return SVN_NO_ERROR;
+}
+
+/* Process the logically addressed revision contents of revisions BASE to
+ * BASE + COUNT - 1 in FS.  Use POOL for allocations.
+ */
+static svn_error_t *
+read_log_rev_or_packfile(fs_t *fs,
+                         svn_revnum_t base,
+                         int count,
+                         apr_pool_t *pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_pool_t *localpool = svn_pool_create(pool);
+  apr_off_t max_offset;
+  apr_off_t offset = 0;
+  int i;
+  svn_fs_fs__revision_file_t *rev_file;
+
+  /* we will process every revision in the rev / pack file */
+  for (i = 0; i < count; ++i)
+    {
+      /* create the revision info for the current rev */
+      revision_info_t *info = apr_pcalloc(pool, sizeof(*info));
+      info->representations = apr_array_make(pool, 4, sizeof(rep_stats_t*));
+      info->revision = base + i;
+
+      APR_ARRAY_PUSH(fs->revisions, revision_info_t*) = info;
+    }
+
+  /* open the pack / rev file that is covered by the p2l index */
+  SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs->fs, base,
+                                           localpool));
+  SVN_ERR(svn_fs_fs__p2l_get_max_offset(&max_offset, fs->fs, rev_file,
+                                        base, localpool));
+
+  /* record the whole pack size in the first rev so the total sum will
+     still be correct */
+  APR_ARRAY_IDX(fs->revisions, base, revision_info_t*)->end = max_offset;
+
+  /* for all offsets in the file, get the P2L index entries and process
+     the interesting items (change lists, noderevs) */
+  for (offset = 0; offset < max_offset; )
+    {
+      apr_array_header_t *entries;
+
+      svn_pool_clear(iterpool);
+
+      /* get all entries for the current block */
+      SVN_ERR(svn_fs_fs__p2l_index_lookup(&entries, fs->fs, rev_file, base,
+                                          offset, iterpool));
+
+      /* process all entries (and later continue with the next block) */
+      for (i = 0; i < entries->nelts; ++i)
+        {
+          svn_fs_fs__p2l_entry_t *entry
+            = &APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t);
+          revision_info_t *info = APR_ARRAY_IDX(fs->revisions,
+                                                entry->item.revision,
+                                                revision_info_t*);
+
+          /* skip bits we previously processed */
+          if (i == 0 && entry->offset < offset)
+            continue;
+
+          /* skip zero-sized entries */
+          if (entry->size == 0)
+            continue;
+
+          /* read and process interesting items */
+          if (entry->type == SVN_FS_FS__ITEM_TYPE_NODEREV)
+            {
+              svn_stringbuf_t *item;
+              SVN_ERR(read_item(&item, fs, rev_file, entry, iterpool));
+              SVN_ERR(read_noderev(fs, item, 0, info, pool, iterpool));
+            }
+          else if (entry->type == SVN_FS_FS__ITEM_TYPE_CHANGES)
+            {
+              svn_stringbuf_t *item;
+              SVN_ERR(read_item(&item, fs, rev_file, entry, iterpool));
+              info->change_count
+                = get_change_count(item->data + 0, item->len);
+            }
+
+          /* advance offset */
+          offset += entry->size;
+        }
+    }
+
+  /* clean up and close file handles */
+  svn_pool_destroy(iterpool);
+  svn_pool_destroy(localpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Read the content of the pack file staring at revision BASE logical
+ * addressing mode and store it in FS.  Use POOL for allocations.
+ */
+static svn_error_t *
+read_log_pack_file(fs_t *fs,
+                   svn_revnum_t base,
+                   apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fs->fsap_data;
+  SVN_ERR(read_log_rev_or_packfile(fs, base, ffd->max_files_per_dir, pool));
+
+  /* one more pack file processed */
+  print_progress(base);
+
+  return SVN_NO_ERROR;
+}
+
+/* Read the content of the file for REVISION in logical addressing mode
+ * and store its contents in FS.  Use POOL for allocations.
+ */
+static svn_error_t *
+read_log_revision_file(fs_t *fs,
+                       svn_revnum_t revision,
+                       apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fs->fsap_data;
+  SVN_ERR(read_log_rev_or_packfile(fs, revision, 1, pool));
+
+  /* show progress every 1000 revs or so */
+  if (revision % ffd->max_files_per_dir == 0)
+    print_progress(revision);
+
+  return SVN_NO_ERROR;
+}
+
 /* Read the repository at PATH beginning with revision START_REVISION and
  * return the result in *FS.  Allocate caches with MEMSIZE bytes total
  * capacity.  Use POOL for non-cache allocations.
@@ -1403,11 +1566,17 @@ read_revisions(fs_t **fs,
   for ( revision = start_revision
       ; revision < ffd->min_unpacked_rev
       ; revision += ffd->max_files_per_dir)
-    SVN_ERR(read_pack_file(*fs, revision, pool));
+    if (svn_fs_fs__use_log_addressing((*fs)->fs, revision))
+      SVN_ERR(read_log_pack_file(*fs, revision, pool));
+    else
+      SVN_ERR(read_phys_pack_file(*fs, revision, pool));
 
   /* read non-packed revs */
   for ( ; revision <= ffd->youngest_rev_cache; ++revision)
-    SVN_ERR(read_revision_file(*fs, revision, pool));
+    if (svn_fs_fs__use_log_addressing((*fs)->fs, revision))
+      SVN_ERR(read_log_revision_file(*fs, revision, pool));
+    else
+      SVN_ERR(read_phys_revision_file(*fs, revision, pool));
 
   return SVN_NO_ERROR;
 }