aboutsummaryrefslogtreecommitdiff
path: root/subversion/libsvn_fs_x/util.c
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2018-05-08 03:44:38 +0000
committerPeter Wemm <peter@FreeBSD.org>2018-05-08 03:44:38 +0000
commit3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch)
tree7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/libsvn_fs_x/util.c
parenta55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff)
Diffstat (limited to 'subversion/libsvn_fs_x/util.c')
-rw-r--r--subversion/libsvn_fs_x/util.c182
1 files changed, 69 insertions, 113 deletions
diff --git a/subversion/libsvn_fs_x/util.c b/subversion/libsvn_fs_x/util.c
index da004ad8febb..bab47fc6d01c 100644
--- a/subversion/libsvn_fs_x/util.c
+++ b/subversion/libsvn_fs_x/util.c
@@ -110,11 +110,17 @@ svn_fs_x__path_current(svn_fs_t *fs,
}
const char *
+svn_fs_x__path_next(svn_fs_t *fs,
+ apr_pool_t *result_pool)
+{
+ return svn_dirent_join(fs->path, PATH_NEXT, result_pool);
+}
+
+const char *
svn_fs_x__path_txn_current(svn_fs_t *fs,
apr_pool_t *result_pool)
{
- return svn_dirent_join(fs->path, PATH_TXN_CURRENT,
- result_pool);
+ return svn_dirent_join(fs->path, PATH_TXN_CURRENT, result_pool);
}
const char *
@@ -147,14 +153,12 @@ svn_fs_x__path_revprop_generation(svn_fs_t *fs,
/* Return the full path of the file FILENAME within revision REV's shard in
* FS. If FILENAME is NULL, return the shard directory directory itself.
- * REVPROPS indicates the parent of the shard parent folder ("revprops" or
- * "revs"). PACKED says whether we want the packed shard's name.
+ * PACKED says whether we want the packed shard's name.
*
* Allocate the result in RESULT_POOL.
*/static const char*
construct_shard_sub_path(svn_fs_t *fs,
svn_revnum_t rev,
- svn_boolean_t revprops,
svn_boolean_t packed,
const char *filename,
apr_pool_t *result_pool)
@@ -162,9 +166,6 @@ construct_shard_sub_path(svn_fs_t *fs,
svn_fs_x__data_t *ffd = fs->fsap_data;
char buffer[SVN_INT64_BUFFER_SIZE + sizeof(PATH_EXT_PACKED_SHARD)] = { 0 };
- /* Select the appropriate parent path constant. */
- const char *parent = revprops ? PATH_REVPROPS_DIR : PATH_REVS_DIR;
-
/* String containing the shard number. */
apr_size_t len = svn__i64toa(buffer, rev / ffd->max_files_per_dir);
@@ -173,7 +174,7 @@ construct_shard_sub_path(svn_fs_t *fs,
strncpy(buffer + len, PATH_EXT_PACKED_SHARD, sizeof(buffer) - len - 1);
/* This will also work for NULL FILENAME as well. */
- return svn_dirent_join_many(result_pool, fs->path, parent, buffer,
+ return svn_dirent_join_many(result_pool, fs->path, PATH_REVS_DIR, buffer,
filename, SVN_VA_NULL);
}
@@ -184,15 +185,15 @@ svn_fs_x__path_rev_packed(svn_fs_t *fs,
apr_pool_t *result_pool)
{
assert(svn_fs_x__is_packed_rev(fs, rev));
- return construct_shard_sub_path(fs, rev, FALSE, TRUE, kind, result_pool);
+ return construct_shard_sub_path(fs, rev, TRUE, kind, result_pool);
}
const char *
-svn_fs_x__path_rev_shard(svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *result_pool)
+svn_fs_x__path_shard(svn_fs_t *fs,
+ svn_revnum_t rev,
+ apr_pool_t *result_pool)
{
- return construct_shard_sub_path(fs, rev, FALSE, FALSE, NULL, result_pool);
+ return construct_shard_sub_path(fs, rev, FALSE, NULL, result_pool);
}
const char *
@@ -200,11 +201,12 @@ svn_fs_x__path_rev(svn_fs_t *fs,
svn_revnum_t rev,
apr_pool_t *result_pool)
{
- char buffer[SVN_INT64_BUFFER_SIZE];
- svn__i64toa(buffer, rev);
+ char buffer[SVN_INT64_BUFFER_SIZE + 1];
+ buffer[0] = 'r';
+ svn__i64toa(buffer + 1, rev);
assert(! svn_fs_x__is_packed_rev(fs, rev));
- return construct_shard_sub_path(fs, rev, FALSE, FALSE, buffer, result_pool);
+ return construct_shard_sub_path(fs, rev, FALSE, buffer, result_pool);
}
const char *
@@ -218,19 +220,11 @@ svn_fs_x__path_rev_absolute(svn_fs_t *fs,
}
const char *
-svn_fs_x__path_revprops_shard(svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *result_pool)
-{
- return construct_shard_sub_path(fs, rev, TRUE, FALSE, NULL, result_pool);
-}
-
-const char *
-svn_fs_x__path_revprops_pack_shard(svn_fs_t *fs,
+svn_fs_x__path_pack_shard(svn_fs_t *fs,
svn_revnum_t rev,
apr_pool_t *result_pool)
{
- return construct_shard_sub_path(fs, rev, TRUE, TRUE, NULL, result_pool);
+ return construct_shard_sub_path(fs, rev, TRUE, NULL, result_pool);
}
const char *
@@ -238,11 +232,17 @@ svn_fs_x__path_revprops(svn_fs_t *fs,
svn_revnum_t rev,
apr_pool_t *result_pool)
{
- char buffer[SVN_INT64_BUFFER_SIZE];
- svn__i64toa(buffer, rev);
+ char buffer[SVN_INT64_BUFFER_SIZE + 1];
+ buffer[0] = 'p';
+ svn__i64toa(buffer + 1, rev);
assert(! svn_fs_x__is_packed_revprop(fs, rev));
- return construct_shard_sub_path(fs, rev, TRUE, FALSE, buffer, result_pool);
+
+ /* Revprops for packed r0 are not packed, yet stored in the packed shard.
+ Hence, the second flag must check for packed _rev_ - not revprop. */
+ return construct_shard_sub_path(fs, rev,
+ svn_fs_x__is_packed_rev(fs, rev) /* sic! */,
+ buffer, result_pool);
}
const char *
@@ -340,14 +340,6 @@ svn_fs_x__path_txn_props(svn_fs_t *fs,
return construct_txn_path(fs, txn_id, PATH_TXN_PROPS, result_pool);
}
-const char *
-svn_fs_x__path_txn_props_final(svn_fs_t *fs,
- svn_fs_x__txn_id_t txn_id,
- apr_pool_t *result_pool)
-{
- return construct_txn_path(fs, txn_id, PATH_TXN_PROPS_FINAL, result_pool);
-}
-
const char*
svn_fs_x__path_l2p_proto_index(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
@@ -543,6 +535,7 @@ svn_fs_x__write_min_unpacked_rev(svn_fs_t *fs,
svn_revnum_t revnum,
apr_pool_t *scratch_pool)
{
+ svn_fs_x__data_t *ffd = fs->fsap_data;
const char *final_path;
char buf[SVN_INT64_BUFFER_SIZE];
apr_size_t len = svn__i64toa(buf, revnum);
@@ -550,8 +543,9 @@ svn_fs_x__write_min_unpacked_rev(svn_fs_t *fs,
final_path = svn_fs_x__path_min_unpacked_rev(fs, scratch_pool);
- SVN_ERR(svn_io_write_atomic(final_path, buf, len + 1,
- final_path /* copy_perms */, scratch_pool));
+ SVN_ERR(svn_io_write_atomic2(final_path, buf, len + 1,
+ final_path /* copy_perms */,
+ ffd->flush_to_disk, scratch_pool));
return SVN_NO_ERROR;
}
@@ -574,7 +568,7 @@ svn_fs_x__read_current(svn_revnum_t *rev,
return SVN_NO_ERROR;
}
-/* Atomically update the 'current' file to hold the specifed REV.
+/* Atomically update the 'current' file to hold the specified REV.
Perform temporary allocations in SCRATCH_POOL. */
svn_error_t *
svn_fs_x__write_current(svn_fs_t *fs,
@@ -583,17 +577,28 @@ svn_fs_x__write_current(svn_fs_t *fs,
{
char *buf;
const char *tmp_name, *name;
+ apr_file_t *file;
/* Now we can just write out this line. */
buf = apr_psprintf(scratch_pool, "%ld\n", rev);
name = svn_fs_x__path_current(fs, scratch_pool);
- SVN_ERR(svn_io_write_unique(&tmp_name,
- svn_dirent_dirname(name, scratch_pool),
- buf, strlen(buf),
- svn_io_file_del_none, scratch_pool));
+ tmp_name = svn_fs_x__path_next(fs, scratch_pool);
- return svn_fs_x__move_into_place(tmp_name, name, name, scratch_pool);
+ SVN_ERR(svn_io_file_open(&file, tmp_name,
+ APR_WRITE | APR_CREATE | APR_BUFFERED,
+ APR_OS_DEFAULT, scratch_pool));
+ SVN_ERR(svn_io_file_write_full(file, buf, strlen(buf), NULL,
+ scratch_pool));
+ SVN_ERR(svn_io_file_close(file, scratch_pool));
+
+ /* Copying permissions is a no-op on WIN32. */
+ SVN_ERR(svn_io_copy_perms(name, tmp_name, scratch_pool));
+
+ /* Move the file into place. */
+ SVN_ERR(svn_io_file_rename2(tmp_name, name, TRUE, scratch_pool));
+
+ return SVN_NO_ERROR;
}
@@ -640,22 +645,6 @@ svn_fs_x__try_stringbuf_from_file(svn_stringbuf_t **content,
/* Fetch the current offset of FILE into *OFFSET_P. */
svn_error_t *
-svn_fs_x__get_file_offset(apr_off_t *offset_p,
- apr_file_t *file,
- apr_pool_t *scratch_pool)
-{
- apr_off_t offset;
-
- /* Note that, for buffered files, one (possibly surprising) side-effect
- of this call is to flush any unwritten data to disk. */
- offset = 0;
- SVN_ERR(svn_io_file_seek(file, APR_CUR, &offset, scratch_pool));
- *offset_p = offset;
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
svn_fs_x__read_content(svn_stringbuf_t **content,
const char *fname,
apr_pool_t *result_pool)
@@ -711,66 +700,33 @@ svn_fs_x__read_number_from_stream(apr_int64_t *result,
return SVN_NO_ERROR;
}
-
-/* Move a file into place from OLD_FILENAME in the transactions
- directory to its final location NEW_FILENAME in the repository. On
- Unix, match the permissions of the new file to the permissions of
- PERMS_REFERENCE. Temporary allocations are from SCRATCH_POOL.
-
- This function almost duplicates svn_io_file_move(), but it tries to
- guarantee a flush. */
svn_error_t *
svn_fs_x__move_into_place(const char *old_filename,
const char *new_filename,
const char *perms_reference,
+ svn_fs_x__batch_fsync_t *batch,
apr_pool_t *scratch_pool)
{
- svn_error_t *err;
-
+ /* Copying permissions is a no-op on WIN32. */
SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, scratch_pool));
+ /* We use specific 'fsyncing move' Win32 API calls on Windows while the
+ * directory update fsync is POSIX-only. Moreover, there tend to be only
+ * a few moved files (1 or 2) per batch.
+ *
+ * Therefore, we use the platform-optimized "immediate" fsyncs on all
+ * non-POSIX platforms and the "scheduled" fsyncs on POSIX only.
+ */
+#if defined(SVN_ON_POSIX)
/* Move the file into place. */
- err = svn_io_file_rename(old_filename, new_filename, scratch_pool);
- if (err && APR_STATUS_IS_EXDEV(err->apr_err))
- {
- apr_file_t *file;
-
- /* Can't rename across devices; fall back to copying. */
- svn_error_clear(err);
- err = SVN_NO_ERROR;
- SVN_ERR(svn_io_copy_file(old_filename, new_filename, TRUE,
- scratch_pool));
-
- /* Flush the target of the copy to disk. */
- SVN_ERR(svn_io_file_open(&file, new_filename, APR_READ,
- APR_OS_DEFAULT, scratch_pool));
- /* ### BH: Does this really guarantee a flush of the data written
- ### via a completely different handle on all operating systems?
- ###
- ### Maybe we should perform the copy ourselves instead of making
- ### apr do that and flush the real handle? */
- SVN_ERR(svn_io_file_flush_to_disk(file, scratch_pool));
- SVN_ERR(svn_io_file_close(file, scratch_pool));
- }
- if (err)
- return svn_error_trace(err);
-
-#ifdef __linux__
- {
- /* Linux has the unusual feature that fsync() on a file is not
- enough to ensure that a file's directory entries have been
- flushed to disk; you have to fsync the directory as well.
- On other operating systems, we'd only be asking for trouble
- by trying to open and fsync a directory. */
- const char *dirname;
- apr_file_t *file;
-
- dirname = svn_dirent_dirname(new_filename, scratch_pool);
- SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
- scratch_pool));
- SVN_ERR(svn_io_file_flush_to_disk(file, scratch_pool));
- SVN_ERR(svn_io_file_close(file, scratch_pool));
- }
+ SVN_ERR(svn_io_file_rename2(old_filename, new_filename, FALSE,
+ scratch_pool));
+
+ /* Schedule for synchronization. */
+ SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, new_filename, scratch_pool));
+#else
+ SVN_ERR(svn_io_file_rename2(old_filename, new_filename, TRUE,
+ scratch_pool));
#endif
return SVN_NO_ERROR;