Return-Path: X-Original-To: apmail-subversion-commits-archive@minotaur.apache.org Delivered-To: apmail-subversion-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4145460C1 for ; Fri, 8 Jul 2011 22:30:08 +0000 (UTC) Received: (qmail 62594 invoked by uid 500); 8 Jul 2011 22:30:08 -0000 Delivered-To: apmail-subversion-commits-archive@subversion.apache.org Received: (qmail 62560 invoked by uid 500); 8 Jul 2011 22:30:07 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 62553 invoked by uid 99); 8 Jul 2011 22:30:07 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 08 Jul 2011 22:30:07 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 08 Jul 2011 22:30:01 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id CB604238890D for ; Fri, 8 Jul 2011 22:29:41 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: svn commit: r1144527 - /subversion/branches/revprop-packing/subversion/libsvn_fs_fs/fs_fs.c Date: Fri, 08 Jul 2011 22:29:41 -0000 To: commits@subversion.apache.org From: hwright@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110708222941.CB604238890D@eris.apache.org> 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;