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/02/11 09:01:43 UTC
svn commit: r1444674 - in
/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs: caching.c fs.h
index.c index.h
Author: stefan2
Date: Mon Feb 11 08:01:42 2013
New Revision: 1444674
URL: http://svn.apache.org/r1444674
Log:
On the fsfs-format7 branch: minimize the impact of logical
addressing, cache the index info. Also, optimize cache access
code to not copy unnecessary data, i.e. use __get_partial
instead of __get. Finally, when having loaded index data from
disk, parse more of it than actually requested and cache it
for future reference.
* subversion/libsvn_fs_fs/fs.h
(fs_fs_data_t): add 4 new caches
* subversion/libsvn_fs_fs/caching.c
(svn_fs_fs__initialize_caches): initialize new caches
* subversion/libsvn_fs_fs/index.c
(l2p_page_info_baton_t,
l2p_page_baton_t,
l2p_page_table_baton_t,
p2l_page_info_baton_t): new cache access data structures
(base_revision,
l2p_header_copy,
l2p_header_access_func,
get_l2p_page_info,
get_l2p_header,
l2p_page_get_offset,
l2p_page_access_func,
l2p_page_table_access_func,
get_l2p_page_table,
prefetch_l2p_pages,
p2l_page_info_copy,
p2l_page_info_func,
prefetch_p2l_page): new utility & cache access functions
(get_l2p_header): rename to ...
(get_l2p_header_body): ... this; add caching support
(svn_fs_fs__l2p_get_max_ids): update; improve pool usage
(get_p2l_header): superseeded by ...
(get_p2l_page_info): ... this one
(l2p_index_lookup,
svn_fs_fs__p2l_index_lookup): use caches and prefetch data
(svn_fs_fs__serialize_l2p_header,
svn_fs_fs__deserialize_l2p_header,
svn_fs_fs__serialize_l2p_page,
svn_fs_fs__deserialize_l2p_page,
svn_fs_fs__serialize_p2l_header,
svn_fs_fs__deserialize_p2l_header,
svn_fs_fs__serialize_p2l_page,
svn_fs_fs__deserialize_p2l_page): implement caches access functions
* subversion/libsvn_fs_fs/index.h
(svn_fs_fs__page_cache_key_t): declare new cache key type
(svn_fs_fs__serialize_l2p_header,
svn_fs_fs__deserialize_l2p_header,
svn_fs_fs__serialize_l2p_page,
svn_fs_fs__deserialize_l2p_page,
svn_fs_fs__serialize_p2l_header,
svn_fs_fs__deserialize_p2l_header,
svn_fs_fs__serialize_p2l_page,
svn_fs_fs__deserialize_p2l_page): declare caches access functions
Modified:
subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/caching.c
subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.h
subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c
subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h
Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/caching.c?rev=1444674&r1=1444673&r2=1444674&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/caching.c Mon Feb 11 08:01:42 2013
@@ -25,6 +25,7 @@
#include "id.h"
#include "dag.h"
#include "tree.h"
+#include "index.h"
#include "temp_serializer.h"
#include "../libsvn_fs/fs-loader.h"
@@ -555,6 +556,69 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
ffd->combined_window_cache = NULL;
}
+ if (ffd->format >= SVN_FS_FS__MIN_LOG_ADDRESSING_FORMAT)
+ {
+ SVN_ERR(create_cache(&(ffd->l2p_header_cache),
+ NULL,
+ membuffer,
+ 0, 0, /* Do not use inprocess cache */
+ svn_fs_fs__serialize_l2p_header,
+ svn_fs_fs__deserialize_l2p_header,
+ sizeof(pair_cache_key_t),
+ apr_pstrcat(pool, prefix, "L2P_HEADER",
+ (char *)NULL),
+ SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ fs,
+ no_handler,
+ fs->pool));
+ SVN_ERR(create_cache(&(ffd->l2p_page_cache),
+ NULL,
+ membuffer,
+ 0, 0, /* Do not use inprocess cache */
+ svn_fs_fs__serialize_l2p_page,
+ svn_fs_fs__deserialize_l2p_page,
+ sizeof(svn_fs_fs__page_cache_key_t),
+ apr_pstrcat(pool, prefix, "L2P_PAGE",
+ (char *)NULL),
+ SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ fs,
+ no_handler,
+ fs->pool));
+ SVN_ERR(create_cache(&(ffd->p2l_header_cache),
+ NULL,
+ membuffer,
+ 0, 0, /* Do not use inprocess cache */
+ svn_fs_fs__serialize_p2l_header,
+ svn_fs_fs__deserialize_p2l_header,
+ sizeof(pair_cache_key_t),
+ apr_pstrcat(pool, prefix, "P2L_HEADER",
+ (char *)NULL),
+ SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ fs,
+ no_handler,
+ fs->pool));
+ SVN_ERR(create_cache(&(ffd->p2l_page_cache),
+ NULL,
+ membuffer,
+ 0, 0, /* Do not use inprocess cache */
+ svn_fs_fs__serialize_p2l_page,
+ svn_fs_fs__deserialize_p2l_page,
+ sizeof(svn_fs_fs__page_cache_key_t),
+ apr_pstrcat(pool, prefix, "P2L_PAGE",
+ (char *)NULL),
+ 0,
+ fs,
+ no_handler,
+ fs->pool));
+ }
+ else
+ {
+ ffd->l2p_header_cache = NULL;
+ ffd->l2p_page_cache = NULL;
+ ffd->p2l_header_cache = NULL;
+ ffd->p2l_page_cache = NULL;
+ }
+
return SVN_NO_ERROR;
}
Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.h?rev=1444674&r1=1444673&r2=1444674&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.h Mon Feb 11 08:01:42 2013
@@ -358,6 +358,23 @@ typedef struct fs_fs_data_t
if the node has mergeinfo, "0" if it doesn't. */
svn_cache__t *mergeinfo_existence_cache;
+ /* Cache for l2p_header_t objects; the key is (revision, is-packed).
+ Will be NULL for pre-format7 repos */
+ svn_cache__t *l2p_header_cache;
+
+ /* Cache for l2p_page_t objects; the key is svn_fs_fs__page_cache_key_t.
+ Will be NULL for pre-format7 repos */
+ svn_cache__t *l2p_page_cache;
+
+ /* Cache for p2l_header_t objects; the key is (revision, is-packed).
+ Will be NULL for pre-format7 repos */
+ svn_cache__t *p2l_header_cache;
+
+ /* Cache for apr_array_header_t objects containing svn_fs_fs__p2l_entry_t
+ elements; the key is svn_fs_fs__page_cache_key_t.
+ Will be NULL for pre-format7 repos */
+ svn_cache__t *p2l_page_cache;
+
/* TRUE while the we hold a lock on the write lock file. */
svn_boolean_t has_write_lock;
Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c?rev=1444674&r1=1444673&r2=1444674&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c Mon Feb 11 08:01:42 2013
@@ -604,16 +604,133 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs
return SVN_NO_ERROR;
}
+/* Return the base revision used to identify the p2l or lp2 index covering
+ * REVISION in FS.
+ */
+static svn_revnum_t
+base_revision(svn_fs_t *fs, svn_revnum_t revision)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+ return is_packed_rev(fs, revision)
+ ? revision - (revision % ffd->max_files_per_dir)
+ : revision;
+}
+
+/* Data structure that describes which l2p page info shall be extracted
+ * from the cache and contains the fields that receive the result.
+ */
+typedef struct l2p_page_info_baton_t
+{
+ /* input data: we want the page covering (REVISION,ITEM_INDEX) */
+ svn_revnum_t revision;
+ apr_uint64_t item_index;
+
+ /* out data */
+ /* page location and size of the page within the l2p index file */
+ l2p_page_table_entry_t entry;
+
+ /* page number within the pages for REVISION (not l2p index global!) */
+ apr_size_t page_no;
+
+ /* offset of ITEM_INDEX within that page */
+ apr_uint32_t page_offset;
+
+ /* revision identifying the l2p index file, also the first rev in that */
+ svn_revnum_t first_revision;
+} l2p_page_info_baton_t;
+
+
+/* Utility function that copies the info requested by BATON->REVISION and
+ * BATON->ITEM_INDEX and from HEADER and PAGE_TABLE into the output fields
+ * of *BATON.
+ */
+static svn_error_t *
+l2p_header_copy(l2p_page_info_baton_t *baton,
+ const l2p_header_t *header,
+ const l2p_page_table_entry_t *page_table,
+ const apr_size_t *page_table_index)
+{
+ /* revision offset within the index file */
+ apr_size_t rel_revision = baton->revision - header->first_revision;
+ if (rel_revision >= header->revision_count)
+ return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_REVISION , NULL,
+ _("Revision %ld not covered by item index"),
+ baton->revision);
+
+ /* select the relevant page */
+ if (baton->item_index < header->page_size)
+ {
+ /* most revs fit well into a single page */
+ baton->page_offset = (apr_size_t)baton->item_index;
+ baton->page_no = 0;
+ baton->entry = page_table[page_table_index[rel_revision]];
+ }
+ else
+ {
+ const l2p_page_table_entry_t *first_entry;
+ const l2p_page_table_entry_t *last_entry;
+
+ /* all pages are of the same size and full, except for the last one */
+ baton->page_offset = (apr_size_t)(baton->item_index % header->page_size);
+ baton->page_no = (apr_uint32_t)(baton->item_index / header->page_size);
+
+ /* range of pages for this rev */
+ first_entry = page_table + page_table_index[rel_revision];
+ last_entry = page_table + page_table_index[rel_revision + 1];
+
+ if (last_entry - first_entry > baton->page_no)
+ {
+ baton->entry = first_entry[baton->page_no];
+ }
+ else
+ {
+ /* limit page index to the valid range */
+ baton->entry = last_entry[-1];
+
+ /* cause index overflow further down the road */
+ baton->page_offset = header->page_size + 1;
+ }
+ }
+
+ baton->first_revision = header->first_revision;
+
+ return SVN_NO_ERROR;
+}
+
+/* Implement svn_cache__partial_getter_func_t: copy the data requested in
+ * l2p_page_info_baton_t *BATON from l2p_header_t *DATA into the output
+ * fields in *BATON.
+ */
+static svn_error_t *
+l2p_header_access_func(void **out,
+ const void *data,
+ apr_size_t data_len,
+ void *baton,
+ apr_pool_t *result_pool)
+{
+ /* resolve all pointer values of in-cache data */
+ const l2p_header_t *header = data;
+ const l2p_page_table_entry_t *page_table
+ = svn_temp_deserializer__ptr(header,
+ (const void *const *)&header->page_table);
+ const apr_size_t *page_table_index
+ = svn_temp_deserializer__ptr(header,
+ (const void *const *)&header->page_table_index);
+
+ /* copy the info */
+ return l2p_header_copy(baton, header, page_table, page_table_index);
+}
+
/* Read the header data structure of the log-to-phys index for REVISION
* in FS and return it in *HEADER. To maximize efficiency, use or return
* the data stream in *STREAM. Use POOL for allocations.
*/
static svn_error_t *
-get_l2p_header(l2p_header_t **header,
- packed_number_stream_t **stream,
- svn_fs_t *fs,
- svn_revnum_t revision,
- apr_pool_t *pool)
+get_l2p_header_body(l2p_header_t **header,
+ packed_number_stream_t **stream,
+ svn_fs_t *fs,
+ svn_revnum_t revision,
+ apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
apr_uint64_t value;
@@ -623,6 +740,10 @@ get_l2p_header(l2p_header_t **header,
l2p_header_t *result = apr_pcalloc(pool, sizeof(*result));
apr_size_t page_table_index;
+ pair_cache_key_t key;
+ key.revision = base_revision(fs, revision);
+ key.second = is_packed_rev(fs, revision);
+
if (*stream == NULL)
SVN_ERR(packed_stream_open(stream, path_l2p_index(fs, revision, pool),
ffd->block_size, pool));
@@ -671,7 +792,73 @@ get_l2p_header(l2p_header_t **header,
offset += result->page_table[page].size;
}
+ /* return and cache the header */
*header = result;
+ SVN_ERR(svn_cache__set(ffd->l2p_header_cache, &key, result, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Get the page info requested in *BATON from FS and set the output fields
+ * in *BATON.
+ * To maximize efficiency, use or return the data stream in *STREAM.
+ * Use POOL for allocations.
+ */
+static svn_error_t *
+get_l2p_page_info(l2p_page_info_baton_t *baton,
+ packed_number_stream_t **stream,
+ svn_fs_t *fs,
+ apr_pool_t *pool)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+ l2p_header_t *result;
+ svn_boolean_t is_cached = FALSE;
+ void *dummy = NULL;
+
+ /* try to find the info in the cache */
+ pair_cache_key_t key;
+ key.revision = base_revision(fs, baton->revision);
+ key.second = is_packed_rev(fs, baton->revision);
+ SVN_ERR(svn_cache__get_partial((void**)&dummy, &is_cached,
+ ffd->l2p_header_cache, &key,
+ l2p_header_access_func, baton,
+ pool));
+ if (is_cached)
+ return SVN_NO_ERROR;
+
+ /* read from disk, cache and copy the result */
+ SVN_ERR(get_l2p_header_body(&result, stream, fs, baton->revision, pool));
+ SVN_ERR(l2p_header_copy(baton, result, result->page_table,
+ result->page_table_index));
+
+ return SVN_NO_ERROR;
+}
+
+/* Read the log-to-phys header info of the index covering REVISION from FS
+ * and return it in *HEADER. To maximize efficiency, use or return the
+ * data stream in *STREAM. Use POOL for allocations.
+ */
+static svn_error_t *
+get_l2p_header(l2p_header_t **header,
+ packed_number_stream_t **stream,
+ svn_fs_t *fs,
+ svn_revnum_t revision,
+ apr_pool_t *pool)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+ svn_boolean_t is_cached = FALSE;
+
+ /* first, try cache lookop */
+ pair_cache_key_t key;
+ key.revision = base_revision(fs, revision);
+ key.second = is_packed_rev(fs, revision);
+ SVN_ERR(svn_cache__get((void**)header, &is_cached, ffd->l2p_header_cache,
+ &key, pool));
+ if (is_cached)
+ return SVN_NO_ERROR;
+
+ /* read from disk and cache the result */
+ SVN_ERR(get_l2p_header_body(header, stream, fs, revision, pool));
return SVN_NO_ERROR;
}
@@ -721,6 +908,224 @@ get_l2p_page(l2p_page_t **page,
return SVN_NO_ERROR;
}
+/* Request data structure for l2p_page_access_func. This one is input
+ * parameters only, i.e. the request results will be passed back otherwise.
+ */
+typedef struct l2p_page_baton_t
+{
+ /* revision. Used for error messages only */
+ svn_revnum_t revision;
+
+ /* item index to look up. Used for error messages only */
+ apr_uint64_t item_index;
+
+ /* offset within the cached page */
+ apr_uint32_t page_offset;
+} l2p_page_baton_t;
+
+/* Return the rev / pack file offset of the item at BATON->PAGE_OFFSET in
+ * OFFSETS of PAGE and write it to *OFFSET.
+ */
+static svn_error_t *
+l2p_page_get_offset(apr_off_t *offset,
+ l2p_page_baton_t *baton,
+ const l2p_page_t *page,
+ const apr_off_t *offsets)
+{
+ /* overflow check */
+ if (page->entry_count <= baton->page_offset)
+ return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+ _("Item index %" APR_UINT64_T_FMT
+ " too large in revision %ld"),
+ baton->item_index, baton->revision);
+
+ /* return the result */
+ *offset = offsets[baton->page_offset];
+
+ return SVN_NO_ERROR;
+}
+
+/* Implement svn_cache__partial_getter_func_t: copy the data requested in
+ * l2p_page_baton_t *BATON from l2p_page_t *DATA into apr_off_t *OUT.
+ */
+static svn_error_t *
+l2p_page_access_func(void **out,
+ const void *data,
+ apr_size_t data_len,
+ void *baton,
+ apr_pool_t *result_pool)
+{
+ /* resolve all in-cache pointers */
+ const l2p_page_t *page = data;
+ const apr_off_t *offsets
+ = svn_temp_deserializer__ptr(page, (const void *const *)&page->offsets);
+
+ /* return the requested data */
+ return l2p_page_get_offset((apr_off_t *)out, baton, page, offsets);
+}
+
+/* Data request structure used by l2p_page_table_access_func.
+ */
+typedef struct l2p_page_table_baton_t
+{
+ /* revision for which to read the page table */
+ svn_revnum_t revision;
+
+ /* page table entries (of type l2p_page_table_entry_t).
+ * Must be created by caller and will be filled by callee. */
+ apr_array_header_t *pages;
+} l2p_page_table_baton_t;
+
+/* Implement svn_cache__partial_getter_func_t: copy the data requested in
+ * l2p_page_baton_t *BATON from l2p_page_t *DATA into apr_off_t *OUT.
+ */
+static svn_error_t *
+l2p_page_table_access_func(void **out,
+ const void *data,
+ apr_size_t data_len,
+ void *baton,
+ apr_pool_t *result_pool)
+{
+ /* resolve in-cache pointers */
+ l2p_page_table_baton_t *table_baton = baton;
+ const l2p_header_t *header = (const l2p_header_t *)data;
+ const l2p_page_table_entry_t *page_table
+ = svn_temp_deserializer__ptr(header,
+ (const void *const *)&header->page_table);
+ const apr_size_t *page_table_index
+ = svn_temp_deserializer__ptr(header,
+ (const void *const *)&header->page_table_index);
+
+ /* copy the revision's page table into BATON */
+ apr_size_t rel_revision = table_baton->revision - header->first_revision;
+ if (rel_revision < header->revision_count)
+ {
+ const l2p_page_table_entry_t *entry
+ = page_table + page_table_index[rel_revision];
+ const l2p_page_table_entry_t *last_entry
+ = page_table + page_table_index[rel_revision + 1];
+
+ for (; entry < last_entry; ++entry)
+ APR_ARRAY_PUSH(table_baton->pages, l2p_page_table_entry_t)
+ = *entry;
+ }
+
+ /* set output as a courtesy to the caller */
+ *out = table_baton->pages;
+
+ return SVN_NO_ERROR;
+}
+
+/* Read the l2p index page table for REVISION in FS from cache and return
+ * it in PAGES. The later must be provided by the caller (and can be
+ * re-used); existing entries will be removed before writing the result.
+ * If the data cannot be found in the cache, the result will be empty
+ * (it never can be empty for a valid REVISION if the data is cached).
+ * Use POOL for temporary allocations.
+ */
+static svn_error_t *
+get_l2p_page_table(apr_array_header_t *pages,
+ svn_fs_t *fs,
+ svn_revnum_t revision,
+ apr_pool_t *pool)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+ svn_boolean_t is_cached = FALSE;
+ l2p_page_table_baton_t baton;
+
+ pair_cache_key_t key;
+ key.revision = base_revision(fs, revision);
+ key.second = is_packed_rev(fs, revision);
+
+ apr_array_clear(pages);
+ baton.revision = revision;
+ baton.pages = pages;
+ SVN_ERR(svn_cache__get_partial((void**)&pages, &is_cached,
+ ffd->l2p_header_cache, &key,
+ l2p_page_table_access_func, &baton, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Utility function. Read the l2p index pages for REVISION in FS from
+ * STREAM and put them into the cache. Skip page number EXLCUDED_PAGE_NO
+ * (use -1 for 'skip none') and pages outside the MIN_OFFSET, MAX_OFFSET
+ * range in the l2p index file. The index is being identified by
+ * FIRST_REVISION. PAGES is a scratch container provided by the caller.
+ * SCRATCH_POOL is used for temporary allocations.
+ */
+static svn_error_t *
+prefetch_l2p_pages(svn_boolean_t *end,
+ svn_fs_t *fs,
+ packed_number_stream_t *stream,
+ svn_revnum_t first_revision,
+ svn_revnum_t revision,
+ apr_array_header_t *pages,
+ int exlcuded_page_no,
+ apr_off_t min_offset,
+ apr_off_t max_offset,
+ apr_pool_t *scratch_pool)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+ int i;
+ apr_pool_t *iterpool;
+ svn_fs_fs__page_cache_key_t key = { 0 };
+
+ /* get the page table for REVISION from cache */
+ *end = FALSE;
+ SVN_ERR(get_l2p_page_table(pages, fs, revision, scratch_pool));
+ if (pages->nelts == 0)
+ {
+ /* not found -> we can't continue without hitting the disk again */
+ *end = TRUE;
+ return SVN_NO_ERROR;
+ }
+
+ /* prefetch pages individually until all are done or we found one in
+ * the cache */
+ iterpool = svn_pool_create(scratch_pool);
+ key.revision = revision;
+ key.is_packed = is_packed_rev(fs, revision);
+
+ for (i = 0; i < pages->nelts && !*end; ++i)
+ {
+ l2p_page_table_entry_t *entry
+ = &APR_ARRAY_IDX(pages, i, l2p_page_table_entry_t);
+ if (i == exlcuded_page_no)
+ continue;
+
+ /* skip pages outside the specified index file range */
+ if ( entry->offset < min_offset
+ || entry->offset + entry->size > max_offset)
+ {
+ *end = TRUE;
+ continue;
+ }
+
+ /* page already in cache? */
+ key.page = i;
+ SVN_ERR(svn_cache__has_key(end, ffd->l2p_page_cache,
+ &key, iterpool));
+ if (!*end)
+ {
+ /* no in cache -> read from stream (data already buffered in APR)
+ * and cache the result */
+ l2p_page_t *page = NULL;
+ SVN_ERR(get_l2p_page(&page, &stream, fs, first_revision,
+ entry, iterpool));
+
+ SVN_ERR(svn_cache__set(ffd->l2p_page_cache, &key, page,
+ iterpool));
+ }
+
+ svn_pool_clear(iterpool);
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
/* Using the log-to-phys indexes in FS, find the absolute offset in the
* rev file for (REVISION, ITEM_INDEX) and return it in *OFFSET.
* Use POOL for allocations.
@@ -732,72 +1137,90 @@ l2p_index_lookup(apr_off_t *offset,
apr_uint64_t item_index,
apr_pool_t *pool)
{
- l2p_header_t *header = NULL;
+ fs_fs_data_t *ffd = fs->fsap_data;
+ l2p_page_info_baton_t info_baton;
+ l2p_page_baton_t page_baton;
l2p_page_t *page = NULL;
- l2p_page_table_entry_t *entry, *first_entry, *last_entry;
- apr_size_t page_no;
- apr_uint32_t page_offset;
packed_number_stream_t *stream = NULL;
+ svn_fs_fs__page_cache_key_t key = { 0 };
+ svn_boolean_t is_cached = FALSE;
- /* read index master data structure */
- SVN_ERR(get_l2p_header(&header, &stream, fs, revision, pool));
- if ( (header->first_revision > revision)
- || (header->first_revision + header->revision_count <= revision))
+ /* read index master data structure and extract the info required to
+ * access the l2p index page for (REVISION,ITEM_INDEX)*/
+ info_baton.revision = revision;
+ info_baton.item_index = item_index;
+ SVN_ERR(get_l2p_page_info(&info_baton, &stream, fs, pool));
+
+ /* try to find the page in the cache and get the OFFSET from it */
+ page_baton.revision = revision;
+ page_baton.item_index = item_index;
+ page_baton.page_offset = info_baton.page_offset;
+
+ key.revision = revision;
+ key.is_packed = is_packed_rev(fs, revision);
+ key.page = info_baton.page_no;
+
+ SVN_ERR(svn_cache__get_partial((void**)offset, &is_cached,
+ ffd->l2p_page_cache, &key,
+ l2p_page_access_func, &page_baton, pool));
+ if (!is_cached)
{
- SVN_ERR(packed_stream_close(stream));
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_REVISION , NULL,
- _("Revision %ld not covered by item index"),
- revision);
- }
-
- /* select the relevant page */
- if (item_index < header->page_size)
- {
- /* most revs fit well into a single page */
- page_offset = (apr_size_t)item_index;
- page_no = 0;
- entry = header->page_table
- + header->page_table_index[revision - header->first_revision];
- }
- else
- {
- /* all pages are of the same size and full, except for the last one */
- page_offset = (apr_size_t)(item_index % header->page_size);
- page_no = (apr_uint32_t)(item_index / header->page_size);
-
- /* range of pages for this rev */
- first_entry = header->page_table
- + header->page_table_index[revision - header->first_revision];
- last_entry = header->page_table
- + header->page_table_index[revision + 1 - header->first_revision];
-
- if (last_entry - first_entry > page_no)
+ /* we need to read the info from disk (might already be in the
+ * APR file buffer, though) */
+ apr_array_header_t *pages;
+ svn_revnum_t prefetch_revision;
+ svn_revnum_t last_revision
+ = info_baton.first_revision
+ + (key.is_packed ? ffd->max_files_per_dir : 1);
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ svn_boolean_t end;
+ apr_off_t max_offset
+ = APR_ALIGN(info_baton.entry.offset + info_baton.entry.size,
+ 0x10000);
+ apr_off_t min_offset = max_offset - 0x10000;
+
+ /* read the relevant page */
+ SVN_ERR(get_l2p_page(&page, &stream, fs, info_baton.first_revision,
+ &info_baton.entry, pool));
+
+ /* cache the page and extract the result we need */
+ SVN_ERR(svn_cache__set(ffd->l2p_page_cache, &key, page, pool));
+ SVN_ERR(l2p_page_get_offset(offset, &page_baton, page, page->offsets));
+
+ /* prefetch pages from following and preceding revisions */
+ pages = apr_array_make(pool, 16, sizeof(l2p_page_table_entry_t));
+ end = FALSE;
+ for (prefetch_revision = revision;
+ prefetch_revision < last_revision && !end;
+ ++prefetch_revision)
{
- entry = first_entry + page_no;
+ int excluded_page_no = prefetch_revision == revision
+ ? info_baton.page_no
+ : -1;
+ SVN_ERR(prefetch_l2p_pages(&end, fs, stream,
+ info_baton.first_revision,
+ prefetch_revision, pages,
+ excluded_page_no, min_offset,
+ max_offset, iterpool));
+ svn_pool_clear(iterpool);
}
- else
- {
- /* limit page index to the valid range */
- entry = last_entry - 1;
- /* cause index overflow further down the road */
- page_offset = header->page_size;
+ end = FALSE;
+ for (prefetch_revision = revision-1;
+ prefetch_revision >= info_baton.first_revision && !end;
+ --prefetch_revision)
+ {
+ SVN_ERR(prefetch_l2p_pages(&end, fs, stream,
+ info_baton.first_revision,
+ prefetch_revision, pages, -1,
+ min_offset, max_offset, iterpool));
+ svn_pool_clear(iterpool);
}
+
+ svn_pool_destroy(iterpool);
}
- /* read the relevant page */
- SVN_ERR(get_l2p_page(&page, &stream, fs, header->first_revision, entry,
- pool));
SVN_ERR(packed_stream_close(stream));
-
- if (page->entry_count <= page_offset)
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
- _("Item index %" APR_UINT64_T_FMT
- " too large in revision %ld"),
- item_index, revision);
-
- /* return the result */
- *offset = page->offsets[item_index];
return SVN_NO_ERROR;
}
@@ -855,37 +1278,47 @@ svn_fs_fs__l2p_get_max_ids(apr_array_hea
svn_revnum_t revision;
svn_revnum_t last_rev = (svn_revnum_t)(start_rev + count);
packed_number_stream_t *stream = NULL;
+ apr_pool_t *header_pool = svn_pool_create(pool);
- /* read index master data structure */
- SVN_ERR(get_l2p_header(&header, &stream, fs, start_rev, pool));
+ /* read index master data structure for the index covering START_REV */
+ SVN_ERR(get_l2p_header(&header, &stream, fs, start_rev, header_pool));
SVN_ERR(packed_stream_close(stream));
stream = NULL;
+ /* Determine the length of the item index list for each rev.
+ * Read new index headers as required. */
*max_ids = apr_array_make(pool, (int)count, sizeof(apr_uint64_t));
for (revision = start_rev; revision < last_rev; ++revision)
{
- apr_uint64_t page_count;
+ apr_uint64_t full_page_count;
apr_uint64_t item_count;
apr_size_t first_page_index, last_page_index;
if (revision >= header->first_revision + header->revision_count)
{
- SVN_ERR(get_l2p_header(&header, &stream, fs, revision, pool));
+ /* need to read the next index. Clear up memory used for the
+ * previous one. */
+ svn_pool_clear(header_pool);
+ SVN_ERR(get_l2p_header(&header, &stream, fs, revision,
+ header_pool));
SVN_ERR(packed_stream_close(stream));
stream = NULL;
}
+ /* in a revision with N index pages, the first N-1 index pages are
+ * "full", i.e. contain HEADER->PAGE_SIZE entries */
first_page_index
= header->page_table_index[revision - header->first_revision];
last_page_index
= header->page_table_index[revision - header->first_revision + 1];
- page_count = first_page_index - last_page_index - 1;
- item_count = page_count * header->page_size
+ full_page_count = first_page_index - last_page_index - 1;
+ item_count = full_page_count * header->page_size
+ header->page_table[last_page_index - 1].entry_count;
APR_ARRAY_PUSH(*max_ids, apr_uint64_t) = item_count;
}
+ svn_pool_destroy(header_pool);
return SVN_NO_ERROR;
}
@@ -1062,26 +1495,115 @@ svn_fs_fs__p2l_index_create(svn_fs_t *fs
return SVN_NO_ERROR;
}
-/* Read the header data structure of the phys-to-log index for REVISION
- * in FS and return it in *HEADER. To maximize efficiency, use or return
- * the data stream in *STREAM. Use POOL for allocations.
+/* Data structure that describes which p2l page info shall be extracted
+ * from the cache and contains the fields that receive the result.
+ */
+typedef struct p2l_page_info_baton_t
+{
+ /* input variables */
+ /* revision identifying the index file */
+ svn_revnum_t revision;
+
+ /* offset within the page in rev / pack file */
+ apr_off_t offset;
+
+ /* output variables */
+ /* page containing OFFSET */
+ apr_size_t page_no;
+
+ /* first revision in this p2l index */
+ svn_revnum_t first_revision;
+
+ /* offset within the p2l index file describing this page */
+ apr_off_t start_offset;
+
+ /* offset within the p2l index file describing the following page */
+ apr_off_t next_offset;
+
+ /* PAGE_NO * PAGE_SIZE (is <= OFFSET) */
+ apr_off_t page_start;
+
+ /* total number of pages indexed */
+ apr_size_t page_count;
+
+ /* size of each page in pack / rev file */
+ apr_uint64_t page_size;
+} p2l_page_info_baton_t;
+
+/* From HEADER and the list of all OFFSETS, fill BATON with the page info
+ * requested by BATON->OFFSET.
+ */
+static void
+p2l_page_info_copy(p2l_page_info_baton_t *baton,
+ const p2l_header_t *header,
+ const apr_off_t *offsets)
+{
+ baton->page_no = baton->offset / header->page_size;
+ baton->first_revision = header->first_revision;
+ baton->start_offset = offsets[baton->page_no];
+ baton->next_offset = offsets[baton->page_no + 1];
+ baton->page_start = (apr_off_t)(header->page_size * baton->page_no);
+ baton->page_count = header->page_count;
+ baton->page_size = header->page_size;
+}
+
+/* Implement svn_cache__partial_getter_func_t: extract the p2l page info
+ * requested by BATON and return it in BATON.
*/
static svn_error_t *
-get_p2l_header(p2l_header_t **header,
- packed_number_stream_t **stream,
- svn_fs_t *fs,
- svn_revnum_t revision,
- apr_pool_t *pool)
+p2l_page_info_func(void **out,
+ const void *data,
+ apr_size_t data_len,
+ void *baton,
+ apr_pool_t *result_pool)
+{
+ /* all the pointers to cached data we need */
+ const p2l_header_t *header = data;
+ const apr_off_t *offsets
+ = svn_temp_deserializer__ptr(header,
+ (const void *const *)&header->offsets);
+
+ /* copy data from cache to BATON */
+ p2l_page_info_copy(baton, header, offsets);
+ return SVN_NO_ERROR;
+}
+
+/* Read the header data structure of the phys-to-log index for revision
+ * BATON->REVISION in FS. Return in *BATON all info relevant to read the
+ * index page for the rev / pack file offset BATON->OFFSET.
+ *
+ * To maximize efficiency, use or return the data stream in *STREAM.
+ * Use POOL for allocations.
+ */
+static svn_error_t *
+get_p2l_page_info(p2l_page_info_baton_t *baton,
+ packed_number_stream_t **stream,
+ svn_fs_t *fs,
+ apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
apr_uint64_t value;
apr_size_t i;
apr_off_t offset;
p2l_header_t *result = apr_pcalloc(pool, sizeof(*result));
+ svn_boolean_t is_cached = FALSE;
+ void *dummy = NULL;
- /* open index file */
+ /* look for the header data in our cache */
+ pair_cache_key_t key;
+ key.revision = base_revision(fs, baton->revision);
+ key.second = is_packed_rev(fs, baton->revision);
+
+ SVN_ERR(svn_cache__get_partial(&dummy, &is_cached, ffd->p2l_header_cache,
+ &key, p2l_page_info_func, baton, pool));
+ if (is_cached)
+ return SVN_NO_ERROR;
+
+ /* not found -> must read it from disk.
+ * Open index file */
if (*stream == NULL)
- SVN_ERR(packed_stream_open(stream, path_p2l_index(fs, revision, pool),
+ SVN_ERR(packed_stream_open(stream,
+ path_p2l_index(fs, baton->revision, pool),
ffd->block_size, pool));
/* read table sizes and allocate page array */
@@ -1107,7 +1629,11 @@ get_p2l_header(p2l_header_t **header,
for (i = 0; i <= result->page_count; ++i)
result->offsets[i] += offset;
- *header = result;
+ /* copy the requested info into *BATON */
+ p2l_page_info_copy(baton, result, result->offsets);
+
+ /* cache the header data */
+ SVN_ERR(svn_cache__set(ffd->p2l_header_cache, &key, result, pool));
return SVN_NO_ERROR;
}
@@ -1201,6 +1727,62 @@ get_p2l_page(apr_array_header_t **entrie
return SVN_NO_ERROR;
}
+/* If it cannot be found in FS's caches, read the p2l index page selected
+ * by BATON->OFFSET from STREAM. Don't read it, if it precedes MIN_OFFSET.
+ * Set *END to TRUE if the caller should stop refeching.
+ *
+ * *BATON will be updated with the selected page's info and SCRATCH_POOL
+ * will be used for temporary allocations.
+ */
+static svn_error_t *
+prefetch_p2l_page(svn_boolean_t *end,
+ svn_fs_t *fs,
+ packed_number_stream_t *stream,
+ p2l_page_info_baton_t *baton,
+ apr_off_t min_offset,
+ apr_pool_t *scratch_pool)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+ apr_array_header_t *page;
+ svn_fs_fs__page_cache_key_t key = { 0 };
+
+ /* fetch the page info */
+ *end = FALSE;
+ baton->revision = baton->first_revision;
+ SVN_ERR(get_p2l_page_info(baton, &stream, fs, scratch_pool));
+ if (baton->start_offset < min_offset)
+ {
+ /* page outside limits -> stop prefetching */
+ *end = TRUE;
+ return SVN_NO_ERROR;
+ }
+
+ /* do we have that page in our caches already? */
+ key.revision = baton->first_revision;
+ key.is_packed = is_packed_rev(fs, baton->first_revision);
+ key.page = baton->page_no;
+ SVN_ERR(svn_cache__has_key(end, ffd->p2l_page_cache,
+ &key, scratch_pool));
+ if (*end)
+ {
+ /* yes, already cached -> stop prefetching */
+ return SVN_NO_ERROR;
+ }
+
+ /* read from disk */
+ SVN_ERR(get_p2l_page(&page, &stream, fs,
+ baton->first_revision,
+ baton->start_offset,
+ baton->next_offset,
+ baton->page_start,
+ baton->page_size, scratch_pool));
+
+ /* and put it into our cache */
+ SVN_ERR(svn_cache__set(ffd->p2l_page_cache, &key, page, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_fs_fs__p2l_index_lookup(apr_array_header_t **entries,
svn_fs_t *fs,
@@ -1208,14 +1790,20 @@ svn_fs_fs__p2l_index_lookup(apr_array_he
apr_off_t offset,
apr_pool_t *pool)
{
- p2l_header_t *header = NULL;
- apr_size_t page_no;
+ fs_fs_data_t *ffd = fs->fsap_data;
packed_number_stream_t *stream = NULL;
+ svn_fs_fs__page_cache_key_t key = { 0 };
+ svn_boolean_t is_cached = FALSE;
+ p2l_page_info_baton_t page_info;
+
+ /* request info for the index pages that describes the pack / rev file
+ * contents at pack / rev file position OFFSET. */
+ page_info.offset = offset;
+ page_info.revision = revision;
+ SVN_ERR(get_p2l_page_info(&page_info, &stream, fs, pool));
- SVN_ERR(get_p2l_header(&header, &stream, fs, revision, pool));
- page_no = offset / header->page_size;
-
- if (header->page_count <= page_no)
+ /* if the offset refers to a non-existent page, bail out */
+ if (page_info.page_count <= page_info.page_no)
{
SVN_ERR(packed_stream_close(stream));
return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
@@ -1224,11 +1812,64 @@ svn_fs_fs__p2l_index_lookup(apr_array_he
offset, revision);
}
- SVN_ERR(get_p2l_page(entries, &stream, fs, header->first_revision,
- header->offsets[page_no],
- header->offsets[page_no + 1],
- (apr_off_t)(page_no * header->page_size),
- header->page_size, pool));
+ /* look for this page in our cache */
+ key.revision = page_info.first_revision;
+ key.is_packed = is_packed_rev(fs, revision);
+ key.page = page_info.page_no;
+
+ SVN_ERR(svn_cache__get((void**)entries, &is_cached, ffd->p2l_page_cache,
+ &key, pool));
+ if (!is_cached)
+ {
+ apr_off_t max_offset = APR_ALIGN(page_info.next_offset, ffd->block_size);
+ apr_off_t min_offset = max_offset - ffd->block_size;
+ svn_boolean_t end;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ apr_off_t original_page_start = page_info.page_start;
+
+ /* fetch page from disk and put it into the cache */
+ SVN_ERR(get_p2l_page(entries, &stream, fs,
+ page_info.first_revision,
+ page_info.start_offset,
+ page_info.next_offset,
+ page_info.page_start,
+ page_info.page_size, pool));
+
+ SVN_ERR(svn_cache__set(ffd->p2l_page_cache, &key, *entries, pool));
+
+ /* Since we read index data in larger chunks, we probably got more
+ * page data than we requested. Parse & cache that until either we
+ * encounter pages already cached or reach the end of the buffer.
+ */
+
+ /* pre-fetch following pages */
+ end = FALSE;
+ page_info.offset = original_page_start;
+ while ( page_info.next_offset < max_offset
+ && page_info.page_no + 1 < page_info.page_count
+ && !end)
+ {
+ page_info.offset += page_info.page_size;
+ SVN_ERR(prefetch_p2l_page(&end, fs, stream, &page_info,
+ min_offset, iterpool));
+ svn_pool_clear(iterpool);
+ }
+
+ /* pre-fetch preceding pages */
+ end = FALSE;
+ page_info.offset = original_page_start;
+ while (page_info.offset >= page_info.page_size && !end)
+ {
+ page_info.offset -= page_info.page_size;
+ SVN_ERR(prefetch_p2l_page(&end, fs, stream, &page_info,
+ min_offset, iterpool));
+ svn_pool_clear(iterpool);
+ }
+
+ svn_pool_destroy(iterpool);
+ }
+
+ /* make sure we close files after usage */
SVN_ERR(packed_stream_close(stream));
return SVN_NO_ERROR;
@@ -1265,3 +1906,213 @@ svn_fs_fs__item_offset(apr_off_t *offset
return SVN_NO_ERROR;
}
+
+/*
+ * Standard (de-)serialization functions
+ */
+
+svn_error_t *
+svn_fs_fs__serialize_l2p_header(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool)
+{
+ l2p_header_t *header = in;
+ svn_temp_serializer__context_t *context;
+ svn_stringbuf_t *serialized;
+ apr_size_t page_count = header->page_table_index[header->revision_count];
+ apr_size_t page_table_size = page_count * sizeof(*header->page_table);
+ apr_size_t index_size
+ = (header->revision_count + 1) * sizeof(*header->page_table_index);
+ apr_size_t data_size = sizeof(*header) + index_size + page_table_size;
+
+ /* serialize header and all its elements */
+ context = svn_temp_serializer__init(header,
+ sizeof(*header),
+ data_size + 32,
+ pool);
+
+ /* page table index array */
+ svn_temp_serializer__add_leaf(context,
+ (const void * const *)&header->page_table_index,
+ index_size);
+
+ /* page table array */
+ svn_temp_serializer__add_leaf(context,
+ (const void * const *)&header->page_table,
+ page_table_size);
+
+ /* return the serialized result */
+ serialized = svn_temp_serializer__get(context);
+
+ *data = serialized->data;
+ *data_len = serialized->len;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__deserialize_l2p_header(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool)
+{
+ l2p_header_t *header = (l2p_header_t *)data;
+
+ /* resolve the pointers in the struct */
+ svn_temp_deserializer__resolve(header, (void**)&header->page_table_index);
+ svn_temp_deserializer__resolve(header, (void**)&header->page_table);
+
+ /* done */
+ *out = header;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__serialize_l2p_page(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool)
+{
+ l2p_page_t *page = in;
+ svn_temp_serializer__context_t *context;
+ svn_stringbuf_t *serialized;
+ apr_size_t table_size = page->entry_count * sizeof(*page->offsets);
+
+ /* serialize struct and all its elements */
+ context = svn_temp_serializer__init(page,
+ sizeof(*page),
+ table_size + sizeof(*page) + 32,
+ pool);
+
+ /* offsets array */
+ svn_temp_serializer__add_leaf(context,
+ (const void * const *)&page->offsets,
+ table_size);
+
+ /* return the serialized result */
+ serialized = svn_temp_serializer__get(context);
+
+ *data = serialized->data;
+ *data_len = serialized->len;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__deserialize_l2p_page(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool)
+{
+ l2p_page_t *page = data;
+
+ /* resolve the only pointer in the struct */
+ svn_temp_deserializer__resolve(page, (void**)&page->offsets);
+
+ /* done */
+ *out = page;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__serialize_p2l_header(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool)
+{
+ p2l_header_t *header = in;
+ svn_temp_serializer__context_t *context;
+ svn_stringbuf_t *serialized;
+ apr_size_t table_size = (header->page_count + 1) * sizeof(*header->offsets);
+
+ /* serialize header and all its elements */
+ context = svn_temp_serializer__init(header,
+ sizeof(*header),
+ table_size + sizeof(*header) + 32,
+ pool);
+
+ /* offsets array */
+ svn_temp_serializer__add_leaf(context,
+ (const void * const *)&header->offsets,
+ table_size);
+
+ /* return the serialized result */
+ serialized = svn_temp_serializer__get(context);
+
+ *data = serialized->data;
+ *data_len = serialized->len;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__deserialize_p2l_header(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool)
+{
+ p2l_header_t *header = data;
+
+ /* resolve the only pointer in the struct */
+ svn_temp_deserializer__resolve(header, (void**)&header->offsets);
+
+ /* done */
+ *out = header;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__serialize_p2l_page(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool)
+{
+ apr_array_header_t *page = in;
+ svn_temp_serializer__context_t *context;
+ svn_stringbuf_t *serialized;
+ apr_size_t table_size = page->elt_size * page->nelts;
+
+ /* serialize array header and all its elements */
+ context = svn_temp_serializer__init(page,
+ sizeof(*page),
+ table_size + sizeof(*page) + 32,
+ pool);
+
+ /* items in the array */
+ svn_temp_serializer__add_leaf(context,
+ (const void * const *)&page->elts,
+ table_size);
+
+ /* return the serialized result */
+ serialized = svn_temp_serializer__get(context);
+
+ *data = serialized->data;
+ *data_len = serialized->len;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__deserialize_p2l_page(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool)
+{
+ apr_array_header_t *page = (apr_array_header_t *)data;
+
+ /* resolve the only pointer in the struct */
+ svn_temp_deserializer__resolve(page, (void**)&page->elts);
+
+ /* patch up members */
+ page->pool = pool;
+ page->nalloc = page->nelts;
+
+ /* done */
+ *out = page;
+
+ return SVN_NO_ERROR;
+}
Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h?rev=1444674&r1=1444673&r2=1444674&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h Mon Feb 11 08:01:42 2013
@@ -183,4 +183,99 @@ svn_fs_fs__l2p_get_max_ids(apr_array_hea
apr_size_t count,
apr_pool_t *pool);
+/* Serialization and caching interface
+ */
+
+/* We use this key type to address individual pages from both index types.
+ */
+typedef struct svn_fs_fs__page_cache_key_t
+{
+ /* in l2p: this is the revision of the items being mapped
+ in p2l: this is the start revision identifying the pack / rev file */
+ svn_revnum_t revision;
+
+ /* if TRUE, this is the index to a pack file
+ */
+ svn_boolean_t is_packed;
+
+ /* in l2p: page number within the revision
+ * in p2l: page number with the rev / pack file
+ */
+ apr_uint64_t page;
+} svn_fs_fs__page_cache_key_t;
+
+/*
+ * Implements svn_cache__serialize_func_t for l2p_header_t objects.
+ */
+svn_error_t *
+svn_fs_fs__serialize_l2p_header(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool);
+
+/*
+ * Implements svn_cache__deserialize_func_t for l2p_header_t objects.
+ */
+svn_error_t *
+svn_fs_fs__deserialize_l2p_header(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool);
+
+/*
+ * Implements svn_cache__serialize_func_t for l2p_page_t objects.
+ */
+svn_error_t *
+svn_fs_fs__serialize_l2p_page(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool);
+
+/*
+ * Implements svn_cache__deserialize_func_t for l2p_page_t objects.
+ */
+svn_error_t *
+svn_fs_fs__deserialize_l2p_page(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool);
+
+/*
+ * Implements svn_cache__serialize_func_t for p2l_header_t objects.
+ */
+svn_error_t *
+svn_fs_fs__serialize_p2l_header(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool);
+
+/*
+ * Implements svn_cache__deserialize_func_t for p2l_header_t objects.
+ */
+svn_error_t *
+svn_fs_fs__deserialize_p2l_header(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool);
+
+/*
+ * Implements svn_cache__serialize_func_t for apr_array_header_t objects
+ * with elements of type svn_fs_fs__p2l_entry_t.
+ */
+svn_error_t *
+svn_fs_fs__serialize_p2l_page(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool);
+
+/*
+ * Implements svn_cache__deserialize_func_t for apr_array_header_t objects
+ * with elements of type svn_fs_fs__p2l_entry_t.
+ */
+svn_error_t *
+svn_fs_fs__deserialize_p2l_page(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool);
+
#endif