Author: stefan2
Date: Sat Apr 27 20:13:50 2013
New Revision: 1476663

URL: http://svn.apache.org/r1476663
Log:
On the fsfs-format7 branch: extend fs_verify for format7 repos to check
L2P and P2L indexes for mutual consistency.

* subversion/include/svn_error_codes.h
  (SVN_ERR_FS_ITEM_INDEX_INCONSISTENT): new error code

* subversion/libsvn_fs_fs/fs_fs.c
  (verify_rep_cache): factor out from svn_fs_fs__verify
  (compare_l2p_to_p2l_index,
   compare_p2l_to_l2p_index,
   verify_index_consistency): implement two-way index consistency check
  (svn_fs_fs__verify): update

Modified:
    subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h
    subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c

Modified: subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h?rev=1476663&r1=1476662&r2=1476663&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h 
(original)
+++ subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h Sat 
Apr 27 20:13:50 2013
@@ -822,6 +822,11 @@ SVN_ERROR_START
              SVN_ERR_FS_CATEGORY_START + 57,
              "Container index out of range.")
 
+  /** @since New in 1.9. */
+  SVN_ERRDEF(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+             SVN_ERR_FS_CATEGORY_START + 58,
+             "Index files are inconsistent.")
+
   /* repos errors */
 
   SVN_ERRDEF(SVN_ERR_REPOS_LOCKED,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c?rev=1476663&r1=1476662&r2=1476663&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c Sat Apr 27 
20:13:50 2013
@@ -36,6 +36,7 @@
 #include "transaction.h"
 #include "tree.h"
 #include "util.h"
+#include "index.h"
 
 #include "private/svn_fs_util.h"
 #include "private/svn_string_private.h"
@@ -1402,30 +1403,23 @@ verify_walker(representation_t *rep,
   return SVN_NO_ERROR;
 }
 
+/* Verify the rep cache DB's consistency with our rev / pack data.
+ * The function signature is similar to svn_fs_fs__verify.
+ * The values of START and END have already been auto-selected and
+ * verified.
+ */
 svn_error_t *
-svn_fs_fs__verify(svn_fs_t *fs,
-                  svn_revnum_t start,
-                  svn_revnum_t end,
-                  svn_fs_progress_notify_func_t notify_func,
-                  void *notify_baton,
-                  svn_cancel_func_t cancel_func,
-                  void *cancel_baton,
-                  apr_pool_t *pool)
+verify_rep_cache(svn_fs_t *fs,
+                 svn_revnum_t start,
+                 svn_revnum_t end,
+                 svn_fs_progress_notify_func_t notify_func,
+                 void *notify_baton,
+                 svn_cancel_func_t cancel_func,
+                 void *cancel_baton,
+                 apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_boolean_t exists;
-  svn_revnum_t youngest = ffd->youngest_rev_cache; /* cache is current */
-
-  if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT)
-    return SVN_NO_ERROR;
-
-  /* Input validation. */
-  if (! SVN_IS_VALID_REVNUM(start))
-    start = 0;
-  if (! SVN_IS_VALID_REVNUM(end))
-    end = youngest;
-  SVN_ERR(ensure_revision_exists(fs, start, pool));
-  SVN_ERR(ensure_revision_exists(fs, end, pool));
 
   /* rep-cache verification. */
   SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, fs, pool));
@@ -1457,3 +1451,247 @@ svn_fs_fs__verify(svn_fs_t *fs,
 
   return SVN_NO_ERROR;
 }
+
+/* Verify that for all log-to-phys index entries for revisions START to
+ * START + COUNT-1 in FS there is a consistent entry in the phys-to-log
+ * index.  If given, invoke CANCEL_FUNC with CANCEL_BATON at regular
+ * intervals. Use POOL for allocations.
+ */
+svn_error_t *
+compare_l2p_to_p2l_index(svn_fs_t *fs,
+                         svn_revnum_t start,
+                         svn_revnum_t count,
+                         svn_cancel_func_t cancel_func,
+                         void *cancel_baton,
+                         apr_pool_t *pool)
+{
+  svn_revnum_t i;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_array_header_t *max_ids;
+
+  /* determine the range of items to check for each revision */
+  SVN_ERR(svn_fs_fs__l2p_get_max_ids(&max_ids, fs, start, count, pool));
+
+  /* check all items in all revisions if the given range */
+  for (i = 0; i < max_ids->nelts; ++i)
+    {
+      apr_uint64_t k;
+      apr_uint64_t max_id = APR_ARRAY_IDX(max_ids, i, apr_uint64_t);
+      svn_revnum_t revision = start + i;
+
+      for (k = 0; k < max_id; ++k)
+        {
+          apr_off_t offset;
+          apr_uint32_t sub_item;
+          svn_fs_fs__id_part_t *p2l_item;
+
+          /* get L2P entry.  Ignore unused entries. */
+          SVN_ERR(svn_fs_fs__item_offset(&offset, &sub_item, fs,
+                                         revision, NULL, k, iterpool));
+          if (offset == -1)
+            continue;
+
+          /* find the corresponding P2L entry */
+          SVN_ERR(svn_fs_fs__p2l_item_lookup(&p2l_item, fs, start,
+                                             offset, sub_item, iterpool));
+
+          if (p2l_item == NULL)
+            return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+                                      NULL,
+                                      _("p2l index entry not found for "
+                                        "PHYS o%" APR_OFF_T_FMT ":s%ld "
+                                        "returned by l2p index for LOG "
+                                        "r%ld:i%" APR_UINT64_T_FMT),
+                                      offset, (long)sub_item, k, revision);
+
+          if (p2l_item->number != k || p2l_item->revision != revision)
+            return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+                                      NULL,
+                                      _("p2l index info LOG r%ld:i%"
+                                        APR_UINT64_T_FMT " does not match "
+                                        "l2p index for LOG r%ld:i%"
+                                        APR_UINT64_T_FMT),
+                                      p2l_item->revision,
+                                      (long)p2l_item->number, revision, k);
+
+          svn_pool_clear(iterpool);
+        }
+
+      if (cancel_func)
+        SVN_ERR(cancel_func(cancel_baton));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Verify that for all phys-to-log index entries for revisions START to
+ * START + COUNT-1 in FS there is a consistent entry in the log-to-phys
+ * index.  If given, invoke CANCEL_FUNC with CANCEL_BATON at regular
+ * intervals. Use POOL for allocations.
+ *
+ * Please note that we can only check on pack / rev file granularity and
+ * must only be called for a single rev / pack file.
+ */
+svn_error_t *
+compare_p2l_to_l2p_index(svn_fs_t *fs,
+                         svn_revnum_t start,
+                         svn_revnum_t count,
+                         svn_cancel_func_t cancel_func,
+                         void *cancel_baton,
+                         apr_pool_t *pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_array_header_t *max_ids;
+  apr_off_t max_offset;
+  apr_off_t offset = 0;
+
+  /* get the size of the rev / pack file as covered by the P2L index */
+  SVN_ERR(svn_fs_fs__p2l_get_max_offset(&max_offset, fs, start, pool));
+
+  /* for all offsets in the file, get the P2L index entries and check
+     them against the L2P index */
+  for (offset = 0; offset < max_offset; )
+    {
+      apr_array_header_t *entries;
+      svn_fs_fs__p2l_entry_t *last_entry;
+      int i;
+
+      /* get all entries for the current block */
+      SVN_ERR(svn_fs_fs__p2l_index_lookup(&entries, fs, start, offset,
+                                          iterpool));
+      if (entries->nelts == 0)
+        return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_CORRUPTION,
+                                 NULL,
+                                 _("p2l does not cover offset " APR_OFF_T_FMT
+                                   " for revision %ld"),
+                                 offset, start);
+
+      /* process all entries (and later continue with the next block) */
+      last_entry
+        = &APR_ARRAY_IDX(entries, entries->nelts-1, svn_fs_fs__p2l_entry_t);
+      offset = last_entry->offset + last_entry->size;
+      
+      for (i = 0; i < entries->nelts; ++i)
+        {
+          apr_uint32_t k;
+          svn_fs_fs__p2l_entry_t *entry
+            = &APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t);
+
+          /* check all sub-items for consist entries in the L2P index */
+          for (k = 0; k < entry->item_count; ++k)
+            {
+              apr_off_t l2p_offset;
+              apr_uint32_t sub_item;
+              svn_fs_fs__id_part_t *p2l_item = &entry->items[k];
+
+              SVN_ERR(svn_fs_fs__item_offset(&l2p_offset, &sub_item, fs,
+                                             p2l_item->revision, NULL,
+                                             p2l_item->number, iterpool));
+
+              if (sub_item != k || l2p_offset != entry->offset)
+                return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+                                         NULL,
+                                         _("l2p index entry PHYS o%"
+                                           APR_OFF_T_FMT ":s%ld does not "
+                                           "match p2l index value LOG r%ld:i%"
+                                           APR_UINT64_T_FMT " for PHYS o%"
+                                           APR_OFF_T_FMT ":s%ld"),
+                                         l2p_offset, (long)sub_item,
+                                         p2l_item->revision, p2l_item->number,
+                                         entry->offset, (long)k);
+            }
+        }
+
+      svn_pool_clear(iterpool);
+
+      if (cancel_func)
+        SVN_ERR(cancel_func(cancel_baton));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Verify that the log-to-phys indexes and phys-to-log indexes are
+ * consistent with each other.  The function signature is similar to
+ * svn_fs_fs__verify.
+ *
+ * The values of START and END have already been auto-selected and
+ * verified.  You may call this for format7 or higher repos.
+ */
+svn_error_t *
+verify_index_consistency(svn_fs_t *fs,
+                         svn_revnum_t start,
+                         svn_revnum_t end,
+                         svn_fs_progress_notify_func_t notify_func,
+                         void *notify_baton,
+                         svn_cancel_func_t cancel_func,
+                         void *cancel_baton,
+                         apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  svn_revnum_t revision, pack_start, pack_end;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+
+  for (revision = start; revision <= end; revision = pack_end)
+    {
+      apr_array_header_t *max_ids;
+      pack_start = packed_base_rev(fs, revision);
+      pack_end = pack_start + pack_size(fs, revision);
+
+      if (notify_func && (pack_start % ffd->max_files_per_dir == 0))
+        notify_func(pack_start, notify_baton, iterpool);
+
+      /* two-way index check */
+      SVN_ERR(compare_l2p_to_p2l_index(fs, pack_start, pack_end - pack_start,
+                                       cancel_func, cancel_baton, iterpool));
+      SVN_ERR(compare_p2l_to_l2p_index(fs, pack_start, pack_end - pack_start,
+                                       cancel_func, cancel_baton, iterpool));
+
+      svn_pool_clear(iterpool);
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__verify(svn_fs_t *fs,
+                  svn_revnum_t start,
+                  svn_revnum_t end,
+                  svn_fs_progress_notify_func_t notify_func,
+                  void *notify_baton,
+                  svn_cancel_func_t cancel_func,
+                  void *cancel_baton,
+                  apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  svn_boolean_t exists;
+  svn_revnum_t youngest = ffd->youngest_rev_cache; /* cache is current */
+
+  /* Input validation. */
+  if (! SVN_IS_VALID_REVNUM(start))
+    start = 0;
+  if (! SVN_IS_VALID_REVNUM(end))
+    end = youngest;
+  SVN_ERR(ensure_revision_exists(fs, start, pool));
+  SVN_ERR(ensure_revision_exists(fs, end, pool));
+
+  /* log/phys index consistency.  We need to check them first to make
+     sure we can access the rev / pack files in format7. */
+  if (ffd->format >= SVN_FS_FS__MIN_LOG_ADDRESSING_FORMAT)
+    SVN_ERR(verify_index_consistency(fs, start, end,
+                                     notify_func, notify_baton,
+                                     cancel_func, cancel_baton, pool));
+
+  /* rep cache consistency */
+  if (ffd->format >= SVN_FS_FS__MIN_REP_SHARING_FORMAT)
+    SVN_ERR(verify_rep_cache(fs, start, end, notify_func, notify_baton,
+                             cancel_func, cancel_baton, pool));
+
+  return SVN_NO_ERROR;
+}


Reply via email to