You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2012/03/09 22:23:49 UTC
svn commit: r1299054 - in
/subversion/branches/revprop-cache/subversion/libsvn_fs_fs: fs.h fs_fs.c
Author: stefan2
Date: Fri Mar 9 21:23:48 2012
New Revision: 1299054
URL: http://svn.apache.org/viewvc?rev=1299054&view=rev
Log:
On the revprop-cache branch: replace the revprop-gen file with
the use of the new svn_named_atomic API.
!!! Not tested, yet. Just committing things for review. !!!
* subversion/libsvn_fs_fs/fs.h
(PATH_REVPROP_GEN): drop
(fs_fs_data_t): remove cached revprop gen value; add shared mem
access objects
* subversion/libsvn_fs_fs/fs_fs.c
(REVPROP_CHANGE_TIMEOUT, ATOMIC_REVPROP_GENERATION,
ATOMIC_REVPROP_TIMEOUT): new constants
(path_revprop_generation): drop
(ensure_revprop_generation, ensure_revprop_timeout): new utilities
(read_revprop_generation): switch from file to shm access
(begin_revprop_change, end_revprop_change): new revprop update
communication functions
(check_revprop_generation, increment_revprop_generation): drop
(set_revision_proplist): if revprop cache has been enabled, call the
new update communication functions
(revision_proplist): if revprop cache has been enabled, call the
new reader function
(hotcopy_create_empty_dest, svn_fs_fs__create): drop handling
of revprop generation files
Modified:
subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs.h
subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c
Modified: subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs.h?rev=1299054&r1=1299053&r2=1299054&view=diff
==============================================================================
--- subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs.h Fri Mar 9 21:23:48 2012
@@ -34,6 +34,7 @@
#include "private/svn_fs_private.h"
#include "private/svn_sqlite.h"
#include "private/svn_mutex.h"
+#include "private/svn_named_atomic.h"
#ifdef __cplusplus
extern "C" {
@@ -60,8 +61,6 @@ extern "C" {
#define PATH_LOCKS_DIR "locks" /* Directory of locks */
#define PATH_MIN_UNPACKED_REV "min-unpacked-rev" /* Oldest revision which
has not been packed. */
-#define PATH_REVPROP_GEN "revprop-gen" /* File containing the
- revprop change counter */
/* If you change this, look at tests/svn_test_fs.c(maybe_install_fsfs_conf) */
#define PATH_CONFIG "fsfs.conf" /* Configuration */
@@ -240,11 +239,13 @@ typedef struct fs_fs_data_t
rep key (revision/offset) to svn_string_t. */
svn_cache__t *fulltext_cache;
- /* Revprop "generation" that is valid for this svn_fs_t.
- It is the revprop change counter read once from "revprop-gen".
- Will be read upon first access. 0 means that the value has not
- been read from disk, yet. */
- apr_int64_t revprop_generation;
+ /* Access object to the revprop "generation". Will be NULL until
+ the first access. */
+ svn_named_atomic__t *revprop_generation;
+
+ /* Access object to the revprop update timeout. Will be NULL until
+ the first access. */
+ svn_named_atomic__t *revprop_timeout;
/* Revision property cache. Maps from (rev,generation) to apr_hash_t. */
svn_cache__t *revprop_cache;
Modified: subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c?rev=1299054&r1=1299053&r2=1299054&view=diff
==============================================================================
--- subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/revprop-cache/subversion/libsvn_fs_fs/fs_fs.c Fri Mar 9 21:23:48 2012
@@ -92,6 +92,16 @@
Values < 1 disable deltification. */
#define SVN_FS_FS_MAX_DELTIFICATION_WALK 1023
+/* Give writing processes 10 seconds to replace an existing revprop
+ file with a new one. After that time, we assume that the writing
+ process got aborted and that we have re-read revprops. */
+#define REVPROP_CHANGE_TIMEOUT 10 * 1000000
+
+/* The following are names of atomics that will be used to communicate
+ * revprop updates across all processes on this machine. */
+#define ATOMIC_REVPROP_GENERATION "RevPropGeneration"
+#define ATOMIC_REVPROP_TIMEOUT "RevPropTimeout"
+
/* Following are defines that specify the textual elements of the
native filesystem directories and revision files. */
@@ -225,12 +235,6 @@ path_lock(svn_fs_t *fs, apr_pool_t *pool
}
static const char *
-path_revprop_generation(svn_fs_t *fs, apr_pool_t *pool)
-{
- return svn_dirent_join(fs->path, PATH_REVPROP_GEN, pool);
-}
-
-static const char *
path_rev_packed(svn_fs_t *fs, svn_revnum_t rev, const char *kind,
apr_pool_t *pool)
{
@@ -2707,103 +2711,129 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro
return SVN_NO_ERROR;
}
-/* Reads the revprop_gen file and writes the content into the
- REVPROP_GENERATION member of FS. Use pool for allocations. */
+/* Make sure the revprop_generation member in FS is set. */
static svn_error_t *
-read_revprop_generation(svn_fs_t *fs,
- apr_pool_t *pool)
+ensure_revprop_generation(svn_fs_t *fs)
{
fs_fs_data_t *ffd = fs->fsap_data;
- const char *path = path_revprop_generation(fs, pool);
- svn_error_t *err;
- char buf[80];
- int i;
+ return ffd->revprop_generation == NULL
+ ? svn_named_atomic__get(&ffd->revprop_generation,
+ ATOMIC_REVPROP_GENERATION,
+ TRUE)
+ : SVN_NO_ERROR;
+}
- /* Read the raw data from the file, if it exists. If it does
- not, set the generation to "1" and return.
- We don't want to have this function fail. So, patiently
- retry a couple of times the case the OS denied us access. */
- apr_pool_t *iterpool = svn_pool_create(pool);
- for (i = 0; i < RECOVERABLE_RETRY_COUNT; ++i)
- {
- apr_file_t *file;
- apr_size_t len = sizeof(buf);
-
- svn_pool_clear(iterpool);
+/* Make sure the revprop_timeout member in FS is set. */
+static svn_error_t *
+ensure_revprop_timeout(svn_fs_t *fs)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+
+ return ffd->revprop_timeout == NULL
+ ? svn_named_atomic__get(&ffd->revprop_timeout,
+ ATOMIC_REVPROP_TIMEOUT,
+ TRUE)
+ : SVN_NO_ERROR;
+}
- err = svn_io_file_open(&file, path, APR_READ | APR_BUFFERED,
- APR_OS_DEFAULT, iterpool);
- if (err && APR_STATUS_IS_ENOENT(err->apr_err))
+/* Read the current revprop generation and return it in *GENERATION.
+ Also, detect aborted / crashed writers and recover from that.
+ Use the access object in FS to set the shared mem values. */
+static svn_error_t *
+read_revprop_generation(svn_fs_t *fs,
+ apr_int64_t *generation)
+{
+ apr_int64_t current = 0;
+ fs_fs_data_t *ffd = fs->fsap_data;
+
+ /* read the current revprop generation number */
+ SVN_ERR(ensure_revprop_generation(fs));
+ SVN_ERR(svn_named_atomic__read(¤t, ffd->revprop_generation));
+
+ /* is an unfinished revprop write under the way? */
+ if (current % 2)
+ {
+ apr_int64_t timeout = 0;
+
+ /* read timeout for the write operation */
+ SVN_ERR(ensure_revprop_timeout(fs));
+ SVN_ERR(svn_named_atomic__read(&timeout, ffd->revprop_timeout));
+
+ /* has the writer process been aborted,
+ * i.e. has the timeout been reached?
+ */
+ if (apr_time_now() > timeout)
{
- /* No-one changed a revprop -> we are still at gen 1. */
- ffd->revprop_generation = 1;
- svn_error_clear(err);
- return SVN_NO_ERROR;
+ /* Cause everyone to re-read revprops upon their next access.
+ * Keep in mind that we may not be the only one trying to do it.
+ */
+ while (current % 2)
+ SVN_ERR(svn_named_atomic__add(¤t,
+ 1,
+ ffd->revprop_generation));
}
- svn_error_clear(err);
-
- RETRY_RECOVERABLE(err, file,
- svn_io_read_length_line(file,
- buf,
- &len,
- iterpool));
- IGNORE_RECOVERABLE(err, svn_io_file_close(file,
- iterpool));
-
- break;
}
- SVN_ERR(err);
-
- svn_pool_destroy(iterpool);
-
- /* Check that the first line contains only digits. */
- SVN_ERR(check_file_buffer_numeric(buf, 0, path,
- "Revprop generations", pool));
- SVN_ERR(svn_cstring_atoi64(&ffd->revprop_generation, buf));
-
- /* Graceful behavior in case someone put a "0" in the file. */
- if (ffd->revprop_generation <= 0)
- ffd->revprop_generation = 1;
+ /* return the value we just got */
+ *generation = current;
return SVN_NO_ERROR;
}
+/* Set the revprop generation to the next odd number to indicate that
+ there is a revprop write process under way. If that times out,
+ readers shall recover from that state & re-read revprops.
+ Use the access object in FS to set the shared mem value. */
static svn_error_t *
-check_revprop_generation(svn_fs_t *fs,
- apr_pool_t *pool)
+begin_revprop_change(svn_fs_t *fs)
{
+ apr_int64_t current;
fs_fs_data_t *ffd = fs->fsap_data;
- return ffd->revprop_generation == 0
- ? read_revprop_generation(fs, pool)
- : SVN_NO_ERROR;
+ /* set the timeout for the write operation */
+ SVN_ERR(ensure_revprop_timeout(fs));
+ SVN_ERR(svn_named_atomic__write(NULL,
+ apr_time_now() + REVPROP_CHANGE_TIMEOUT,
+ ffd->revprop_timeout));
+
+ /* set the revprop generation to an odd value to indicate
+ * that a write is in progress
+ */
+ SVN_ERR(ensure_revprop_generation(fs));
+ do
+ {
+ SVN_ERR(svn_named_atomic__add(¤t,
+ 1,
+ ffd->revprop_generation));
+ }
+ while (current % 2 == 0);
+
+ return SVN_NO_ERROR;
}
+/* Set the revprop generation to the next even number to indicate that
+ a) readers shall re-read revprops, and
+ b) the write process has been completed (no recovery required)
+ Use the access object in FS to set the shared mem value. */
static svn_error_t *
-increment_revprop_generation(svn_fs_t *fs,
- apr_pool_t *pool)
+end_revprop_change(svn_fs_t *fs)
{
+ apr_int64_t current = 1;
fs_fs_data_t *ffd = fs->fsap_data;
- const char *path = path_revprop_generation(fs, pool);
- const char *tmp_filename;
- svn_string_t *generation;
-
- SVN_ERR(read_revprop_generation(fs, pool));
-
- /* Increment the key and add a trailing \n to the string so the
- txn-current file has a newline in it. */
- ++ffd->revprop_generation;
- generation = svn_string_createf(pool, "%" APR_INT64_T_FMT "\n",
- ffd->revprop_generation);
+ /* set the revprop generation to an even value to indicate
+ * that a write has been completed
+ */
+ SVN_ERR(ensure_revprop_generation(fs));
+ do
+ {
+ SVN_ERR(svn_named_atomic__add(¤t,
+ 1,
+ ffd->revprop_generation));
+ }
+ while (current % 2);
- SVN_ERR(svn_io_write_unique(&tmp_filename,
- svn_dirent_dirname(path, pool),
- generation->data, generation->len,
- svn_io_file_del_none, pool));
- return move_into_place(tmp_filename, path,
- svn_fs_fs__path_current(fs, pool), pool);
+ return SVN_NO_ERROR;
}
/* Set the revision property list of revision REV in filesystem FS to
@@ -2822,10 +2852,12 @@ set_revision_proplist(svn_fs_t *fs,
const char *tmp_path;
const char *perms_reference;
svn_stream_t *stream;
- svn_node_kind_t kind;
+ svn_node_kind_t kind = svn_node_none;
+ fs_fs_data_t *ffd = fs->fsap_data;
/* test whether revprops already exist for this revision */
- SVN_ERR(svn_io_check_path(final_path, &kind, pool));
+ if (ffd->revprop_cache)
+ SVN_ERR(svn_io_check_path(final_path, &kind, pool));
/* ### do we have a directory sitting around already? we really shouldn't
### have to get the dirname here. */
@@ -2840,13 +2872,17 @@ set_revision_proplist(svn_fs_t *fs,
file won't exist and therefore can't serve as its own reference.
(Whereas the rev file should already exist at this point.) */
SVN_ERR(svn_fs_fs__path_rev_absolute(&perms_reference, fs, rev, pool));
+
+ /* Now, we are actually (potentially) replacing revprops. Make sure
+ that all other threads and processes will know about this. */
+ if (kind != svn_node_none)
+ SVN_ERR(begin_revprop_change(fs));
+
SVN_ERR(move_into_place(tmp_path, final_path, perms_reference, pool));
- /* Invalidate all cached revprops for this FS and for all other
- users that haven't read any revprops, YET. Since writing revprops
- implies a write lock, there can be no races. */
+ /* Indicate that the update (if relevant) has been completed. */
if (kind != svn_node_none)
- SVN_ERR(increment_revprop_generation(fs, pool));
+ SVN_ERR(end_revprop_change(fs));
return SVN_NO_ERROR;
}
@@ -2865,15 +2901,18 @@ revision_proplist(apr_hash_t **proplist_
const char *key;
SVN_ERR(ensure_revision_exists(fs, rev, pool));
- SVN_ERR(check_revprop_generation(fs, pool));
/* Try cache lookup first. */
- key = svn_fs_fs__combine_two_numbers(rev, ffd->revprop_generation, pool);
if (ffd->revprop_cache)
{
+ apr_int64_t generation;
svn_boolean_t is_cached;
+
+ SVN_ERR(read_revprop_generation(fs, &generation));
+
+ key = svn_fs_fs__combine_two_numbers(rev, generation, pool);
SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
- ffd->revprop_cache, key, pool));
+ ffd->revprop_cache, key, pool));
if (is_cached)
return SVN_NO_ERROR;
}
@@ -6909,9 +6948,6 @@ svn_fs_fs__create(svn_fs_t *fs,
"", pool));
}
- /* Create the revprop generation tracking file. */
- SVN_ERR(increment_revprop_generation(fs, pool));
-
/* This filesystem is ready. Stamp it with a format number. */
SVN_ERR(write_format(path_format(fs, pool),
ffd->format, ffd->max_files_per_dir, FALSE, pool));
@@ -9026,14 +9062,6 @@ hotcopy_create_empty_dest(svn_fs_t *src_
"", pool));
}
- /* Copy the revprop generation file if it exists in SRC_FS. */
- SVN_ERR(svn_io_check_path(path_revprop_generation(src_fs, pool),
- &kind, pool));
- if (kind == svn_node_file)
- SVN_ERR(svn_io_copy_file(path_revprop_generation(src_fs, pool),
- path_revprop_generation(dst_fs, pool),
- TRUE, pool));
-
dst_ffd->youngest_rev_cache = 0;
return SVN_NO_ERROR;
}