subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1635528 - in /subversion/trunk/subversion/libsvn_fs_x: ./ index.c index.h pack.c rev_file.c rev_file.h transaction.c
Date Thu, 30 Oct 2014 16:01:16 GMT
Author: stefan2
Date: Thu Oct 30 16:01:16 2014
New Revision: 1635528

URL: http://svn.apache.org/r1635528
Log:
Sync FSX with FSFS:
Merge revisions r1606514, r1606526, r1606528, r1607572 and r1623007
from libsvn_fs_fs, resolve the usual FSX conflicts and adapt the code
to FSX.

This port adds the "index (re-)creation utilities" to FSX.

Modified:
    subversion/trunk/subversion/libsvn_fs_x/   (props changed)
    subversion/trunk/subversion/libsvn_fs_x/index.c
    subversion/trunk/subversion/libsvn_fs_x/index.h
    subversion/trunk/subversion/libsvn_fs_x/pack.c
    subversion/trunk/subversion/libsvn_fs_x/rev_file.c
    subversion/trunk/subversion/libsvn_fs_x/rev_file.h
    subversion/trunk/subversion/libsvn_fs_x/transaction.c

Propchange: subversion/trunk/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/libsvn_fs_fs:r1606514,1606526,1606528,1607572,1623007

Modified: subversion/trunk/subversion/libsvn_fs_x/index.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/index.c?rev=1635528&r1=1635527&r2=1635528&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/index.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/index.c Thu Oct 30 16:01:16 2014
@@ -2998,6 +2998,270 @@ svn_fs_x__item_offset(apr_off_t *offset,
   return SVN_NO_ERROR;
 }
 
+/* Calculate the FNV1 checksum over the offset range in REV_FILE, covered by
+ * ENTRY.  Store the result in ENTRY->FNV1_CHECKSUM.  Use POOL for temporary
+ * allocations. */
+static svn_error_t *
+calc_fnv1(svn_fs_x__p2l_entry_t *entry,
+          svn_fs_x__revision_file_t *rev_file,
+          apr_pool_t *pool)
+{
+  unsigned char buffer[4096];
+  svn_checksum_t *checksum;
+  svn_checksum_ctx_t *context
+    = svn_checksum_ctx_create(svn_checksum_fnv1a_32x4, pool);
+  apr_off_t size = entry->size;
+
+  /* Special rules apply to unused sections / items.  The data must be a
+   * sequence of NUL bytes (not checked here) and the checksum is fixed to 0.
+   */
+  if (entry->type == SVN_FS_X__ITEM_TYPE_UNUSED)
+    {
+      entry->fnv1_checksum = 0;
+      return SVN_NO_ERROR;
+    }
+
+  /* Read the block and feed it to the checksum calculator. */
+  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &entry->offset, pool));
+  while (size > 0)
+    {
+      apr_size_t to_read = size > sizeof(buffer)
+                         ? sizeof(buffer)
+                         : (apr_size_t)size;
+      SVN_ERR(svn_io_file_read_full2(rev_file->file, buffer, to_read, NULL,
+                                     NULL, pool));
+      SVN_ERR(svn_checksum_update(context, buffer, to_read));
+      size -= to_read;
+    }
+
+  /* Store final checksum in ENTRY. */
+  SVN_ERR(svn_checksum_final(&checksum, context, pool));
+  entry->fnv1_checksum = ntohl(*(const apr_uint32_t *)checksum->digest);
+
+  return SVN_NO_ERROR;
+}
+
+/*
+ * Index (re-)creation utilities.
+ */
+
+svn_error_t *
+svn_fs_x__p2l_index_from_p2l_entries(const char **protoname,
+                                     svn_fs_t *fs,
+                                     svn_fs_x__revision_file_t *rev_file,
+                                     apr_array_header_t *entries,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool)
+{
+  apr_file_t *proto_index;
+
+  /* Use a subpool for immediate temp file cleanup at the end of this
+   * function. */
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  int i;
+
+  /* Create a proto-index file. */
+  SVN_ERR(svn_io_open_unique_file3(NULL, protoname, NULL,
+                                   svn_io_file_del_on_pool_cleanup,
+                                   result_pool, scratch_pool));
+  SVN_ERR(svn_fs_x__p2l_proto_index_open(&proto_index, *protoname,
+                                         scratch_pool));
+
+  /* Write ENTRIES to proto-index file and calculate checksums as we go. */
+  for (i = 0; i < entries->nelts; ++i)
+    {
+      svn_fs_x__p2l_entry_t *entry
+        = APR_ARRAY_IDX(entries, i, svn_fs_x__p2l_entry_t *);
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(calc_fnv1(entry, rev_file, iterpool));
+      SVN_ERR(svn_fs_x__p2l_proto_index_add_entry(proto_index, entry,
+                                                  iterpool));
+    }
+
+  /* Convert proto-index into final index and move it into position.
+   * Note that REV_FILE contains the start revision of the shard file if it
+   * has been packed while REVISION may be somewhere in the middle.  For
+   * non-packed shards, they will have identical values. */
+  SVN_ERR(svn_io_file_close(proto_index, iterpool));
+
+  /* Temp file cleanup. */
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Decorator for svn_fs_x__p2l_entry_t that associates it with a sorted
+ * variant of its ITEMS array.
+ */
+typedef struct sub_item_ordered_t
+{
+  /* ENTRY that got wrapped */
+  svn_fs_x__p2l_entry_t *entry;
+
+  /* Array of pointers into ENTRY->ITEMS, sorted by their revision member
+   * _descending_ order.  May be NULL if ENTRY->ITEM_COUNT < 2. */
+  svn_fs_x__id_part_t **order;
+} sub_item_ordered_t;
+
+/* implements compare_fn_t. Place LHS before RHS, if the latter is younger.
+ * Used to sort sub_item_ordered_t::order
+ */
+static int
+compare_sub_items(const svn_fs_x__id_part_t * const * lhs,
+                  const svn_fs_x__id_part_t * const * rhs)
+{
+  return (*lhs)->change_set < (*rhs)->change_set
+       ? 1
+       : ((*lhs)->change_set > (*rhs)->change_set ? -1 : 0);
+}
+
+/* implements compare_fn_t. Place LHS before RHS, if the latter belongs to
+ * a newer revision.
+ */
+static int
+compare_p2l_info_rev(const sub_item_ordered_t * lhs,
+                     const sub_item_ordered_t * rhs)
+{
+  svn_fs_x__id_part_t *lhs_part;
+  svn_fs_x__id_part_t *rhs_part;
+  
+  assert(lhs != rhs);
+  if (lhs->entry->item_count == 0)
+    return rhs->entry->item_count == 0 ? 0 : -1;
+  if (rhs->entry->item_count == 0)
+    return 1;
+
+  lhs_part = lhs->order ? lhs->order[lhs->entry->item_count - 1]
+                        : &lhs->entry->items[0];
+  rhs_part = rhs->order ? rhs->order[rhs->entry->item_count - 1]
+                        : &rhs->entry->items[0];
+
+  if (lhs_part->change_set == rhs_part->change_set)
+    return 0;
+
+  return lhs_part->change_set < rhs_part->change_set ? -1 : 1;
+}
+
+svn_error_t *
+svn_fs_x__l2p_index_from_p2l_entries(const char **protoname,
+                                     svn_fs_t *fs,
+                                     apr_array_header_t *entries,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool)
+{
+  apr_file_t *proto_index;
+
+  /* Use a subpool for immediate temp file cleanup at the end of this
+   * function. */
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  svn_revnum_t prev_rev = SVN_INVALID_REVNUM;
+  int i;
+  apr_uint32_t k;
+  svn_priority_queue__t *queue;
+  apr_size_t count = 0;
+  apr_array_header_t *sub_item_orders;
+
+  /* Create the temporary proto-rev file. */
+  SVN_ERR(svn_io_open_unique_file3(NULL, protoname, NULL,
+                                   svn_io_file_del_on_pool_cleanup,
+                                   result_pool, scratch_pool));
+  SVN_ERR(svn_fs_x__l2p_proto_index_open(&proto_index, *protoname,
+                                         scratch_pool));
+
+
+  /* wrap P2L entries such that we have access to the sub-items in revision
+     order.  The ENTRY_COUNT member will point to the next item to read+1. */
+  sub_item_orders = apr_array_make(scratch_pool, entries->nelts,
+                                   sizeof(sub_item_ordered_t));
+  sub_item_orders->nelts = entries->nelts;
+
+  for (i = 0; i < entries->nelts; ++i)
+    {
+      svn_fs_x__p2l_entry_t *entry
+        = APR_ARRAY_IDX(entries, i, svn_fs_x__p2l_entry_t *);
+      sub_item_ordered_t *ordered
+        = &APR_ARRAY_IDX(sub_item_orders, i, sub_item_ordered_t);
+
+      /* skip unused regions (e.g. padding) */
+      if (entry->item_count == 0)
+        continue;
+
+      assert(entry);
+      ordered->entry = entry;
+      count += entry->item_count;
+
+      if (entry->item_count > 1)
+        {
+          ordered->order
+            = apr_palloc(scratch_pool,
+                         sizeof(*ordered->order) * entry->item_count);
+          for (k = 0; k < entry->item_count; ++k)
+            ordered->order[k] = &entry->items[k];
+
+          qsort(ordered->order, entry->item_count, sizeof(*ordered->order),
+                (int (*)(const void *, const void *))compare_sub_items);
+        }
+    }
+
+  /* we need to write the index in ascending revision order */
+  queue = svn_priority_queue__create
+            (sub_item_orders,
+             (int (*)(const void *, const void *))compare_p2l_info_rev);
+
+  /* write index entries */
+  for (i = 0; i < count; ++i)
+    {
+      svn_fs_x__id_part_t *sub_item;
+      sub_item_ordered_t *ordered = svn_priority_queue__peek(queue);
+
+      if (ordered->entry->item_count > 0)
+        {
+          /* if there is only one item, we skip the overhead of having an
+             extra array for the item order */
+          sub_item = ordered->order
+                   ? ordered->order[ordered->entry->item_count - 1]
+                   : &ordered->entry->items[0];
+
+          /* next revision? */
+          if (prev_rev != svn_fs_x__get_revnum(sub_item->change_set))
+            {
+              prev_rev = svn_fs_x__get_revnum(sub_item->change_set);
+              SVN_ERR(svn_fs_x__l2p_proto_index_add_revision
+                          (proto_index, iterpool));
+            }
+
+          /* add entry */
+          SVN_ERR(svn_fs_x__l2p_proto_index_add_entry
+                      (proto_index, ordered->entry->offset,
+                      (apr_uint32_t)(sub_item - ordered->entry->items),
+                      sub_item->number, iterpool));
+
+          /* make ITEM_COUNT point the next sub-item to use+1 */
+          --ordered->entry->item_count;
+        }
+
+      /* process remaining sub-items (if any) of that container later */
+      if (ordered->entry->item_count)
+        svn_priority_queue__update(queue);
+      else
+        svn_priority_queue__pop(queue);
+
+      /* keep memory usage in check */
+      if (i % 256 == 0)
+        svn_pool_clear(iterpool);
+    }
+
+  /* Convert proto-index into final index and move it into position. */
+  SVN_ERR(svn_io_file_close(proto_index, iterpool));
+
+  /* Temp file cleanup. */
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+
 /*
  * Standard (de-)serialization functions
  */

Modified: subversion/trunk/subversion/libsvn_fs_x/index.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/index.h?rev=1635528&r1=1635527&r2=1635528&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/index.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/index.h Thu Oct 30 16:01:16 2014
@@ -252,6 +252,37 @@ svn_fs_x__p2l_get_max_offset(apr_off_t *
                              svn_revnum_t revision,
                              apr_pool_t *pool);
 
+/* Index (re-)creation utilities.
+ */
+
+/* For FS, create a new L2P auto-deleting proto index file in POOL and return
+ * its name in *PROTONAME.  All entries to write are given in ENTRIES and
+ * entries are of type svn_fs_fs__p2l_entry_t* (sic!).  The ENTRIES array
+ * will be reordered.  Give the proto index file the lifetime of RESULT_POOL
+ * and use SCRATCH_POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_x__l2p_index_from_p2l_entries(const char **protoname,
+                                     svn_fs_t *fs,
+                                     apr_array_header_t *entries,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool);
+
+/* For FS, create a new P2L auto-deleting proto index file in POOL and return
+ * its name in *PROTONAME.  All entries to write are given in ENTRIES and
+ * of type svn_fs_fs__p2l_entry_t*.  The FVN1 checksums are not taken from
+ * ENTRIES but are begin calculated from the current contents of REV_FILE
+ * as we go.  Give the proto index file the lifetime of RESULT_POOL and use
+ * SCRATCH_POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_x__p2l_index_from_p2l_entries(const char **protoname,
+                                     svn_fs_t *fs,
+                                     svn_fs_x__revision_file_t *rev_file,
+                                     apr_array_header_t *entries,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool);
+
 /* Serialization and caching interface
  */
 

Modified: subversion/trunk/subversion/libsvn_fs_x/pack.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/pack.c?rev=1635528&r1=1635527&r2=1635528&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/pack.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/pack.c Thu Oct 30 16:01:16 2014
@@ -757,58 +757,6 @@ sort_items(apr_array_header_t *entries)
                   (int (*)(const void *, const void *))compare_p2l_info);
 }
 
-/* Decorator for svn_fs_x__p2l_entry_t that associates it with a sorted
- * variant of its ITEMS array.
- */
-typedef struct sub_item_ordered_t
-{
-  /* ENTRY that got wrapped */
-  svn_fs_x__p2l_entry_t *entry;
-
-  /* Array of pointers into ENTRY->ITEMS, sorted by their revision member
-   * _descending_ order.  May be NULL if ENTRY->ITEM_COUNT < 2. */
-  svn_fs_x__id_part_t **order;
-} sub_item_ordered_t;
-
-/* implements compare_fn_t. Place LHS before RHS, if the latter is younger.
- * Used to sort sub_item_ordered_t::order
- */
-static int
-compare_sub_items(const svn_fs_x__id_part_t * const * lhs,
-                  const svn_fs_x__id_part_t * const * rhs)
-{
-  return (*lhs)->change_set < (*rhs)->change_set
-       ? 1
-       : ((*lhs)->change_set > (*rhs)->change_set ? -1 : 0);
-}
-
-/* implements compare_fn_t. Place LHS before RHS, if the latter belongs to
- * a newer revision.
- */
-static int
-compare_p2l_info_rev(const sub_item_ordered_t * lhs,
-                     const sub_item_ordered_t * rhs)
-{
-  svn_fs_x__id_part_t *lhs_part;
-  svn_fs_x__id_part_t *rhs_part;
-  
-  assert(lhs != rhs);
-  if (lhs->entry->item_count == 0)
-    return rhs->entry->item_count == 0 ? 0 : -1;
-  if (rhs->entry->item_count == 0)
-    return 1;
-
-  lhs_part = lhs->order ? lhs->order[lhs->entry->item_count - 1]
-                        : &lhs->entry->items[0];
-  rhs_part = rhs->order ? rhs->order[rhs->entry->item_count - 1]
-                        : &rhs->entry->items[0];
-
-  if (lhs_part->change_set == rhs_part->change_set)
-    return 0;
-
-  return lhs_part->change_set < rhs_part->change_set ? -1 : 1;
-}
-
 /* implements compare_fn_t.  Sort descending by PATH, NODE_ID and REVISION.
  */
 static int
@@ -1710,13 +1658,10 @@ static svn_error_t *
 write_l2p_index(pack_context_t *context,
                 apr_pool_t *pool)
 {
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  svn_revnum_t prev_rev = SVN_INVALID_REVNUM;
-  int i;
-  apr_uint32_t k;
-  svn_priority_queue__t *queue;
-  apr_size_t count = 0;
-  apr_array_header_t *sub_item_orders;
+  apr_pool_t *scratch_pool = svn_pool_create(pool);
+  const char *temp_name;
+  const char *proto_index;
+  apr_off_t offset = 0;
 
   /* lump all items into one bucket.  As target, use the bucket that
    * probably has the most entries already. */
@@ -1724,88 +1669,24 @@ write_l2p_index(pack_context_t *context,
   append_entries(context->reps, context->file_props);
   append_entries(context->reps, context->dir_props);
 
-  /* wrap P2L entries such that we have access to the sub-items in revision
-     order.  The ENTRY_COUNT member will point to the next item to read+1. */
-  sub_item_orders
-    = apr_array_make(pool, context->reps->nelts, sizeof(sub_item_ordered_t));
-  sub_item_orders->nelts = context->reps->nelts;
-
-  for (i = 0; i < context->reps->nelts; ++i)
-    {
-      svn_fs_x__p2l_entry_t *entry
-        = APR_ARRAY_IDX(context->reps, i, svn_fs_x__p2l_entry_t *);
-      sub_item_ordered_t *ordered
-        = &APR_ARRAY_IDX(sub_item_orders, i, sub_item_ordered_t);
-
-      /* skip unused regions (e.g. padding) */
-      if (entry->item_count == 0)
-        continue;
-
-      assert(entry);
-      ordered->entry = entry;
-      count += entry->item_count;
-
-      if (entry->item_count > 1)
-        {
-          ordered->order
-            = apr_palloc(pool, sizeof(*ordered->order) * entry->item_count);
-          for (k = 0; k < entry->item_count; ++k)
-            ordered->order[k] = &entry->items[k];
-
-          qsort(ordered->order, entry->item_count, sizeof(*ordered->order),
-                (int (*)(const void *, const void *))compare_sub_items);
-        }
-    }
-
-  /* we need to write the index in ascending revision order */
-  queue = svn_priority_queue__create
-            (sub_item_orders,
-             (int (*)(const void *, const void *))compare_p2l_info_rev);
-
-  /* write index entries */
-  for (i = 0; i < count; ++i)
-    {
-      svn_fs_x__id_part_t *sub_item;
-      sub_item_ordered_t *ordered = svn_priority_queue__peek(queue);
-
-      if (ordered->entry->item_count > 0)
-        {
-          /* if there is only one item, we skip the overhead of having an
-             extra array for the item order */
-          sub_item = ordered->order
-                   ? ordered->order[ordered->entry->item_count - 1]
-                   : &ordered->entry->items[0];
-
-          /* next revision? */
-          if (prev_rev != svn_fs_x__get_revnum(sub_item->change_set))
-            {
-              prev_rev = svn_fs_x__get_revnum(sub_item->change_set);
-              SVN_ERR(svn_fs_x__l2p_proto_index_add_revision
-                          (context->proto_l2p_index, iterpool));
-            }
-
-          /* add entry */
-          SVN_ERR(svn_fs_x__l2p_proto_index_add_entry
-                      (context->proto_l2p_index, ordered->entry->offset,
-                      (apr_uint32_t)(sub_item - ordered->entry->items),
-                      sub_item->number, iterpool));
-
-          /* make ITEM_COUNT point the next sub-item to use+1 */
-          --ordered->entry->item_count;
-        }
-
-      /* process remaining sub-items (if any) of that container later */
-      if (ordered->entry->item_count)
-        svn_priority_queue__update(queue);
-      else
-        svn_priority_queue__pop(queue);
-
-      /* keep memory usage in check */
-      if (i % 256 == 0)
-        svn_pool_clear(iterpool);
-    }
+  /* Let the index code do the expensive L2P -> P2L transformation. */
+  SVN_ERR(svn_fs_x__l2p_index_from_p2l_entries(&temp_name,
+                                               context->fs,
+                                               context->reps,
+                                               pool, scratch_pool));
+
+  /* Append newly written segment to exisiting proto index file. */
+  SVN_ERR(svn_io_file_name_get(&proto_index, context->proto_l2p_index,
+                               scratch_pool));
+
+  SVN_ERR(svn_io_file_flush(context->proto_l2p_index, scratch_pool));
+  SVN_ERR(svn_io_append_file(temp_name, proto_index, scratch_pool));
+  SVN_ERR(svn_io_remove_file2(temp_name, FALSE, scratch_pool));
+  SVN_ERR(svn_io_file_seek(context->proto_l2p_index, APR_END, &offset,
+                           scratch_pool));
 
-  svn_pool_destroy(iterpool);
+  /* Done. */
+  svn_pool_destroy(scratch_pool);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/libsvn_fs_x/rev_file.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/rev_file.c?rev=1635528&r1=1635527&r2=1635528&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/rev_file.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/rev_file.c Thu Oct 30 16:01:16 2014
@@ -28,8 +28,11 @@
 
 #include "../libsvn_fs/fs-loader.h"
 
+#include "private/svn_io_private.h"
 #include "svn_private_config.h"
 
+/* Return a new revision file instance, allocated in RESULT_POOL, for
+ * filesystem FS.  Set its pool member to the provided RESULT_POOL. */
 static svn_fs_x__revision_file_t *
 create_revision_file(svn_fs_t *fs,
                      apr_pool_t *result_pool)
@@ -53,6 +56,9 @@ create_revision_file(svn_fs_t *fs,
   return file;
 }
 
+/* Return a new revision file instance, allocated in RESULT_POOL, for
+ * REVISION in filesystem FS.  Set its pool member to the provided
+ * RESULT_POOL. */
 static svn_fs_x__revision_file_t *
 init_revision_file(svn_fs_t *fs,
                    svn_revnum_t revision,
@@ -69,13 +75,78 @@ init_revision_file(svn_fs_t *fs,
   return file;
 }
 
-/* Core implementation of svn_fs_x__open_pack_or_rev_file working on an
- * existing, initialized FILE structure.
+/* Baton type for set_read_only() */
+typedef struct set_read_only_baton_t
+{
+  /* File to set to read-only. */
+  const char *file_path;
+
+  /* Scratch pool sufficient life time.
+   * Ideally the pool that we registered the cleanup on. */
+  apr_pool_t *pool;
+} set_read_only_baton_t;
+
+/* APR pool cleanup callback taking a set_read_only_baton_t baton and then
+ * (trying to) set the specified file to r/o mode. */
+static apr_status_t
+set_read_only(void *baton)
+{
+  set_read_only_baton_t *ro_baton = baton;
+  apr_status_t status = APR_SUCCESS;
+  svn_error_t *err;
+
+  err = svn_io_set_file_read_only(ro_baton->file_path, TRUE, ro_baton->pool);
+  if (err)
+    {
+      status = err->apr_err;
+      svn_error_clear(err);
+    }
+
+  return status;
+}
+
+/* If the file at PATH is read-only, attempt to make it writable.  The
+ * original state will be restored with RESULT_POOL gets cleaned up.
+ * SCRATCH_POOL is for temporary allocations. */
+static svn_error_t *
+auto_make_writable(const char *path,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  svn_boolean_t is_read_only;
+  apr_finfo_t finfo;
+
+  SVN_ERR(svn_io_stat(&finfo, path, SVN__APR_FINFO_READONLY, scratch_pool));
+  SVN_ERR(svn_io__is_finfo_read_only(&is_read_only, &finfo, scratch_pool));
+
+  if (is_read_only)
+    {
+      /* Tell the pool to restore the r/o state upon cleanup
+         (assuming the file will still exist, failing silently otherwise). */
+      set_read_only_baton_t *baton = apr_pcalloc(result_pool,
+                                                  sizeof(*baton));
+      baton->pool = result_pool;
+      baton->file_path = apr_pstrdup(result_pool, path);
+      apr_pool_cleanup_register(result_pool, baton,
+                                set_read_only, apr_pool_cleanup_null);
+
+      /* Finally, allow write access (undoing it has already been scheduled
+         and is idempotent). */
+      SVN_ERR(svn_io_set_file_read_write(path, FALSE, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Core implementation of svn_fs_fs__open_pack_or_rev_file working on an
+ * existing, initialized FILE structure.  If WRITABLE is TRUE, give write
+ * access to the file - temporarily resetting the r/o state if necessary.
  */
 static svn_error_t *
 open_pack_or_rev_file(svn_fs_x__revision_file_t *file,
                       svn_fs_t *fs,
                       svn_revnum_t rev,
+                      svn_boolean_t writable,
                       apr_pool_t *result_pool,
                       apr_pool_t *scratch_pool)
 {
@@ -86,11 +157,19 @@ open_pack_or_rev_file(svn_fs_x__revision
     {
       const char *path = svn_fs_x__path_rev_absolute(fs, rev, scratch_pool);
       apr_file_t *apr_file;
+      apr_int32_t flags = writable
+                        ? APR_READ | APR_WRITE | APR_BUFFERED
+                        : APR_READ | APR_BUFFERED;
+
+      /* We may have to *temporarily* enable write access. */
+      err = writable ? auto_make_writable(path, result_pool, scratch_pool)
+                     : SVN_NO_ERROR; 
+
+      /* open the revision file in buffered r/o or r/w mode */
+      if (!err)
+        err = svn_io_file_open(&apr_file, path, flags, APR_OS_DEFAULT,
+                               result_pool);
 
-      /* open the revision file in buffered r/o mode */
-      err = svn_io_file_open(&apr_file, path,
-                             APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
-                             result_pool);
       if (!err)
         {
           file->file = apr_file;
@@ -134,7 +213,19 @@ svn_fs_x__open_pack_or_rev_file(svn_fs_x
                                  apr_pool_t *scratch_pool)
 {
   *file = init_revision_file(fs, rev, result_pool);
-  return svn_error_trace(open_pack_or_rev_file(*file, fs, rev,
+  return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, FALSE,
+                                               result_pool, scratch_pool));
+}
+
+svn_error_t *
+svn_fs_x__open_pack_or_rev_file_writable(svn_fs_x__revision_file_t** file,
+                                         svn_fs_t* fs,
+                                         svn_revnum_t rev,
+                                         apr_pool_t* result_pool,
+                                         apr_pool_t *scratch_pool)
+{
+  *file = init_revision_file(fs, rev, result_pool);
+  return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, TRUE,
                                                result_pool, scratch_pool));
 }
 

Modified: subversion/trunk/subversion/libsvn_fs_x/rev_file.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/rev_file.h?rev=1635528&r1=1635527&r2=1635528&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/rev_file.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/rev_file.h Thu Oct 30 16:01:16 2014
@@ -98,6 +98,20 @@ svn_fs_x__open_pack_or_rev_file(svn_fs_x
                                 apr_pool_t *result_pool,
                                 apr_pool_t *scratch_pool);
 
+/* Open the correct revision file for REV with read and write access.
+ * If necessary, temporarily reset the file's read-only state.  If the
+ * filesystem FS has been packed, *FILE will be set to the packed file;
+ * otherwise, set *FILE to the revision file for REV.
+ *
+ * Return SVN_ERR_FS_NO_SUCH_REVISION if the file doesn't exist.
+ * Allocate *FILE in RESULT_POOL and use SCRATCH_POOLfor temporaries. */
+svn_error_t *
+svn_fs_x__open_pack_or_rev_file_writable(svn_fs_x__revision_file_t **file,
+                                         svn_fs_t *fs,
+                                         svn_revnum_t rev,
+                                         apr_pool_t *result_pool,
+                                         apr_pool_t *scratch_pool);
+
 /* If the footer data in FILE has not been read, yet, do so now.
  * Index locations will only be read upon request as we assume they get
  * cached and the FILE is usually used for REP data access only.

Modified: subversion/trunk/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/transaction.c?rev=1635528&r1=1635527&r2=1635528&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/transaction.c Thu Oct 30 16:01:16 2014
@@ -3242,12 +3242,12 @@ svn_fs_x__add_index_data(svn_fs_t *fs,
 
   /* Append the actual index data to the pack file. */
   l2p_offset = 0;
-  SVN_ERR(svn_io_file_seek(file, APR_CUR, &l2p_offset, pool));
+  SVN_ERR(svn_io_file_seek(file, APR_END, &l2p_offset, pool));
   SVN_ERR(svn_fs_x__l2p_index_append(fs, file, l2p_proto_index, revision,
                                      pool));
 
   p2l_offset = 0;
-  SVN_ERR(svn_io_file_seek(file, APR_CUR, &p2l_offset, pool));
+  SVN_ERR(svn_io_file_seek(file, APR_END, &p2l_offset, pool));
   SVN_ERR(svn_fs_x__p2l_index_append(fs, file, p2l_proto_index, revision,
                                      pool));
 



Mime
View raw message