Hi, I've noticed that the new fs-fs-pack-tests (#13 and #14) fail on my machine around trunk@r1559108. This happens with different Windows versions (I've tried Windows XP SP3 32-bit / Vista SP2 32-bit / Server 2008 R2 64-bit / Windows 7 64-bit / Windows 8 64-bit) and does not happen with Ubuntu 64-bit: [[[ svn_tests: E720145: Can't remove directory 'upgrade_new_txns_to_log_addressing\revs\2': The directory is not empty. FAIL: fs-fs-pack-test.exe 13: upgrade txns to log addressing in shared FSFS
svn_tests: E720145: Can't remove directory 'upgrade_old_txns_to_log_addressing\revs\2': The directory is not empty. FAIL: fs-fs-pack-test.exe 14: upgrade txns started before svnadmin upgrade ]]] This Windows-specific error is usually caused by an attempt to remove a folder while still having open file handles to some of its children. So, I grabbed the Process Monitor [1] and dumped the CreateFile and CloseFile events that happen within the 'upgrade_new_txns_to_log_addressing' test. It is easy to spot that the 'revs/2/8' file handle is only closed during the test cleanup (when the per-function TEST_POOL is being cleared). As a consequence, an attempt to pack the repository fails to delete the 'revs/2' folder with an ENOTEMPTY error. I've tracked down the origin of this file handle and here is the corresponding stacktrace: [[[ file_open + 0x20, libsvn_subr\io.c(350) svn_io_file_open + 0x4a, libsvn_subr\io.c(3427) open_pack_or_rev_file + 0x48, libsvn_fs_fs\rev_file.c(67) svn_fs_fs__open_pack_or_rev_file + 0x45, libsvn_fs_fs\rev_file.c(124) open_and_seek_revision + 0x52, libsvn_fs_fs\cached_data.c(217) get_node_revision_body + 0x1a7, libsvn_fs_fs\cached_data.c(338) svn_fs_fs__get_node_revision + 0x2a, libsvn_fs_fs\cached_data.c(387) shards_spanned + 0x7a, libsvn_fs_fs\transaction.c(1858) choose_delta_base + 0x8e, libsvn_fs_fs\transaction.c(1925) write_container_delta_rep + 0xd5, libsvn_fs_fs\transaction.c(2655) write_final_rev + 0x22b, libsvn_fs_fs\transaction.c(2923) commit_body + 0x344, libsvn_fs_fs\transaction.c(3843) ... ]]] Now, if you examine the core FSFS routines like 'get_node_revision_body', you can notice that some of them close the temporary 'svn_fs_fs__revision_file_t' objects, but some of them do not, e.g., svn_fs_fs__get_changes does, but get_node_revision_body does not (for the physical addressing mode). In the latter case, this can lead to various sorts of problems, one of which was caught by the fs-fs-pack-tests. This behavior looks like a regression from 1.8.x, where these routines did close the temporary file handles via explicit 'svn_io_file_close' calls or via less explicit 'svn_stream_close' calls for the streams with DISOWN=FALSE. I've attached a patch that restores this behavior for FSFS7. The invariant is quite simple: on any non-erroneous flow, a routine should not leak the file handle(s) in the POOL that come from the temporary 'svn_fs_fs__revision_file_t' object(s). NOTE: It looks like FSX suffers from the same kind of problem. There are 77 failing tests from the standalone suite (client-test.exe, fs-test.exe, ...) and any attempt to run the Python tests (basic_tests.py, ...) immediately fails during the greek tree initialization phase. I guess I might be able to come up with a patch for this problem in the nearby future (in case someone does not fix it earlier): [[[ (client-test.exe --fs-type=fsx) svn_tests: E720145: Can't remove directory 'BUILDPATH\subversion\tests\cmdline\svn-test-work\libsvn_client\ test-wc-add-repos\db\transactions\0-0.txn': The directory is not empty. FAIL: client-test.exe 3: test svn_wc_add3 scenarios (win-tests.py --fs-type=fsx --test=basic_tests.py --log-to-stdout) Testing Release configuration on local repository. START: basic_tests.py E: import did not succeed, while creating greek repos. E: The final line from 'svn import' was: E: Can't remove directory 'BUILDPATH\subversion\tests\cmdline\svn-test-work\local-tmp\ repos\db\transactions\0-0.txn': The directory is not empty. ]]] [1] http://technet.microsoft.com/sysinternals/bb896645 Thanks and regards, Evgeny Kotkov
Index: subversion/libsvn_fs_fs/cached_data.c =================================================================== --- subversion/libsvn_fs_fs/cached_data.c (revision 1559108) +++ subversion/libsvn_fs_fs/cached_data.c (working copy) @@ -354,7 +354,6 @@ get_node_revision_body(node_revision_t **noderev_p revision_file, pool, pool)); - SVN_ERR(svn_fs_fs__close_revision_file(revision_file)); } else { @@ -373,6 +372,8 @@ get_node_revision_body(node_revision_t **noderev_p *noderev_p, pool)); } + + SVN_ERR(svn_fs_fs__close_revision_file(revision_file)); } return SVN_NO_ERROR; @@ -884,6 +885,7 @@ svn_fs_fs__check_rep(representation_t *rep, if (is_packed != rev_file.is_packed) { svn_error_clear(err); + SVN_ERR(svn_fs_fs__close_revision_file(&rev_file)); return svn_error_trace(svn_fs_fs__check_rep(rep, fs, hint, pool)); } else @@ -900,6 +902,8 @@ svn_fs_fs__check_rep(representation_t *rep, " in revision %ld"), apr_off_t_toa(pool, entry->offset), rep->item_index, rep->revision); + + SVN_ERR(svn_fs_fs__close_revision_file(&rev_file)); } else { Index: subversion/libsvn_fs_fs/pack.c =================================================================== --- subversion/libsvn_fs_fs/pack.c (revision 1559108) +++ subversion/libsvn_fs_fs/pack.c (working copy) @@ -1426,6 +1426,8 @@ append_revision(pack_context_t *context, svn_pool_destroy(iterpool); context->pack_offset += finfo.size; + SVN_ERR(svn_fs_fs__close_revision_file(rev_file)); + return SVN_NO_ERROR; } Index: subversion/libsvn_fs_fs/verify.c =================================================================== --- subversion/libsvn_fs_fs/verify.c (revision 1559108) +++ subversion/libsvn_fs_fs/verify.c (working copy) @@ -233,6 +233,8 @@ compare_l2p_to_p2l_index(svn_fs_t *fs, svn_pool_destroy(iterpool); + SVN_ERR(svn_fs_fs__close_revision_file(&rev_file)); + return SVN_NO_ERROR; } @@ -321,6 +323,8 @@ compare_p2l_to_l2p_index(svn_fs_t *fs, svn_pool_destroy(iterpool); + SVN_ERR(svn_fs_fs__close_revision_file(&rev_file)); + return SVN_NO_ERROR; } @@ -576,6 +580,8 @@ compare_p2l_to_rev(svn_fs_t *fs, svn_pool_destroy(iterpool); + SVN_ERR(svn_fs_fs__close_revision_file(rev_file)); + return SVN_NO_ERROR; }
Reduce the lifetime of open revision files within core FSFS routines. Whenever these files are only required in the scope of the routine itself, there is no reason not to close them before exiting that routine. Moreover, leaving them open can lead to various problems when attempting to reorganize the repository structure on Windows (e.g., ENOTEMPTY error when removing folders during 'svnadmin pack'). This changeset restores the 1.8.x behavior of these routines and unbreaks the upgrade_new_txns_to_log_addressing / upgrade_old_txns_to_log_addressing tests (fs-fs-pack-tests) on Windows. * subversion/libsvn_fs_fs/cached_data.c (get_node_revision_body, svn_fs_fs__check_rep): Call svn_fs_fs__close_revision_file(). * subversion/libsvn_fs_fs/pack.c (append_revision): Call svn_fs_fs__close_revision_file(). * subversion/libsvn_fs_fs/verify.c (compare_l2p_to_p2l_index, compare_p2l_to_l2p_index, compare_p2l_to_rev): Call svn_fs_fs__close_revision_file(). Patch by: Evgeny Kotkov <evgeny.kotkov{_AT_}visualsvn.com>