Index: subversion/libsvn_fs_fs/util.c =================================================================== --- subversion/libsvn_fs_fs/util.c (revision 1687052) +++ subversion/libsvn_fs_fs/util.c (working copy) @@ -644,13 +644,13 @@ /* APR will *not* error out on Win32 if this requires a copy instead of of a move. */ SVN_ERR(svn_io_file_rename(old_filename, new_filename, pool)); - +#if 0 /* Flush the target of the copy to disk. */ SVN_ERR(svn_io_file_open(&file, new_filename, APR_WRITE, APR_OS_DEFAULT, pool)); SVN_ERR(svn_io_file_flush_to_disk(file, pool)); SVN_ERR(svn_io_file_close(file, pool)); - +#endif /* Copying permissions is a no-op on WIN32. */ #else Index: subversion/tests/libsvn_repos/repos-test.c =================================================================== --- subversion/tests/libsvn_repos/repos-test.c (revision 1687052) +++ subversion/tests/libsvn_repos/repos-test.c (working copy) @@ -23,6 +23,7 @@ #include #include #include +#include #include "../svn_test.h" @@ -3612,9 +3613,132 @@ return SVN_NO_ERROR; } +struct commit_file_baton_t { + const char *repos_path; + const char *fs_path; + apr_pool_t *pool; + svn_error_t *err; + apr_thread_t *tid; + int num; +}; + +void fs_warning(void *baton, svn_error_t *err) +{ + svn_handle_warning(stderr, err); +} + +svn_error_t * +commit_file_child_body(struct commit_file_baton_t *baton, apr_pool_t *pool) +{ + svn_repos_t *repos; + svn_revnum_t rev; + apr_pool_t *iterpool; + + SVN_ERR(svn_repos_open(&repos, baton->repos_path, pool)); + svn_fs_set_warning_func(svn_repos_fs(repos), fs_warning, NULL); + iterpool = svn_pool_create(pool); + + rev = 0; + while (TRUE) + { + svn_fs_txn_t *txn; + svn_fs_root_t *root; + svn_stringbuf_t *buf; + int i; + + svn_pool_clear(iterpool); + + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, rev, + "author", "log", iterpool)); + + SVN_ERR(svn_fs_txn_root(&root, txn, iterpool)); + if (rev == 0) + { + SVN_ERR(svn_fs_make_file(root, baton->fs_path, iterpool)); + } + + buf = svn_stringbuf_create_ensure(100*100, iterpool); + for (i = 0; i < 100; i++) + { + svn_stringbuf_appendfill(buf, rand() % 200 + 1, 100); + } + + SVN_ERR(svn_test__set_file_contents(root, baton->fs_path, + buf->data, iterpool)); + + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &rev, txn, iterpool)); + + fprintf(stderr, "Thread %d: Committed %ld\n", baton->num, rev); + } + + svn_pool_destroy(iterpool); + return SVN_NO_ERROR; +} + +static void * APR_THREAD_FUNC +commit_file_child(apr_thread_t *tid, void *data) +{ + struct commit_file_baton_t *baton = data; + + baton->err = commit_file_child_body(baton, baton->pool); + if (baton->err) + svn_handle_error2(baton->err, stderr, FALSE, "test:"); + svn_pool_destroy(baton->pool); + apr_thread_exit(tid, 0); + return NULL; +} + + +static svn_error_t * +test_concurrent_commits(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_repos_t *repos; + int i; + struct commit_file_baton_t threads[4]; + + /* Create test repository. */ + SVN_ERR(svn_test__create_repos(&repos, + "test-repo-concurrent-commits", + opts, pool)); + + for (i = 0; i < sizeof(threads) / sizeof(threads[0]); i++) + { + apr_status_t status; + apr_threadattr_t *tattr; + threads[i].pool = svn_pool_create(pool); + threads[i].err = SVN_NO_ERROR; + threads[i].repos_path = "test-repo-concurrent-commits"; + threads[i].fs_path = apr_psprintf(pool, "/file-%d", i); + threads[i].num = i; + + status = apr_threadattr_create(&tattr, pool); + if (status) + return svn_error_wrap_apr(status, "Can't create threadattr"); + + status = apr_thread_create(&threads[i].tid, tattr, commit_file_child, &threads[i], pool); + if (status) + return svn_error_wrap_apr(status, "Can't create thread"); + } + + for (i = 0; i < sizeof(threads) / sizeof(threads[0]); i++) + { + apr_status_t status; + apr_status_t child_status; + status = apr_thread_join(&child_status, threads[i].tid); + if (status) + return svn_error_wrap_apr(status, "Can't join thread"); + + if (threads[i].err) + return svn_error_trace(threads[i].err); + } + + return SVN_NO_ERROR; +} + /* The test table. */ -static int max_threads = 4; +static int max_threads = 1; static struct svn_test_descriptor_t test_funcs[] = { @@ -3667,6 +3791,8 @@ "test test_repos_fs_type"), SVN_TEST_OPTS_PASS(deprecated_access_context_api, "test deprecated access context api"), + SVN_TEST_OPTS_PASS(test_concurrent_commits, + "perform concurrent commits"), SVN_TEST_NULL };