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)
{