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 2014/04/03 21:47:25 UTC

svn commit: r1584356 - in /subversion/trunk/subversion/libsvn_fs_fs: index.c index.h transaction.c

Author: stefan2
Date: Thu Apr  3 19:47:24 2014
New Revision: 1584356

URL: http://svn.apache.org/r1584356
Log:
Ensure consistency between proto rev and proto index files in FSFS f7
after a write operation to the transaction crashed.

Bottom line here is that the proto rev file may contain extra (garbage)
data that is not being referenced by anybody.

* subversion/libsvn_fs_fs/index.h
  (svn_fs_fs__p2l_proto_index_next_offset): Add private API to retrieve
                                            the expected length of the
                                            proto-rev file.

* subversion/libsvn_fs_fs/index.c
  (svn_fs_fs__p2l_proto_index_next_offset): Implement.

* subversion/libsvn_fs_fs/transaction.c
  (auto_truncate_proto_rev): New function matching the actual proto-rev
                             file size with the value expected as per
                             proto-index.
  (get_writable_proto_rev): Call the new function whenever we open the
                            proto-rev file.

Modified:
    subversion/trunk/subversion/libsvn_fs_fs/index.c
    subversion/trunk/subversion/libsvn_fs_fs/index.h
    subversion/trunk/subversion/libsvn_fs_fs/transaction.c

Modified: subversion/trunk/subversion/libsvn_fs_fs/index.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/index.c?rev=1584356&r1=1584355&r2=1584356&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/index.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/index.c Thu Apr  3 19:47:24 2014
@@ -1600,6 +1600,36 @@ svn_fs_fs__p2l_proto_index_add_entry(apr
 }
 
 svn_error_t *
+svn_fs_fs__p2l_proto_index_next_offset(apr_off_t *next_offset,
+                                       apr_file_t *proto_index,
+                                       apr_pool_t *pool)
+{
+  apr_off_t offset = 0;
+
+  /* Empty index file? */
+  SVN_ERR(svn_io_file_seek(proto_index, APR_END, &offset, pool));
+  if (offset == 0)
+    {
+      *next_offset = 0;
+    }
+  else
+    {
+      /* At least one entry.  Read last entry. */
+      svn_fs_fs__p2l_entry_t entry;
+      offset -= sizeof(entry);
+
+      SVN_ERR(svn_io_file_seek(proto_index, APR_SET, &offset, pool));
+      SVN_ERR(svn_io_file_read_full2(proto_index, &entry, sizeof(entry),
+                                    NULL, NULL, pool));
+
+      /* Return next offset. */
+      *next_offset = entry.offset + entry.size;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_fs_fs__p2l_index_create(svn_fs_t *fs,
                             const char *file_name,
                             const char *proto_file_name,

Modified: subversion/trunk/subversion/libsvn_fs_fs/index.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/index.h?rev=1584356&r1=1584355&r2=1584356&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/index.h (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/index.h Thu Apr  3 19:47:24 2014
@@ -136,6 +136,15 @@ svn_fs_fs__p2l_proto_index_add_entry(apr
                                      svn_fs_fs__p2l_entry_t *entry,
                                      apr_pool_t *pool);
 
+/* Set *NEXT_OFFSET to the first offset behind the last entry in the
+ * phys-to-log proto index file PROTO_INDEX.  This will be 0 for empty
+ * index files.  Use POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__p2l_proto_index_next_offset(apr_off_t *next_offset,
+                                       apr_file_t *proto_index,
+                                       apr_pool_t *pool);
+
 /* Use the proto index file stored at PROTO_FILE_NAME and construct the
  * final phys-to-log index file at FILE_NAME.  Entries without a valid
  * revision will be assigned to the REVISION given here.

Modified: subversion/trunk/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/transaction.c?rev=1584356&r1=1584355&r2=1584356&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/transaction.c Thu Apr  3 19:47:24 2014
@@ -395,6 +395,51 @@ get_writable_proto_rev_body(svn_fs_t *fs
   return SVN_NO_ERROR;
 }
 
+/* Make sure the length ACTUAL_LENGTH of the proto-revision file PROTO_REV
+   of transaction TXN_ID in filesystem FS matches the proto-index file.
+   Trim any crash / failure related extra data from the proto-rev file.
+
+   If the prototype revision file is too short, we can't do much but bail out.
+
+   Perform all allocations in POOL. */
+static svn_error_t *
+auto_truncate_proto_rev(svn_fs_t *fs,
+                        apr_file_t *proto_rev,
+                        apr_off_t actual_length,
+                        const svn_fs_fs__id_part_t *txn_id,
+                        apr_pool_t *pool)
+{
+  /* Only relevant for newer FSFS formats. */
+  if (svn_fs_fs__use_log_addressing(fs, txn_id->revision))
+    {
+      /* Determine file range covered by the proto-index so far.  Note that
+         we always append to both file, i.e. the last index entry also
+         corresponds to the last addition in the rev file. */
+      const char *path = svn_fs_fs__path_p2l_proto_index(fs, txn_id, pool);
+      apr_file_t *file;
+      apr_off_t indexed_length;
+
+      SVN_ERR(svn_fs_fs__p2l_proto_index_open(&file, path, pool));
+      SVN_ERR(svn_fs_fs__p2l_proto_index_next_offset(&indexed_length, file,
+                                                     pool));
+      SVN_ERR(svn_io_file_close(file, pool));
+
+      /* Handle mismatches. */
+      if (indexed_length < actual_length)
+        SVN_ERR(svn_io_file_trunc(proto_rev, indexed_length, pool));
+      else if (indexed_length > actual_length)
+        return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+                                 NULL,
+                                 _("p2l proto index offset %s beyond proto"
+                                   "rev file size %s for TXN %s"),
+                                   apr_off_t_toa(pool, indexed_length),
+                                   apr_off_t_toa(pool, actual_length),
+                                   svn_fs_fs__id_txn_unparse(txn_id, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Get a handle to the prototype revision file for transaction TXN_ID in
    filesystem FS, and lock it for writing.  Return FILE, a file handle
    positioned at the end of the file, and LOCKCOOKIE, a cookie that
@@ -414,6 +459,7 @@ get_writable_proto_rev(apr_file_t **file
 {
   struct get_writable_proto_rev_baton b;
   svn_error_t *err;
+  apr_off_t end_offset = 0;
 
   b.lockcookie = lockcookie;
   b.txn_id = *txn_id;
@@ -434,10 +480,15 @@ get_writable_proto_rev(apr_file_t **file
      the APR file pointer to the OS file pointer (since we need to be
      able to read the current file position later). */
   if (!err)
-    {
-      apr_off_t offset = 0;
-      err = svn_io_file_seek(*file, APR_END, &offset, pool);
-    }
+    err = svn_io_file_seek(*file, APR_END, &end_offset, pool);
+
+  /* We don't want unused sections (such as leftovers from failed delta
+     stream) in our file.  If we use log addressing, we would need an
+     index entry for the unused section and that section would need to 
+     be all NUL by convention.  So, detect and fix those cases by truncating
+     the protorev file. */
+  if (!err)
+    err = auto_truncate_proto_rev(fs, *file, end_offset, txn_id, pool);
 
   if (err)
     {