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 2011/10/29 02:33:21 UTC
svn commit: r1190714 - in /subversion/branches/file-handle-cache: ./
subversion/include/private/ subversion/libsvn_fs_fs/
subversion/libsvn_subr/ subversion/mod_dav_svn/ subversion/svnadmin/
subversion/svnserve/
Author: stefan2
Date: Sat Oct 29 00:33:21 2011
New Revision: 1190714
URL: http://svn.apache.org/viewvc?rev=1190714&view=rev
Log:
Merging relevant changes from the performance branch, part 4:
r982057,982360,982375,982391,982417,983385,983437,985602,985670,987875,
992905,1003430,1029082,1029381,1029408,1030759,1037466,1037470,1037548,
1037552,1037586,1037588,1067129-1067130
and resolved numerous intermediate conflicts
Modified:
subversion/branches/file-handle-cache/ (props changed)
subversion/branches/file-handle-cache/build.conf
subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h (contents, props changed)
subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c
subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs.h
subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c
subversion/branches/file-handle-cache/subversion/libsvn_subr/stream.c
subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c (contents, props changed)
subversion/branches/file-handle-cache/subversion/mod_dav_svn/mod_dav_svn.c
subversion/branches/file-handle-cache/subversion/svnadmin/main.c
subversion/branches/file-handle-cache/subversion/svnserve/main.c
subversion/branches/file-handle-cache/subversion/svnserve/server.h
Propchange: subversion/branches/file-handle-cache/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat Oct 29 00:33:21 2011
@@ -38,7 +38,7 @@
/subversion/branches/log-g-performance:870941-871032
/subversion/branches/merge-skips-obstructions:874525-874615
/subversion/branches/nfc-nfd-aware-client:870276,870376
-/subversion/branches/performance:979193,980118,981087,981090-981091,981189,981194,981204,981287,981665,981684,981827-981828,982043,982355,983398,983406,983430,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601,985603,985606,985669,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,102933
5-1029336,1029339-1029340,1029342,1029344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
+/subversion/branches/performance:979193,980118,981087,981090-981091,981189,981194,981204,981287,981665,981684,981827-981828,982043,982057,982355,982360,982375,982391,982417,983385,983398,983406,983430,983437,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601-985603,985606,985669-985670,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987875,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904-992905,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1003430,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,
1029082,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,1029335-1029336,1029339-1029340,1029342,1029344,1029381,1029408,1030759,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1037466,1037470,1037548,1037552,1037586,1037588,1039511,1043705,1053735,1056015,1066452,1067129-1067130,1067683,1067697-1078365
/subversion/branches/py-tests-as-modules:956579-1033052
/subversion/branches/ra_serf-digest-authn:875693-876404
/subversion/branches/reintegrate-improvements:873853-874164
Modified: subversion/branches/file-handle-cache/build.conf
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/build.conf?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/build.conf (original)
+++ subversion/branches/file-handle-cache/build.conf Sat Oct 29 00:33:21 2011
@@ -332,6 +332,7 @@ msvc-export =
private\svn_temp_serializer.h private\svn_io_private.h
private\svn_string_private.h private\svn_magic.h
private\svn_subr_private.h private\svn_mutex.h
+ private\svn_temp_serializer.h private\svn_file_handle_cache.h
# Working copy management lib
[libsvn_wc]
Modified: subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h (original)
+++ subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h Sat Oct 29 00:33:21 2011
@@ -24,8 +24,7 @@
* @brief File handle cache API
*/
-#include <apr_file_io.h>
-#include "svn_types.h"
+#include "svn_io.h"
/**
* An opaque structure representing a cache for open file handles.
@@ -86,6 +85,21 @@ svn_file_handle_cache__get_apr_handle(sv
const char *
svn_file_handle_cache__get_name(svn_file_handle_cache__handle_t *f);
+/** Create a stream from a cached file handle. For convenience, if @a file
+ * is @c NULL, an empty stream created by svn_stream_empty() is returned.
+ *
+ * This function should normally be called with @a disown set to FALSE,
+ * in which case closing the stream will also return the file handle to
+ * the respective cache object.
+ *
+ * If @a disown is TRUE, the stream will disown the file handle, meaning
+ * that svn_stream_close() will not close the cached file handle.
+ */
+svn_stream_t *
+svn_stream__from_cached_file_handle(svn_file_handle_cache__handle_t *file,
+ svn_boolean_t disown,
+ apr_pool_t *pool);
+
/**
* Return the cached file handle @a f to the cache. Depending on the number
* of open handles, the underlying handle may actually get closed. If @a f
@@ -113,3 +127,4 @@ svn_file_handle_cache__create_cache(svn_
size_t max_handles,
svn_boolean_t thread_safe,
apr_pool_t *pool);
+
Propchange: subversion/branches/file-handle-cache/subversion/include/private/svn_file_handle_cache.h
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat Oct 29 00:33:21 2011
@@ -1 +1 @@
-/subversion/branches/performance/subversion/include/private/svn_file_handle_cache.h:981665,981828
+/subversion/branches/performance/subversion/include/private/svn_file_handle_cache.h:981665,981828,983385,983437
Modified: subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/caching.c Sat Oct 29 00:33:21 2011
@@ -92,6 +92,34 @@ warn_on_cache_errors(svn_error_t *err,
return SVN_NO_ERROR;
}
+static apr_status_t
+close_unused_file_handles(void *cache_void)
+{
+ svn_file_handle_cache_t *cache = cache_void;
+ apr_status_t result = APR_SUCCESS;
+
+ /* Close all file handles that are not in use anymore. So, as long as
+ * no requests to a given repository are being processed, we may change
+ * the file content and / or structure. However, content that has been
+ * cached *above* the APR layer (e.g. fulltext caches) will *not* be
+ * changed and may become inconsistent with the disk content.
+ *
+ * This will cause concurrent threads to perform somewhat slower because
+ * they might have put those handles to good use a few moments later.
+ * They now have to actually re-open the respective files.
+ */
+ svn_error_t *err = svn_file_handle_cache__flush(cache);
+
+ /* process error returns */
+ if (err)
+ {
+ result = err->apr_err;
+ svn_error_clear(err);
+ }
+
+ return result;
+}
+
#ifdef SVN_DEBUG_CACHE_DUMP_STATS
/* Baton to be used for the dump_cache_statistics() pool cleanup function, */
struct dump_cache_baton_t
@@ -189,6 +217,24 @@ init_callbacks(svn_cache__t *cache,
return SVN_NO_ERROR;
}
+/* Access the process-global (singleton) open file handle cache. The first
+ * call will automatically allocate the cache using the current cache config.
+ * Even for file handle limit of 0, a cache object will be returned.
+ */
+static svn_file_handle_cache_t *
+get_global_file_handle_cache(void)
+{
+ static svn_file_handle_cache_t *cache = NULL;
+
+ if (!cache)
+ svn_file_handle_cache__create_cache(&cache,
+ cache_settings.file_handle_count,
+ !cache_settings.single_threaded,
+ svn_pool_create(NULL));
+
+ return cache;
+}
+
/* Sets *CACHE_P to cache instance based on provided options.
* Creates memcache if MEMCACHE is not NULL. Creates membuffer cache if
* MEMBUFFER is not NULL. Fallbacks to inprocess cache if MEMCACHE and
@@ -260,11 +306,17 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
membuffer = svn_cache__get_global_membuffer_cache();
- /* Make the cache for revision roots. For the vast majority of
- * commands, this is only going to contain a few entries (svnadmin
- * dump/verify is an exception here), so to reduce overhead let's
- * try to keep it to just one page. I estimate each entry has about
- * 72 bytes of overhead (svn_revnum_t key, svn_fs_id_t +
+ /* Schedule file handle cache cleanup after finishing the request. */
+ apr_pool_cleanup_register(pool,
+ svn_fs__get_global_file_handle_cache(),
+ close_unused_file_handles,
+ apr_pool_cleanup_null);
+
+ /* Make the caches for non-packed and packed revision roots. For the
+ * vastmajority of commands, this is only going to contain a few entries
+ * (svnadmin dump/verify is an exception here), so to reduce overhead
+ * let's try to keep it to just one page. I estimate each entry has
+ * about 72 bytes of overhead (svn_revnum_t key, svn_fs_id_t +
* id_private_t + 3 strings for value, and the cache_entry); the
* default pool size is 8192, so about a hundred should fit
* comfortably. */
@@ -373,6 +425,9 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(init_callbacks(ffd->node_revision_cache, fs, no_handler, pool));
+ /* initialize file handle cache as configured */
+ ffd->file_handle_cache = get_global_file_handle_cache();
+
return SVN_NO_ERROR;
}
Modified: subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs.h?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs.h Sat Oct 29 00:33:21 2011
@@ -34,6 +34,7 @@
#include "private/svn_fs_private.h"
#include "private/svn_sqlite.h"
#include "private/svn_mutex.h"
+#include "private/svn_file_handle_cache.h"
#ifdef __cplusplus
extern "C" {
@@ -221,9 +222,15 @@ typedef struct fs_fs_data_t
multiple svn_fs_t's for the same filesystem.) */
/* A cache of revision root IDs, mapping from (svn_revnum_t *) to
- (svn_fs_id_t *). (Not threadsafe.) */
+ (svn_fs_id_t *). Some of the IDs may belong to non-packed revs
+ but these will never be read. This is guaranteed by the fact
+ that the transition from non-packed to packed is irreversable. */
svn_cache__t *rev_root_id_cache;
+ /* Similar to @ref rev_root_id_cache but all IDs are guaranteed
+ to belong to packed revisions. */
+ svn_cache__t *packed_rev_root_id_cache;
+
/* DAG node cache for immutable nodes */
svn_cache__t *rev_node_cache;
@@ -254,6 +261,9 @@ typedef struct fs_fs_data_t
unparsed FS ID to ###x. NULL outside transactions. */
svn_cache__t *txn_dir_cache;
+ /* Reference to the process-global open file handle cache */
+ svn_file_handle_cache_t *file_handle_cache;
+
/* Data shared between all svn_fs_t objects for a given filesystem. */
fs_fs_shared_data_t *shared;
Modified: subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_fs_fs/fs_fs.c Sat Oct 29 00:33:21 2011
@@ -114,6 +114,17 @@
#define REP_PLAIN "PLAIN"
#define REP_DELTA "DELTA"
+/* Cookies used to classify cached file handle usage */
+/* Used whenever no other specific region of the rev file is being read. */
+#define DEFAULT_FILE_COOKIE 0
+
+/* Used when reading representation data.
+ * Since this is often interleaved with other reads, use a separate
+ * cookie (hence a separate file handle) for the reps. That way, rep
+ * access can often be satisfied from the APR read buffer. The same
+ * applies to the meta data because it is not rep data. */
+#define REP_FILE_COOKIE 1
+
/* Notes:
To avoid opening and closing the rev-files all the time, it would
@@ -611,6 +622,17 @@ with_txn_current_lock(svn_fs_t *fs,
return SVN_NO_ERROR;
}
+/* A frequently used utility method: close all cached, idle file handles.
+ * Call this at the end of write transactions to ensure that successive
+ * reads will see the new file content.
+ */
+static svn_error_t *
+sync_file_handle_cache(svn_fs_t *fs)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+ return svn_file_handle_cache__flush(ffd->file_handle_cache);
+}
+
/* A structure used by unlock_proto_rev() and unlock_proto_rev_body(),
which see. */
struct unlock_proto_rev_baton
@@ -1769,7 +1791,9 @@ ensure_revision_exists(svn_fs_t *fs,
/* Open the correct revision file for REV. If the filesystem FS has
been packed, *FILE will be set to the packed file; otherwise, set *FILE
to the revision file for REV. Return SVN_ERR_FS_NO_SUCH_REVISION if the
- file doesn't exist.
+ file doesn't exist. Move the file pointer of OFFSET, if the latter is
+ not -1. Prefer cached file handles that share the same COOKIE (again,
+ if not -1).
TODO: Consider returning an indication of whether this is a packed rev
file, so the caller need not rely on is_packed_rev() which in turn
@@ -1778,15 +1802,18 @@ ensure_revision_exists(svn_fs_t *fs,
Use POOL for allocations. */
static svn_error_t *
-open_pack_or_rev_file(apr_file_t **file,
+open_pack_or_rev_file(svn_file_handle_cache__handle_t **file,
svn_fs_t *fs,
svn_revnum_t rev,
+ apr_off_t offset,
+ int cookie,
apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
svn_error_t *err;
const char *path;
svn_boolean_t retry = FALSE;
+ fs_fs_data_t *ffd = fs->fsap_data;
do
{
@@ -1794,8 +1821,14 @@ open_pack_or_rev_file(apr_file_t **file,
/* open the revision file in buffered r/o mode */
if (! err)
- err = svn_io_file_open(file, path,
- APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
+ err = svn_file_handle_cache__open(file,
+ ffd->file_handle_cache,
+ path,
+ APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT,
+ offset,
+ cookie,
+ pool);
if (err && APR_STATUS_IS_ENOENT(err->apr_err)
&& ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
@@ -1895,20 +1928,18 @@ get_packed_offset(apr_off_t *rev_offset,
/* Open the revision file for revision REV in filesystem FS and store
the newly opened file in FILE. Seek to location OFFSET before
- returning. Perform temporary allocations in POOL. */
+ returning. Prefer cached file handles with the specified COOKIE
+ (if not -1). Perform temporary allocations in POOL. */
static svn_error_t *
-open_and_seek_revision(apr_file_t **file,
+open_and_seek_revision(svn_file_handle_cache__handle_t **file,
svn_fs_t *fs,
svn_revnum_t rev,
apr_off_t offset,
+ int cookie,
apr_pool_t *pool)
{
- apr_file_t *rev_file;
-
+ /* none of the following requires the file handle */
SVN_ERR(ensure_revision_exists(fs, rev, pool));
-
- SVN_ERR(open_pack_or_rev_file(&rev_file, fs, rev, pool));
-
if (is_packed_rev(fs, rev))
{
apr_off_t rev_offset;
@@ -1917,53 +1948,55 @@ open_and_seek_revision(apr_file_t **file
offset += rev_offset;
}
- SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool));
-
- *file = rev_file;
-
- return SVN_NO_ERROR;
+ /* So, open the revision file and position the pointer here in one go. */
+ return open_pack_or_rev_file(file, fs, rev, offset, cookie, pool);
}
/* Open the representation for a node-revision in transaction TXN_ID
in filesystem FS and store the newly opened file in FILE. Seek to
- location OFFSET before returning. Perform temporary allocations in
+ location OFFSET before returning. Prefer cached file handles witt
+ the specified COOKIE (if not -1). Perform temporary allocations in
POOL. Only appropriate for file contents, nor props or directory
contents. */
static svn_error_t *
-open_and_seek_transaction(apr_file_t **file,
+open_and_seek_transaction(svn_file_handle_cache__handle_t **file,
svn_fs_t *fs,
const char *txn_id,
representation_t *rep,
+ int cookie,
apr_pool_t *pool)
{
- apr_file_t *rev_file;
- apr_off_t offset;
-
- SVN_ERR(svn_io_file_open(&rev_file, path_txn_proto_rev(fs, txn_id, pool),
- APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
-
- offset = rep->offset;
- SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool));
-
- *file = rev_file;
+ fs_fs_data_t *ffd = fs->fsap_data;
- return SVN_NO_ERROR;
+ /* open & seek in one call */
+ return svn_file_handle_cache__open(file,
+ ffd->file_handle_cache,
+ path_txn_proto_rev(fs, txn_id, pool),
+ APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT,
+ rep->offset,
+ cookie,
+ pool);
}
/* Given a node-id ID, and a representation REP in filesystem FS, open
the correct file and seek to the correction location. Store this
file in *FILE_P. Perform any allocations in POOL. */
static svn_error_t *
-open_and_seek_representation(apr_file_t **file_p,
+open_and_seek_representation(svn_file_handle_cache__handle_t **file_p,
svn_fs_t *fs,
representation_t *rep,
apr_pool_t *pool)
{
+ /* representation headers tend to cluster. Therefore, use separate
+ * file handles for them (controlled by the cookie) to maximize APR
+ * buffer effectiveness. */
if (! rep->txn_id)
return open_and_seek_revision(file_p, fs, rep->revision, rep->offset,
- pool);
+ REP_FILE_COOKIE, pool);
else
- return open_and_seek_transaction(file_p, fs, rep->txn_id, rep, pool);
+ return open_and_seek_transaction(file_p, fs, rep->txn_id, rep,
+ REP_FILE_COOKIE, pool);
}
/* Parse the description of a representation from STRING and store it
@@ -2170,7 +2203,7 @@ get_node_revision_body(node_revision_t *
const svn_fs_id_t *id,
apr_pool_t *pool)
{
- apr_file_t *revision_file;
+ svn_file_handle_cache__handle_t *revision_file;
svn_error_t *err;
svn_boolean_t is_cached = FALSE;
@@ -2182,8 +2215,15 @@ get_node_revision_body(node_revision_t *
if (svn_fs_fs__id_txn_id(id))
{
/* This is a transaction node-rev. */
- err = svn_io_file_open(&revision_file, path_txn_node_rev(fs, id, pool),
- APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
+ fs_fs_data_t *ffd = fs->fsap_data;
+ err = svn_file_handle_cache__open(&revision_file,
+ ffd->file_handle_cache,
+ path_txn_node_rev(fs, id, pool),
+ APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT,
+ 0,
+ DEFAULT_FILE_COOKIE,
+ pool);
}
else
{
@@ -2191,6 +2231,7 @@ get_node_revision_body(node_revision_t *
err = open_and_seek_revision(&revision_file, fs,
svn_fs_fs__id_rev(id),
svn_fs_fs__id_offset(id),
+ DEFAULT_FILE_COOKIE,
pool);
}
@@ -2206,9 +2247,11 @@ get_node_revision_body(node_revision_t *
}
SVN_ERR(svn_fs_fs__read_noderev(noderev_p,
- svn_stream_from_aprfile2(revision_file, FALSE,
- pool),
- pool));
+ svn_stream__from_cached_file_handle
+ (revision_file,
+ FALSE,
+ pool),
+ pool));
/* The noderev is not in cache, yet. Add it, if caching has been enabled. */
return set_cached_node_revision_body(*noderev_p, fs, id, pool);
@@ -2525,7 +2568,10 @@ svn_fs_fs__put_node_revision(svn_fs_t *f
svn_fs_fs__fs_supports_mergeinfo(fs),
pool));
- return svn_io_file_close(noderev_file, pool);
+ SVN_ERR(svn_io_file_close(noderev_file, pool));
+
+ /* we wrote to the db -> sync file contents */
+ return sync_file_handle_cache(fs);
}
@@ -2869,28 +2915,45 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro
apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
- apr_file_t *revision_file;
+ svn_file_handle_cache__handle_t *revision_file;
+ apr_file_t *apr_rev_file;
apr_off_t root_offset;
+ svn_cache__t *cache = NULL;
svn_fs_id_t *root_id = NULL;
svn_boolean_t is_cached;
SVN_ERR(ensure_revision_exists(fs, rev, pool));
+ /* Try to find the ID in our caches. Once we tried is_packed_rev
+ returned true, we will never try to use the cache for non-packed
+ revs again. Also, if we find the entry in the cache, this
+ function cannot be racy because we don't need to access the file. */
+ cache = is_packed_rev(fs, rev)
+ ? ffd->packed_rev_root_id_cache
+ : ffd->rev_root_id_cache;
SVN_ERR(svn_cache__get((void **) root_id_p, &is_cached,
- ffd->rev_root_id_cache, &rev, pool));
+ cache, &rev, pool));
if (is_cached)
return SVN_NO_ERROR;
- SVN_ERR(open_pack_or_rev_file(&revision_file, fs, rev, pool));
- SVN_ERR(get_root_changes_offset(&root_offset, NULL, revision_file, fs, rev,
+ /* we don't care about the file pointer position */
+ SVN_ERR(open_pack_or_rev_file(&revision_file, fs, rev, -1,
+ DEFAULT_FILE_COOKIE, pool));
+ apr_rev_file = svn_file_handle_cache__get_apr_handle(revision_file);
+
+ /* it will moved here anyways */
+ SVN_ERR(get_root_changes_offset(&root_offset, NULL, apr_rev_file, fs, rev,
pool));
- SVN_ERR(get_fs_id_at_offset(&root_id, revision_file, fs, rev,
- root_offset, pool));
+ SVN_ERR(get_fs_id_at_offset(&root_id, apr_rev_file, fs, rev, root_offset,
+ pool));
- SVN_ERR(svn_io_file_close(revision_file, pool));
+ SVN_ERR(svn_file_handle_cache__close(revision_file));
- SVN_ERR(svn_cache__set(ffd->rev_root_id_cache, &rev, root_id, pool));
+ /* At this point, the revision might have already gotten packed
+ but cache is still the one for non-packed IDs. In that case,
+ it will never be looked up here, again. So, we are safe. */
+ SVN_ERR(svn_cache__set(cache, &rev, root_id, pool));
*root_id_p = root_id;
@@ -3019,7 +3082,10 @@ svn_fs_fs__revision_proplist(apr_hash_t
representation is. */
struct rep_state
{
- apr_file_t *file;
+ svn_file_handle_cache__handle_t *file;
+ /* For convenience, store the APR file handle
+ along with the surrounding cached file handle. */
+ apr_file_t *apr_file;
/* The txdelta window cache to use or NULL. */
svn_cache__t *window_cache;
apr_off_t start; /* The starting offset for the raw
@@ -3044,10 +3110,11 @@ create_rep_state_body(struct rep_state *
unsigned char buf[4];
SVN_ERR(open_and_seek_representation(&rs->file, fs, rep, pool));
+ rs->apr_file = svn_file_handle_cache__get_apr_handle(rs->file);
rs->window_cache = ffd->txdelta_window_cache;
- SVN_ERR(read_rep_line(&ra, rs->file, pool));
- SVN_ERR(get_file_offset(&rs->start, rs->file, pool));
+ SVN_ERR(read_rep_line(&ra, rs->apr_file, pool));
+ SVN_ERR(get_file_offset(&rs->start, rs->apr_file, pool));
rs->off = rs->start;
rs->end = rs->start + rep->size;
*rep_state = rs;
@@ -3058,7 +3125,7 @@ create_rep_state_body(struct rep_state *
return SVN_NO_ERROR;
/* We are dealing with a delta, find out what version. */
- SVN_ERR(svn_io_file_read_full2(rs->file, buf, sizeof(buf),
+ SVN_ERR(svn_io_file_read_full2(rs->apr_file, buf, sizeof(buf),
NULL, NULL, pool));
/* ### Layering violation */
if (! ((buf[0] == 'S') && (buf[1] == 'V') && (buf[2] == 'N')))
@@ -3373,9 +3440,9 @@ read_window(svn_txdelta_window_t **nwin,
/* Skip windows to reach the current chunk if we aren't there yet. */
while (rs->chunk_index < this_chunk)
{
- SVN_ERR(svn_txdelta_skip_svndiff_window(rs->file, rs->ver, pool));
+ SVN_ERR(svn_txdelta_skip_svndiff_window(rs->apr_file, rs->ver, pool));
rs->chunk_index++;
- SVN_ERR(get_file_offset(&rs->off, rs->file, pool));
+ SVN_ERR(get_file_offset(&rs->off, rs->apr_file, pool));
if (rs->off >= rs->end)
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Reading one svndiff window read "
@@ -3390,10 +3457,10 @@ read_window(svn_txdelta_window_t **nwin,
/* Actually read the next window. */
old_offset = rs->off;
- stream = svn_stream_from_aprfile2(rs->file, TRUE, pool);
+ stream = svn_stream__from_cached_file_handle(rs->file, TRUE, pool);
SVN_ERR(svn_txdelta_read_svndiff_window(nwin, stream, rs->ver, pool));
rs->chunk_index++;
- SVN_ERR(get_file_offset(&rs->off, rs->file, pool));
+ SVN_ERR(get_file_offset(&rs->off, rs->apr_file, pool));
if (rs->off > rs->end)
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -3489,7 +3556,7 @@ get_contents(struct rep_read_baton *rb,
rs = rb->src_state;
if (((apr_off_t) copy_len) > rs->end - rs->off)
copy_len = (apr_size_t) (rs->end - rs->off);
- SVN_ERR(svn_io_file_read_full2(rs->file, cur, copy_len, NULL,
+ SVN_ERR(svn_io_file_read_full2(rs->apr_file, cur, copy_len, NULL,
NULL, rb->pool));
rs->off += copy_len;
*len = copy_len;
@@ -3562,10 +3629,10 @@ get_contents(struct rep_read_baton *rb,
if ((rs->start + lwindow->sview_offset) != rs->off)
{
rs->off = rs->start + lwindow->sview_offset;
- SVN_ERR(svn_io_file_seek(rs->file, APR_SET, &rs->off,
+ SVN_ERR(svn_io_file_seek(rs->apr_file, APR_SET, &rs->off,
rb->pool));
}
- SVN_ERR(svn_io_file_read_full2(rs->file, sbuf,
+ SVN_ERR(svn_io_file_read_full2(rs->apr_file, sbuf,
lwindow->sview_len,
NULL, NULL, rb->pool));
rs->off += lwindow->sview_len;
@@ -3798,7 +3865,7 @@ svn_fs_fs__get_file_delta_stream(svn_txd
return SVN_NO_ERROR;
}
else
- SVN_ERR(svn_io_file_close(rep_state->file, pool));
+ SVN_ERR(svn_file_handle_cache__close(rep_state->file));
}
/* Read both fulltexts and construct a delta. */
@@ -4624,24 +4691,29 @@ svn_fs_fs__paths_changed(apr_hash_t **ch
{
apr_off_t changes_offset;
apr_hash_t *changed_paths;
- apr_file_t *revision_file;
+ svn_file_handle_cache__handle_t *revision_file;
+ apr_file_t *apr_revision_file;
SVN_ERR(ensure_revision_exists(fs, rev, pool));
- SVN_ERR(open_pack_or_rev_file(&revision_file, fs, rev, pool));
-
- SVN_ERR(get_root_changes_offset(NULL, &changes_offset, revision_file, fs,
- rev, pool));
+ /* we don't care about the file pointer position */
+ SVN_ERR(open_pack_or_rev_file(&revision_file, fs, rev, -1,
+ DEFAULT_FILE_COOKIE, pool));
+ apr_revision_file = svn_file_handle_cache__get_apr_handle(revision_file);
+
+ /* it will moved here anyways */
+ SVN_ERR(get_root_changes_offset(NULL, &changes_offset, apr_revision_file,
+ fs, rev, pool));
- SVN_ERR(svn_io_file_seek(revision_file, APR_SET, &changes_offset, pool));
+ SVN_ERR(svn_io_file_seek(apr_revision_file, APR_SET, &changes_offset, pool));
changed_paths = apr_hash_make(pool);
- SVN_ERR(fetch_all_changes(changed_paths, copyfrom_cache, revision_file,
+ SVN_ERR(fetch_all_changes(changed_paths, copyfrom_cache, apr_revision_file,
TRUE, pool));
/* Close the revision file. */
- SVN_ERR(svn_io_file_close(revision_file, pool));
+ SVN_ERR(svn_file_handle_cache__close(revision_file));
*changed_paths_p = changed_paths;
@@ -5011,7 +5083,10 @@ write_next_ids(svn_fs_t *fs,
SVN_ERR(svn_stream_printf(out_stream, pool, "%s %s\n", node_id, copy_id));
SVN_ERR(svn_stream_close(out_stream));
- return svn_io_file_close(file, pool);
+ SVN_ERR(svn_io_file_close(file, pool));
+
+ /* we wrote to the db -> sync file contents */
+ return sync_file_handle_cache(fs);
}
/* Find out what the next unique node-id and copy-id are for
@@ -5249,7 +5324,10 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
strlen(name), name));
}
- return svn_io_file_close(file, pool);
+ SVN_ERR(svn_io_file_close(file, pool));
+
+ /* we wrote to the db -> sync file contents */
+ return sync_file_handle_cache(fs);
}
/* Write a single change entry, path PATH, change CHANGE, and copyfrom
@@ -5350,7 +5428,10 @@ svn_fs_fs__add_change(svn_fs_t *fs,
SVN_ERR(write_change_entry(file, path, change, TRUE, pool));
- return svn_io_file_close(file, pool);
+ SVN_ERR(svn_io_file_close(file, pool));
+
+ /* we wrote to the db -> sync file contents */
+ return sync_file_handle_cache(fs);
}
/* This baton is used by the representation writing streams. It keeps
@@ -5634,7 +5715,8 @@ rep_write_contents_close(void *baton)
SVN_ERR(unlock_proto_rev(b->fs, rep->txn_id, b->lockcookie, b->pool));
svn_pool_destroy(b->pool);
- return SVN_NO_ERROR;
+ /* we wrote to the db -> sync file contents */
+ return sync_file_handle_cache(b->fs);
}
/* Store a writable stream in *CONTENTS_P that will receive all data
@@ -5736,7 +5818,8 @@ svn_fs_fs__set_proplist(svn_fs_t *fs,
SVN_ERR(svn_fs_fs__put_node_revision(fs, noderev->id, noderev, FALSE, pool));
}
- return SVN_NO_ERROR;
+ /* we wrote to the db -> sync file contents */
+ return sync_file_handle_cache(fs);
}
/* Read the 'current' file for filesystem FS and store the next
@@ -6357,6 +6440,9 @@ commit_body(void *baton, apr_pool_t *poo
SVN_ERR(svn_io_file_flush_to_disk(proto_file, pool));
SVN_ERR(svn_io_file_close(proto_file, pool));
+ /* we wrote to the db -> sync file contents */
+ SVN_ERR(sync_file_handle_cache(cb->fs));
+
/* We don't unlock the prototype revision file immediately to avoid a
race with another caller writing to the prototype revision file
before we commit it. */
@@ -6704,9 +6790,12 @@ recover_get_largest_revision(svn_fs_t *f
while (1)
{
svn_error_t *err;
- apr_file_t *file;
+ svn_file_handle_cache__handle_t *file;
- err = open_pack_or_rev_file(&file, fs, right, iterpool);
+ /* We don't care about the file pointer position as long as the file
+ itself exists. */
+ err = open_pack_or_rev_file(&file, fs, right, -1,
+ DEFAULT_FILE_COOKIE, iterpool);
svn_pool_clear(iterpool);
if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
@@ -6728,9 +6817,11 @@ recover_get_largest_revision(svn_fs_t *f
{
svn_revnum_t probe = left + ((right - left) / 2);
svn_error_t *err;
- apr_file_t *file;
+ svn_file_handle_cache__handle_t *file;
- err = open_pack_or_rev_file(&file, fs, probe, iterpool);
+ /* Again, ignore the file pointer position. */
+ err = open_pack_or_rev_file(&file, fs, probe, -1,
+ DEFAULT_FILE_COOKIE, iterpool);
svn_pool_clear(iterpool);
if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
@@ -7010,7 +7101,8 @@ recover_body(void *baton, apr_pool_t *po
for (rev = 0; rev <= max_rev; rev++)
{
- apr_file_t *rev_file;
+ svn_file_handle_cache__handle_t *rev_file;
+ apr_file_t *apr_rev_file;
apr_off_t root_offset;
svn_pool_clear(iterpool);
@@ -7018,12 +7110,18 @@ recover_body(void *baton, apr_pool_t *po
if (b->cancel_func)
SVN_ERR(b->cancel_func(b->cancel_baton));
- SVN_ERR(open_pack_or_rev_file(&rev_file, fs, rev, iterpool));
- SVN_ERR(get_root_changes_offset(&root_offset, NULL, rev_file, fs, rev,
+ /* Any file pointer position will do ... */
+ SVN_ERR(open_pack_or_rev_file(&rev_file, fs, rev, -1,
+ DEFAULT_FILE_COOKIE, iterpool));
+ apr_rev_file = svn_file_handle_cache__get_apr_handle(rev_file);
+
+ /* ... because it gets set here explicitly */
+ SVN_ERR(get_root_changes_offset(&root_offset, NULL,
+ apr_rev_file, fs, rev,
iterpool));
- SVN_ERR(recover_find_max_ids(fs, rev, rev_file, root_offset,
+ SVN_ERR(recover_find_max_ids(fs, rev, apr_rev_file, root_offset,
max_node_id, max_copy_id, iterpool));
- SVN_ERR(svn_io_file_close(rev_file, iterpool));
+ SVN_ERR(svn_file_handle_cache__close(rev_file));
}
svn_pool_destroy(iterpool);
Modified: subversion/branches/file-handle-cache/subversion/libsvn_subr/stream.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_subr/stream.c?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_subr/stream.c Sat Oct 29 00:33:21 2011
@@ -44,7 +44,7 @@
#include "svn_path.h"
#include "private/svn_eol_private.h"
#include "private/svn_io_private.h"
-
+#include "private/svn_file_handle_cache.h"
struct svn_stream_t {
void *baton;
@@ -732,6 +732,10 @@ svn_stream_disown(svn_stream_t *stream,
struct baton_apr {
apr_file_t *file;
apr_pool_t *pool;
+
+ /* If not NULL, file is actually wrapped into this cached file handle
+ * and should be returned to the file handle cache asap. */
+ svn_file_handle_cache__handle_t *cached_handle;
};
/* svn_stream_mark_t for streams backed by APR files. */
@@ -751,7 +755,7 @@ read_handler_apr(void *baton, char *buff
err = svn_io_file_getc(buffer, btn->file, btn->pool);
if (err)
{
- *len = 0;
+ *len = 0;
if (APR_STATUS_IS_EOF(err->apr_err))
{
svn_error_clear(err);
@@ -793,6 +797,17 @@ write_handler_apr(void *baton, const cha
return err;
}
+/* Returns the cached file handle back to the respective cache object.
+ * This is call is allowed even for btn->cached_handle == NULL.
+ */
+static svn_error_t *
+close_handler_cached_handle(void *baton)
+{
+ struct baton_apr *btn = baton;
+
+ return svn_file_handle_cache__close(btn->cached_handle);
+}
+
static svn_error_t *
close_handler_apr(void *baton)
{
@@ -886,6 +901,36 @@ svn_stream_open_unique(svn_stream_t **st
return SVN_NO_ERROR;
}
+/* Common initialization code for svn_stream_from_aprfile2() and
+ * svn_stream__from_cached_file_handle().
+ */
+static svn_stream_t *
+stream_from_aprfile(struct baton_apr **baton,
+ apr_file_t *file,
+ apr_pool_t *pool)
+{
+ struct baton_apr *new_baton;
+ svn_stream_t *stream;
+
+ /* create and fully initialize the baton */
+ new_baton = apr_palloc(pool, sizeof(*new_baton));
+ new_baton->file = file;
+ new_baton->cached_handle = NULL; /* default */
+ new_baton->pool = pool;
+
+ /* construct the stream vtable, except for the close() function */
+ stream = svn_stream_create(new_baton, pool);
+ svn_stream_set_read(stream, read_handler_apr);
+ svn_stream_set_write(stream, write_handler_apr);
+ svn_stream_set_skip(stream, skip_handler_apr);
+ svn_stream_set_mark(stream, mark_handler_apr);
+ svn_stream_set_seek(stream, seek_handler_apr);
+
+ /* return structures */
+ *baton = new_baton;
+
+ return stream;
+}
svn_stream_t *
svn_stream_from_aprfile2(apr_file_t *file,
@@ -895,26 +940,46 @@ svn_stream_from_aprfile2(apr_file_t *fil
struct baton_apr *baton;
svn_stream_t *stream;
+ /* having no file at all is a special case */
if (file == NULL)
return svn_stream_empty(pool);
- baton = apr_palloc(pool, sizeof(*baton));
- baton->file = file;
- baton->pool = pool;
- stream = svn_stream_create(baton, pool);
- svn_stream_set_read(stream, read_handler_apr);
- svn_stream_set_write(stream, write_handler_apr);
- svn_stream_set_skip(stream, skip_handler_apr);
- svn_stream_set_mark(stream, mark_handler_apr);
- svn_stream_set_seek(stream, seek_handler_apr);
+ /* construct and init the default stream structures */
+ stream = stream_from_aprfile(&baton, file, pool);
svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
+ /* make sure to close the file handle after use if we own it */
if (! disown)
svn_stream_set_close(stream, close_handler_apr);
return stream;
}
+svn_stream_t *
+svn_stream__from_cached_file_handle(svn_file_handle_cache__handle_t *file,
+ svn_boolean_t disown,
+ apr_pool_t *pool)
+{
+ struct baton_apr *baton;
+ svn_stream_t *stream;
+
+ /* having no file at all is a special case (file == NULL is legal, too) */
+ apr_file_t *apr_file = svn_file_handle_cache__get_apr_handle(file);
+ if (apr_file == NULL)
+ return svn_stream_empty(pool);
+
+ /* construct and init the default stream structures */
+ stream = stream_from_aprfile(&baton, apr_file, pool);
+
+ /* store the cached file handle and return it to the cache after use,
+ * if we own it */
+ baton->cached_handle = file;
+ if (! disown)
+ svn_stream_set_close(stream, close_handler_cached_handle);
+
+ return stream;
+}
+
/* Compressed stream support */
Modified: subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c Sat Oct 29 00:33:21 2011
@@ -363,7 +363,7 @@ find_first(svn_file_handle_cache_t *cach
/* the index must contain only used entries, i.e. those that actually
* contain an open APR file handle. */
- assert (!result || result->file);
+ assert(!result || result->file);
return result;
}
@@ -526,6 +526,7 @@ close_handle_before_cleanup(void *handle
{
svn_file_handle_cache__handle_t *f = handle_void;
svn_error_t *err = SVN_NO_ERROR;
+ apr_status_t result = APR_SUCCESS;
/* if this hasn't been done before:
* "close" the handle, i.e. return it to the cache
@@ -537,7 +538,14 @@ close_handle_before_cleanup(void *handle
f->entry = NULL;
f->cache = NULL;
- return err ? err->apr_err : APR_SUCCESS;
+ /* process error returns */
+ if (err)
+ {
+ result = err->apr_err;
+ svn_error_clear(err);
+ }
+
+ return result;
}
/* Create a cached file handle to be returned to the application in F for
@@ -552,7 +560,7 @@ open_entry(svn_file_handle_cache__handle
apr_pool_t *pool)
{
/* any entry can be handed out to the application only once at any time */
- assert (! entry->open_handle);
+ assert(!entry->open_handle);
/* the entry will no longer be idle */
remove_from_list(&cache->idle_entries, &entry->idle_link);
@@ -887,10 +895,11 @@ svn_file_handle_cache__create_cache(svn_
init_list(&new_cache->unused_entries);
new_cache->first_by_name = apr_hash_make(new_cache->pool);
+
+#if APR_HAS_THREADS
new_cache->mutex = NULL;
/* synchronization support may or may not be needed or available */
-#if APR_HAS_THREADS
if (thread_safe)
{
apr_status_t status = apr_thread_mutex_create(&(new_cache->mutex),
Propchange: subversion/branches/file-handle-cache/subversion/libsvn_subr/svn_file_handle_cache.c
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat Oct 29 00:33:21 2011
@@ -1 +1 @@
-/subversion/branches/performance/subversion/libsvn_subr/svn_file_handle_cache.c:981665,981828
+/subversion/branches/performance/subversion/libsvn_subr/svn_file_handle_cache.c:981665,981828,992905,1003430,1029082,1037466,1037470
Modified: subversion/branches/file-handle-cache/subversion/mod_dav_svn/mod_dav_svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/mod_dav_svn/mod_dav_svn.c?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/mod_dav_svn/mod_dav_svn.c (original)
+++ subversion/branches/file-handle-cache/subversion/mod_dav_svn/mod_dav_svn.c Sat Oct 29 00:33:21 2011
@@ -458,19 +458,29 @@ SVNCacheFullTexts_cmd(cmd_parms *cmd, vo
return NULL;
}
-static const char *
-SVNInMemoryCacheSize_cmd(cmd_parms *cmd, void *config, const char *arg1)
+static apr_uint64_t
+parse_number(const char *arg)
{
- svn_cache_config_t settings = *svn_cache_config_get();
-
apr_uint64_t value = 0;
- svn_error_t *err = svn_cstring_atoui64(&value, arg1);
+ svn_error_t *err = svn_cstring_atoui64(&value, arg);
if (err)
{
svn_error_clear(err);
- return "Invalid decimal number for the SVN cache size.";
+ return (apr_uint64_t)(-1);
}
+ return value;
+}
+
+static const char *
+SVNInMemoryCacheSize_cmd(cmd_parms *cmd, void *config, const char *arg1)
+{
+ svn_cache_config_t settings = *svn_cache_config_get();
+
+ apr_uint64_t value = parse_number(arg1);
+ if (value == (apr_uint64_t)(-1))
+ return "Invalid decimal number for the SVN cache size.";
+
settings.cache_size = value * 0x400;
svn_cache_config_set(&settings);
@@ -479,6 +489,22 @@ SVNInMemoryCacheSize_cmd(cmd_parms *cmd,
}
static const char *
+SVNMaxOpenFileHandles_cmd(cmd_parms *cmd, void *config, const char *arg1)
+{
+ svn_fs_cache_config_t settings = *svn_fs_get_cache_config();
+
+ apr_uint64_t value = parse_number(arg1);
+ if (value == (apr_uint64_t)(-1))
+ return "Invalid decimal number for the open file handle count.";
+
+ settings.file_handle_count = (apr_size_t)value;
+
+ svn_fs_set_cache_config(&settings);
+
+ return NULL;
+}
+
+static const char *
SVNCompressionLevel_cmd(cmd_parms *cmd, void *config, const char *arg1)
{
int value = 0;
@@ -1008,6 +1034,11 @@ static const command_rec cmds[] =
"in-memory object cache (default value is 16384; 0 deactivates "
"the cache)."),
/* per server */
+ AP_INIT_TAKE1("SVNMaxOpenFileHandles", SVNMaxOpenFileHandles_cmd, NULL,
+ RSRC_CONF,
+ "specify the maximum of unused file handles kept open per "
+ "process (default values is 16)."),
+ /* per server */
AP_INIT_TAKE1("SVNCompressionLevel", SVNCompressionLevel_cmd, NULL,
RSRC_CONF,
"specifies the compression level used before sending file "
Modified: subversion/branches/file-handle-cache/subversion/svnadmin/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/svnadmin/main.c?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/svnadmin/main.c (original)
+++ subversion/branches/file-handle-cache/subversion/svnadmin/main.c Sat Oct 29 00:33:21 2011
@@ -280,6 +280,11 @@ static const apr_getopt_option_t options
" minimize redundant operations. Default: 16.\n"
" [used for FSFS repositories only]")},
+ {"open-file-count", 'F', 1,
+ N_("maximum number of files kept open after usage\n"
+ " to reduce OS and I/O overhead. Default: 64.\n"
+ " [used for FSFS repositories only]")},
+
{NULL}
};
@@ -310,7 +315,7 @@ static const svn_opt_subcommand_desc2_t
"essence compresses the repository by only storing the differences or\n"
"delta from the preceding revision. If no revisions are specified,\n"
"this will simply deltify the HEAD revision.\n"),
- {'r', 'q', 'M'} },
+ {'r', 'q', 'M', 'F'} },
{"dump", subcommand_dump, {0}, N_
("usage: svnadmin dump REPOS_PATH [-r LOWER[:UPPER] [--incremental]]\n\n"
@@ -323,7 +328,7 @@ static const svn_opt_subcommand_desc2_t
"every path present in the repository as of that revision. (In either\n"
"case, the second and subsequent revisions, if any, describe only paths\n"
"changed in those revisions.)\n"),
- {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M'} },
+ {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M', 'F'} },
{"help", subcommand_help, {"?", "h"}, N_
("usage: svnadmin help [SUBCOMMAND...]\n\n"
@@ -357,7 +362,7 @@ static const svn_opt_subcommand_desc2_t
"in the dump stream whose revision numbers match the specified range.\n"),
{'q', 'r', svnadmin__ignore_uuid, svnadmin__force_uuid,
svnadmin__use_pre_commit_hook, svnadmin__use_post_commit_hook,
- svnadmin__parent_dir, svnadmin__bypass_prop_validation, 'M'} },
+ svnadmin__parent_dir, svnadmin__bypass_prop_validation, 'M', 'F'} },
{"lslocks", subcommand_lslocks, {0}, N_
("usage: svnadmin lslocks REPOS_PATH [PATH-IN-REPOS]\n\n"
@@ -440,7 +445,7 @@ static const svn_opt_subcommand_desc2_t
{"verify", subcommand_verify, {0}, N_
("usage: svnadmin verify REPOS_PATH\n\n"
"Verifies the data stored in the repository.\n"),
- {'r', 'q', 'M'} },
+ {'r', 'q', 'M', 'F'} },
{ NULL, NULL, {0}, NULL, {0} }
};
@@ -473,6 +478,7 @@ struct svnadmin_opt_state
enum svn_repos_load_uuid uuid_action; /* --ignore-uuid,
--force-uuid */
apr_uint64_t memory_cache_size; /* --memory-cache-size M */
+ apr_size_t open_file_count; /* --open-file-count F */
const char *parent_dir;
const char *config_dir; /* Overriding Configuration Directory */
@@ -1692,6 +1698,7 @@ main(int argc, const char *argv[])
opt_state.start_revision.kind = svn_opt_revision_unspecified;
opt_state.end_revision.kind = svn_opt_revision_unspecified;
opt_state.memory_cache_size = svn_cache_config_get()->cache_size;
+ opt_state.open_file_count = 64;
/* Parse options. */
err = svn_cmdline__getopt_init(&os, argc, argv, pool);
@@ -1755,6 +1762,9 @@ main(int argc, const char *argv[])
opt_state.memory_cache_size
= 0x100000 * apr_strtoi64(opt_arg, NULL, 0);
break;
+ case 'F':
+ opt_state.open_file_count = apr_strtoi64(opt_arg, NULL, 0);
+ break;
case svnadmin__version:
opt_state.version = TRUE;
break;
@@ -1973,6 +1983,7 @@ main(int argc, const char *argv[])
svn_cache_config_t settings = *svn_cache_config_get();
settings.cache_size = opt_state.memory_cache_size;
+ settings.file_handle_count = opt_state.open_file_count;
settings.single_threaded = TRUE;
svn_cache_config_set(&settings);
Modified: subversion/branches/file-handle-cache/subversion/svnserve/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/svnserve/main.c?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/svnserve/main.c (original)
+++ subversion/branches/file-handle-cache/subversion/svnserve/main.c Sat Oct 29 00:33:21 2011
@@ -221,6 +221,14 @@ static const apr_getopt_option_t svnserv
"Default is yes.\n"
" "
"[used for FSFS repositories only]")},
+ {"open-file-count", 'F', 1,
+ N_("maximum number of files kept open after usage\n"
+ " "
+ "to reduce OS and I/O overhead.\n"
+ " "
+ "Default is 64 and 16 for non-threaded mode.\n"
+ " "
+ "[used for FSFS repositories only]")},
#ifdef CONNECTION_HAVE_THREAD_OPTION
/* ### Making the assumption here that WIN32 never has fork and so
* ### this option never exists when --service exists. */
@@ -475,6 +483,7 @@ int main(int argc, const char *argv[])
params.memory_cache_size = (apr_uint64_t)-1;
params.cache_fulltexts = TRUE;
params.cache_txdeltas = FALSE;
+ params.open_file_count = -1;
while (1)
{
@@ -609,6 +618,9 @@ int main(int argc, const char *argv[])
= svn_tristate__from_word(arg) == svn_tristate_true;
break;
+ case 'F':
+ params.open_file_count = apr_strtoi64(arg, NULL, 0);
+
#ifdef WIN32
case SVNSERVE_OPT_SERVICE:
if (run_mode != run_mode_service)
@@ -878,7 +890,9 @@ int main(int argc, const char *argv[])
if (params.memory_cache_size != -1)
settings.cache_size = params.memory_cache_size;
- settings.single_threaded = TRUE;
+ if (params.open_file_count != -1)
+ settings.file_handle_count = params.open_file_count;
+
if (handling_mode == connection_mode_thread)
{
#ifdef APR_HAS_THREADS
Modified: subversion/branches/file-handle-cache/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/svnserve/server.h?rev=1190714&r1=1190713&r2=1190714&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/svnserve/server.h (original)
+++ subversion/branches/file-handle-cache/subversion/svnserve/server.h Sat Oct 29 00:33:21 2011
@@ -125,6 +125,9 @@ typedef struct serve_params_t {
Defaults to SVN_DELTA_COMPRESSION_LEVEL_DEFAULT. */
int compression_level;
+ /* Number of handles kept open independently of there actual use
+ (used by FSFS only). */
+ apr_size_t open_file_count;
} serve_params_t;
/* Serve the connection CONN according to the parameters PARAMS. */