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;