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 2013/07/25 14:25:33 UTC
svn commit: r1506925 - in
/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs:
cached_data.c caching.c fs.h
Author: stefan2
Date: Thu Jul 25 12:25:33 2013
New Revision: 1506925
URL: http://svn.apache.org/r1506925
Log:
On the fsfs-improvements branch: use integer structs instead of strings
to address txdelta window caches.
* subversion/libsvn_fs_fs/fs.h
(window_cache_key_t): new cache key type
* subversion/libsvn_fs_fs/caching.c
(svn_fs_fs__initialize_caches): window caches use the new key type
* subversion/libsvn_fs_fs/cached_data.c
(get_window_key): simplify greatly
(get_cached_combined_window,
set_cached_combined_window): update callers
(get_cached_window,
set_cached_window): ditto; allow random access to a rep's chunks
(build_rep_list): don't attempt to read txn windows from the cache
(read_delta_window): we can now randomly access the cache;
leave it to the caller when to bump CHUNK_INDEX;
don't cache in-txn windows
(delta_read_next_window): update caller
(get_combined_window): ditto; don't cache combined in-txn windows
Modified:
subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c
subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/caching.c
subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c?rev=1506925&r1=1506924&r2=1506925&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c Thu Jul 25 12:25:33 2013
@@ -882,74 +882,32 @@ struct rep_read_baton
apr_pool_t *filehandle_pool;
};
-/* Combine the name of the rev file in RS with the given OFFSET to form
- * a cache lookup key. Allocations will be made from POOL. May return
- * NULL if the key cannot be constructed. */
-static const char*
-get_window_key(rep_state_t *rs, apr_off_t offset, apr_pool_t *pool)
-{
- const char *name;
- const char *last_part;
- const char *name_last;
- svn_error_t *err;
-
- err = auto_open_shared_file(rs->file);
- if (err)
- {
- svn_error_clear(err);
- return NULL;
- }
-
- /* the rev file name containing the txdelta window.
- * If this fails we are in serious trouble anyways.
- * And if nobody else detects the problems, the file content checksum
- * comparison _will_ find them.
- */
- err = svn_io_file_name_get(&name, rs->file->file, pool);
- if (err)
- {
- svn_error_clear(err);
- return NULL;
- }
-
- /* Handle packed files as well by scanning backwards until we find the
- * revision or pack number. */
- name_last = name + strlen(name) - 1;
- while (! svn_ctype_isdigit(*name_last))
- --name_last;
-
- last_part = name_last;
- while (svn_ctype_isdigit(*last_part))
- --last_part;
-
- /* We must differentiate between packed files (as of today, the number
- * is being followed by a dot) and non-packed files (followed by \0).
- * Otherwise, there might be overlaps in the numbering range if the
- * repo gets packed after caching the txdeltas of non-packed revs.
- * => add the first non-digit char to the packed number. */
- if (name_last[1] != '\0')
- ++name_last;
-
- /* copy one char MORE than the actual number to mark packed files,
- * i.e. packed revision file content uses different key space then
- * non-packed ones: keys for packed rev file content ends with a dot
- * for non-packed rev files they end with a digit. */
- name = apr_pstrndup(pool, last_part + 1, name_last - last_part);
- return svn_fs_fs__combine_number_and_string(offset, name, pool);
-}
-
-/* Read the WINDOW_P for the rep state RS from the current FSFS session's
- * cache. This will be a no-op and IS_CACHED will be set to FALSE if no
- * cache has been given. If a cache is available IS_CACHED will inform
- * the caller about the success of the lookup. Allocations (of the window
- * in particualar) will be made from POOL.
+/* Set window key in *KEY to address the window described by RS.
+ For convenience, return the KEY. */
+static window_cache_key_t *
+get_window_key(window_cache_key_t *key, rep_state_t *rs)
+{
+ assert(rs->revision <= APR_UINT32_MAX);
+ key->revision = (apr_uint32_t)rs->revision;
+ key->offset = rs->offset;
+ key->chunk_index = rs->chunk_index;
+
+ return key;
+}
+
+/* Read the WINDOW_P number CHUNK_INDEX for the representation given in
+ * rep state RS from the current FSFS session's cache. This will be a
+ * no-op and IS_CACHED will be set to FALSE if no cache has been given.
+ * If a cache is available IS_CACHED will inform the caller about the
+ * success of the lookup. Allocations (of the window in particualar) will
+ * be made from POOL.
*
- * If the information could be found, put RS and the position within the
- * rev file into the same state as if the data had just been read from it.
+ * If the information could be found, put RS to CHUNK_INDEX.
*/
static svn_error_t *
get_cached_window(svn_txdelta_window_t **window_p,
rep_state_t *rs,
+ int chunk_index,
svn_boolean_t *is_cached,
apr_pool_t *pool)
{
@@ -962,11 +920,13 @@ get_cached_window(svn_txdelta_window_t *
{
/* ask the cache for the desired txdelta window */
svn_fs_fs__txdelta_cached_window_t *cached_window;
+ window_cache_key_t key = { 0 };
+ get_window_key(&key, rs);
+ key.chunk_index = chunk_index;
SVN_ERR(svn_cache__get((void **) &cached_window,
is_cached,
rs->window_cache,
- get_window_key(rs, rs->current + rs->start,
- pool),
+ &key,
pool));
if (*is_cached)
@@ -976,35 +936,36 @@ get_cached_window(svn_txdelta_window_t *
/* manipulate the RS as if we just read the data */
rs->current = cached_window->end_offset;
+ rs->chunk_index = chunk_index;
}
}
return SVN_NO_ERROR;
}
-/* Store the WINDOW read at OFFSET for the rep state RS in the current
- * FSFS session's cache. This will be a no-op if no cache has been given.
+/* Store the WINDOW read for the rep state RS in the current FSFS
+ * session's cache. This will be a no-op if no cache has been given.
* Temporary allocations will be made from SCRATCH_POOL. */
static svn_error_t *
set_cached_window(svn_txdelta_window_t *window,
rep_state_t *rs,
- apr_off_t offset,
apr_pool_t *scratch_pool)
{
if (rs->window_cache)
{
/* store the window and the first offset _past_ it */
svn_fs_fs__txdelta_cached_window_t cached_window;
+ window_cache_key_t key = {0};
cached_window.window = window;
cached_window.end_offset = rs->current;
/* but key it with the start offset because that is the known state
* when we will look it up */
- return svn_cache__set(rs->window_cache,
- get_window_key(rs, offset, scratch_pool),
- &cached_window,
- scratch_pool);
+ SVN_ERR(svn_cache__set(rs->window_cache,
+ get_window_key(&key, rs),
+ &cached_window,
+ scratch_pool));
}
return SVN_NO_ERROR;
@@ -1030,31 +991,32 @@ get_cached_combined_window(svn_stringbuf
else
{
/* ask the cache for the desired txdelta window */
+ window_cache_key_t key = { 0 };
return svn_cache__get((void **)window_p,
is_cached,
rs->combined_cache,
- get_window_key(rs, rs->start, pool),
+ get_window_key(&key, rs),
pool);
}
return SVN_NO_ERROR;
}
-/* Store the WINDOW read at OFFSET for the rep state RS in the current
- * FSFS session's cache. This will be a no-op if no cache has been given.
+/* Store the WINDOW read for the rep state RS in the current FSFS session's
+ * cache. This will be a no-op if no cache has been given.
* Temporary allocations will be made from SCRATCH_POOL. */
static svn_error_t *
set_cached_combined_window(svn_stringbuf_t *window,
rep_state_t *rs,
- apr_off_t offset,
apr_pool_t *scratch_pool)
{
if (rs->combined_cache)
{
/* but key it with the start offset because that is the known state
* when we will look it up */
+ window_cache_key_t key = { 0 };
return svn_cache__set(rs->combined_cache,
- get_window_key(rs, offset, scratch_pool),
+ get_window_key(&key, rs),
window,
scratch_pool);
}
@@ -1116,7 +1078,10 @@ build_rep_list(apr_array_header_t **list
SVN_ERR(create_rep_state(&rs, &rep_header, &shared_file,
&rep, fs, pool));
- SVN_ERR(get_cached_combined_window(window_p, rs, &is_cached, pool));
+ /* for txn reps, there won't be a cached combined window */
+ if (!svn_fs_fs__id_txn_used(&rep.txn_id))
+ SVN_ERR(get_cached_combined_window(window_p, rs, &is_cached, pool));
+
if (is_cached)
{
/* We already have a reconstructed window in our cache.
@@ -1199,7 +1164,8 @@ rep_read_get_baton(struct rep_read_baton
}
/* Skip forwards to THIS_CHUNK in REP_STATE and then read the next delta
- window into *NWIN. */
+ window into *NWIN. Note that RS->CHUNK_INDEX will be THIS_CHUNK rather
+ than THIS_CHUNK + 1 when this function returns. */
static svn_error_t *
read_delta_window(svn_txdelta_window_t **nwin, int this_chunk,
rep_state_t *rs, apr_pool_t *pool)
@@ -1212,6 +1178,11 @@ read_delta_window(svn_txdelta_window_t *
SVN_ERR(dbg_log_access(rs->file->fs, rs->revision, rs->offset,
NULL, SVN_FS_FS__ITEM_TYPE_ANY_REP, pool));
+ /* Read the next window. But first, try to find it in the cache. */
+ SVN_ERR(get_cached_window(nwin, rs, this_chunk, &is_cached, pool));
+ if (is_cached)
+ return SVN_NO_ERROR;
+
/* someone has to actually read the data from file. Open it */
SVN_ERR(auto_open_shared_file(rs->file));
SVN_ERR(auto_set_start_offset(rs, pool));
@@ -1238,15 +1209,9 @@ read_delta_window(svn_txdelta_window_t *
"representation"));
}
- /* Read the next window. But first, try to find it in the cache. */
- SVN_ERR(get_cached_window(nwin, rs, &is_cached, pool));
- if (is_cached)
- return SVN_NO_ERROR;
-
/* Actually read the next window. */
SVN_ERR(svn_txdelta_read_svndiff_window(nwin, rs->file->stream, rs->ver,
pool));
- rs->chunk_index++;
SVN_ERR(svn_fs_fs__get_file_offset(&end_offset, rs->file->file, pool));
rs->current = end_offset - rs->start;
if (rs->current > rs->size)
@@ -1256,7 +1221,10 @@ read_delta_window(svn_txdelta_window_t *
/* the window has not been cached before, thus cache it now
* (if caching is used for them at all) */
- return set_cached_window(*nwin, rs, start_offset, pool);
+ if (SVN_IS_VALID_REVNUM(rs->revision))
+ SVN_ERR(set_cached_window(*nwin, rs, pool));
+
+ return SVN_NO_ERROR;
}
/* Read SIZE bytes from the representation RS and return it in *NWIN. */
@@ -1353,8 +1321,11 @@ get_combined_window(svn_stringbuf_t **re
/* Cache windows only if the whole rep content could be read as a
single chunk. Only then will no other chunk need a deeper RS
list than the cached chunk. */
- if ((rb->chunk_index == 0) && (rs->current == rs->size))
- SVN_ERR(set_cached_combined_window(buf, rs, rs->start, new_pool));
+ if ( (rb->chunk_index == 0) && (rs->current == rs->size)
+ && SVN_IS_VALID_REVNUM(rs->revision))
+ SVN_ERR(set_cached_combined_window(buf, rs, new_pool));
+
+ rs->chunk_index++;
/* Cycle pools so that we only need to hold three windows at a time. */
svn_pool_destroy(pool);
@@ -1671,13 +1642,14 @@ delta_read_next_window(svn_txdelta_windo
{
struct delta_read_baton *drb = baton;
- if (drb->rs->current == drb->rs->size)
+ *window = NULL;
+ if (drb->rs->current < drb->rs->size)
{
- *window = NULL;
- return SVN_NO_ERROR;
+ SVN_ERR(read_delta_window(window, drb->rs->chunk_index, drb->rs, pool));
+ drb->rs->chunk_index++;
}
- return read_delta_window(window, drb->rs->chunk_index, drb->rs, pool);
+ return SVN_NO_ERROR;
}
/* This implements the svn_txdelta_md5_digest_fn_t interface. */
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/caching.c?rev=1506925&r1=1506924&r2=1506925&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/caching.c Thu Jul 25 12:25:33 2013
@@ -626,7 +626,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
0, 0, /* Do not use inprocess cache */
svn_fs_fs__serialize_txdelta_window,
svn_fs_fs__deserialize_txdelta_window,
- APR_HASH_KEY_STRING,
+ sizeof(window_cache_key_t),
apr_pstrcat(pool, prefix, "TXDELTA_WINDOW",
(char *)NULL),
0,
@@ -640,7 +640,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
0, 0, /* Do not use inprocess cache */
/* Values are svn_stringbuf_t */
NULL, NULL,
- APR_HASH_KEY_STRING,
+ sizeof(window_cache_key_t),
apr_pstrcat(pool, prefix, "COMBINED_WINDOW",
(char *)NULL),
SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h?rev=1506925&r1=1506924&r2=1506925&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h Thu Jul 25 12:25:33 2013
@@ -245,6 +245,19 @@ typedef struct representation_cache_key_
apr_uint64_t offset;
} representation_cache_key_t;
+/* Key type that identifies a txdelta window. */
+typedef struct window_cache_key_t
+{
+ /* Revision that contains the representation */
+ apr_uint32_t revision;
+
+ /* Window number within that representation */
+ apr_int32_t chunk_index;
+
+ /* Offset of the representation within REVISION */
+ apr_uint64_t offset;
+} window_cache_key_t;
+
/* Private (non-shared) FSFS-specific data for each svn_fs_t object.
Any caches in here may be NULL. */
typedef struct fs_fs_data_t