subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hwri...@apache.org
Subject svn commit: r1144527 - /subversion/branches/revprop-packing/subversion/libsvn_fs_fs/fs_fs.c
Date Fri, 08 Jul 2011 22:29:41 GMT
Author: hwright
Date: Fri Jul  8 22:29:41 2011
New Revision: 1144527

URL: http://svn.apache.org/viewvc?rev=1144527&view=rev
Log:
On the revprop-packing branch:
Add a naïve implementation to support editing of packed revprops.  This
decreases the number of test failures to 20, mainly in the svnsync tests.

Notes: This can certainly be further corrected and improved, and I welcome
interested parties to do so.  Hopefully the intent of the code is clear.

* subversion/libsvn_fs_fs/fs_fs.c
  (set_revision_proplist): Implemented for the packed case.

Modified:
    subversion/branches/revprop-packing/subversion/libsvn_fs_fs/fs_fs.c

Modified: subversion/branches/revprop-packing/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_fs_fs/fs_fs.c?rev=1144527&r1=1144526&r2=1144527&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_fs_fs/fs_fs.c Fri Jul  8 22:29:41
2011
@@ -3035,16 +3035,127 @@ set_revision_proplist(svn_fs_t *fs,
   else
     {
       /* Here's how this works:
-          - Open a new pack file and manifest file
-          - We copy all the existing revprops, upto the one being edited
-          - Copy the new prop content into the the target file
-          - Copy the remaining revprops into the target file
-          - Append the pack file to the manifest file (just like we do when
-            packing).
+          - Compute the size of the new set of properties
+          - Open the new combined pack and manifest file
+          - Copy existing offsets up until N+1
+          - Copy N+1 to the end, accounting for any change in propsize in
+            the new properties
+          - Copy the prophashes, substituting the new props for the old one
+            for the interesting revision.
           - Move the new packed file into place. */
 
       /* ### We need some locking here, so that folks editing props in the
          ### same shard don't clobber each other. */
+
+      svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+      svn_stream_t *stream = svn_stream_from_stringbuf(sb, pool);
+      apr_off_t offset_diff;
+      apr_off_t old_offset;
+      apr_off_t next_offset;
+      svn_stream_t *source_stream;
+      svn_stream_t *target_stream;
+      const char *target_path;
+      svn_revnum_t shard;
+      apr_int64_t shard_pos;
+      apr_int64_t i;
+      const char *pack_file_path;
+      const char *pack_file_dir;
+      const char *revprops_dir;
+      char buf[REVPROP_MANIFEST_FIELD_WIDTH + 1];
+      apr_size_t len = REVPROP_MANIFEST_FIELD_WIDTH;
+
+      /* Calculate the size of the new proplist */
+      SVN_ERR(svn_hash_write2(proplist, stream, SVN_HASH_TERMINATOR, pool));
+      SVN_ERR(svn_stream_close(stream));
+
+      shard = rev / ffd->max_files_per_dir;
+
+      /* position of the shard within the manifest */
+      shard_pos = rev % ffd->max_files_per_dir;
+
+      revprops_dir = svn_dirent_join(fs->path, PATH_REVPROPS_DIR, pool);
+      pack_file_dir = svn_dirent_join(revprops_dir,
+                        apr_psprintf(pool, "%" APR_INT64_T_FMT ".pack", shard),
+                        pool);
+      pack_file_path = svn_dirent_join(pack_file_dir, "pack", pool);
+
+      /* Open the new and existing file. */
+      SVN_ERR(svn_stream_open_unique(&target_stream, &target_path,
+                                     pack_file_dir, svn_io_file_del_none,
+                                     pool, pool));
+      SVN_ERR(svn_stream_open_readonly(&source_stream, pack_file_path,
+                                       pool, pool));
+
+      /* Copy manifest info up to the new prop's offset value. */
+      SVN_ERR(svn_stream_copy4(svn_stream_disown(source_stream, pool),
+                               svn_stream_disown(target_stream, pool),
+                               shard_pos * REVPROP_MANIFEST_FIELD_WIDTH,
+                               NULL, NULL, pool));
+
+      /* Read the old offset value from the existing pack file, and compute
+         the difference, given the new
+
+         Note: the new property has the same offset as the existing one,
+         it's only subsequent properties' offsets that need to be adjusted. */
+      SVN_ERR(svn_stream_read(source_stream, buf, &len));
+      SVN_ERR(svn_stream_write(target_stream, buf, &len));
+      old_offset = apr_atoi64(buf);
+
+      /* In this corner case, the editted prop is the last one in the
+         shard, so there is no further offset to read or bump. */
+      if (shard_pos != (ffd->max_files_per_dir - 1) )
+        {
+          SVN_ERR(svn_stream_read(source_stream, buf, &len));
+          next_offset = apr_atoi64(buf);
+          offset_diff = sb->len - (next_offset - old_offset);
+          SVN_ERR(svn_stream_printf(target_stream, pool,
+                "%0" APR_STRINGIFY(REVPROP_MANIFEST_FIELD_WIDTH) APR_OFF_T_FMT,
+                next_offset + offset_diff));
+        }
+      else
+        offset_diff = 0;  /* for completeness */
+
+      /* Iterate over the remaining offsets, adjusting them as appropriate.
+         We skip over both of the offset values we manually read and wrote
+         above.  This should also handle our corner case. */
+      for (i = (shard_pos + 2); i < ffd->max_files_per_dir; i++)
+        {
+          SVN_ERR(svn_stream_read(source_stream, buf, &len));
+          next_offset = apr_atoi64(buf);
+          SVN_ERR(svn_stream_printf(target_stream, pool,
+                "%0" APR_STRINGIFY(REVPROP_MANIFEST_FIELD_WIDTH) APR_OFF_T_FMT,
+                next_offset + offset_diff));
+        }
+
+      /* Now we copy the existing data over, in much the same way we copied
+         over the offset values. */
+      SVN_ERR(svn_stream_copy4(svn_stream_disown(source_stream, pool),
+                               svn_stream_disown(target_stream, pool),
+                               old_offset, NULL, NULL, pool));
+
+      len = sb->len;
+      SVN_ERR(svn_stream_write(target_stream, sb->data, &len));
+
+      if (offset_diff)
+        {
+          /* If we have an offset, it means we aren't the last rev in the
+             shard, and need copy the rest of the content from source to
+             target. */
+          len = sb->len - offset_diff;
+          SVN_ERR(svn_stream_skip(source_stream, len));
+          SVN_ERR(svn_stream_copy4(source_stream, target_stream, -1,
+                                   NULL, NULL, pool));
+        }
+      else
+        {
+          /* Otherwise, just close everything up. */
+          SVN_ERR(svn_stream_close(source_stream));
+          SVN_ERR(svn_stream_close(target_stream));
+        }
+
+      /* Move it all into place. */
+      SVN_ERR(move_into_place(target_path, pack_file_path, pack_file_path,
+                              pool));
     }
 
   return SVN_NO_ERROR;



Mime
View raw message