diff options
author | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
---|---|---|
committer | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
commit | 3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch) | |
tree | 7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/libsvn_fs_x/rev_file.c | |
parent | a55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff) |
Diffstat (limited to 'subversion/libsvn_fs_x/rev_file.c')
-rw-r--r-- | subversion/libsvn_fs_x/rev_file.c | 321 |
1 files changed, 272 insertions, 49 deletions
diff --git a/subversion/libsvn_fs_x/rev_file.c b/subversion/libsvn_fs_x/rev_file.c index 445d45b55b436..2a362337a93cf 100644 --- a/subversion/libsvn_fs_x/rev_file.c +++ b/subversion/libsvn_fs_x/rev_file.c @@ -20,6 +20,8 @@ * ==================================================================== */ +#include "svn_pools.h" + #include "rev_file.h" #include "fs_x.h" #include "index.h" @@ -31,6 +33,46 @@ #include "private/svn_io_private.h" #include "svn_private_config.h" +struct svn_fs_x__revision_file_t +{ + /* the filesystem that this revision file belongs to */ + svn_fs_t *fs; + + /* Meta-data to FILE. */ + svn_fs_x__rev_file_info_t file_info; + + /* rev / pack file */ + apr_file_t *file; + + /* stream based on FILE and not NULL exactly when FILE is not NULL */ + svn_stream_t *stream; + + /* the opened P2L index stream or NULL. Always NULL for txns. */ + svn_fs_x__packed_number_stream_t *p2l_stream; + + /* the opened L2P index stream or NULL. Always NULL for txns. */ + svn_fs_x__packed_number_stream_t *l2p_stream; + + /* Copied from FS->FFD->BLOCK_SIZE upon creation. It allows us to + * use aligned seek() without having the FS handy. */ + apr_off_t block_size; + + /* Info on the L2P index within FILE. + * Elements are -1 / NULL until svn_fs_x__auto_read_footer gets called. */ + svn_fs_x__index_info_t l2p_info; + + /* Info on the P2L index within FILE. + * Elements are -1 / NULL until svn_fs_x__auto_read_footer gets called. */ + svn_fs_x__index_info_t p2l_info; + + /* Pool used for all sub-structure allocations (file, streams etc.). + A sub-pool of OWNER. NULL until the lazily initilized. */ + apr_pool_t *pool; + + /* Pool that this structure got allocated in. */ + apr_pool_t *owner; +}; + /* Return a new revision file instance, allocated in RESULT_POOL, for * filesystem FS. Set its pool member to the provided RESULT_POOL. */ static svn_fs_x__revision_file_t * @@ -38,22 +80,24 @@ create_revision_file(svn_fs_t *fs, apr_pool_t *result_pool) { svn_fs_x__data_t *ffd = fs->fsap_data; - svn_fs_x__revision_file_t *file = apr_palloc(result_pool, sizeof(*file)); - - file->is_packed = FALSE; - file->start_revision = SVN_INVALID_REVNUM; + svn_fs_x__revision_file_t *file = apr_palloc(result_pool, sizeof(*file)); + file->fs = fs; + file->file_info.is_packed = FALSE; + file->file_info.start_revision = SVN_INVALID_REVNUM; file->file = NULL; file->stream = NULL; file->p2l_stream = NULL; file->l2p_stream = NULL; file->block_size = ffd->block_size; - file->l2p_offset = -1; - file->l2p_checksum = NULL; - file->p2l_offset = -1; - file->p2l_checksum = NULL; - file->footer_offset = -1; - file->pool = result_pool; + file->l2p_info.start = -1; + file->l2p_info.end = -1; + file->l2p_info.checksum = NULL; + file->p2l_info.start = -1; + file->p2l_info.end = -1; + file->p2l_info.checksum = NULL; + file->pool = NULL; + file->owner = result_pool; return file; } @@ -68,8 +112,8 @@ init_revision_file(svn_fs_t *fs, { svn_fs_x__revision_file_t *file = create_revision_file(fs, result_pool); - file->is_packed = svn_fs_x__is_packed_rev(fs, revision); - file->start_revision = svn_fs_x__packed_base_rev(fs, revision); + file->file_info.is_packed = svn_fs_x__is_packed_rev(fs, revision); + file->file_info.start_revision = svn_fs_x__packed_base_rev(fs, revision); return file; } @@ -137,20 +181,31 @@ auto_make_writable(const char *path, return SVN_NO_ERROR; } -/* Core implementation of svn_fs_fs__open_pack_or_rev_file working on an +/* Return the pool to be used for allocations with FILE. + Lazily created that pool upon the first call. */ +static apr_pool_t * +get_file_pool(svn_fs_x__revision_file_t *file) +{ + if (file->pool == NULL) + file->pool = svn_pool_create(file->owner); + + return file->pool; +} + +/* Core implementation of svn_fs_x__open_pack_or_rev_file working on an * existing, initialized FILE structure. If WRITABLE is TRUE, give write * access to the file - temporarily resetting the r/o state if necessary. */ static svn_error_t * open_pack_or_rev_file(svn_fs_x__revision_file_t *file, - svn_fs_t *fs, - svn_revnum_t rev, svn_boolean_t writable, - apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_error_t *err; svn_boolean_t retry = FALSE; + svn_fs_t *fs = file->fs; + svn_revnum_t rev = file->file_info.start_revision; + apr_pool_t *file_pool = get_file_pool(file); do { @@ -161,19 +216,19 @@ open_pack_or_rev_file(svn_fs_x__revision_file_t *file, : APR_READ | APR_BUFFERED; /* We may have to *temporarily* enable write access. */ - err = writable ? auto_make_writable(path, result_pool, scratch_pool) + err = writable ? auto_make_writable(path, file_pool, scratch_pool) : SVN_NO_ERROR; /* open the revision file in buffered r/o or r/w mode */ if (!err) err = svn_io_file_open(&apr_file, path, flags, APR_OS_DEFAULT, - result_pool); + file_pool); if (!err) { file->file = apr_file; file->stream = svn_stream_from_aprfile2(apr_file, TRUE, - result_pool); + file_pool); return SVN_NO_ERROR; } @@ -191,7 +246,7 @@ open_pack_or_rev_file(svn_fs_x__revision_file_t *file, /* We failed for the first time. Refresh cache & retry. */ SVN_ERR(svn_fs_x__update_min_unpacked_rev(fs, scratch_pool)); - file->start_revision = svn_fs_x__packed_base_rev(fs, rev); + file->file_info.start_revision = svn_fs_x__packed_base_rev(fs, rev); retry = TRUE; } @@ -206,39 +261,52 @@ open_pack_or_rev_file(svn_fs_x__revision_file_t *file, } svn_error_t * -svn_fs_x__open_pack_or_rev_file(svn_fs_x__revision_file_t **file, - svn_fs_t *fs, - svn_revnum_t rev, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +svn_fs_x__rev_file_init(svn_fs_x__revision_file_t **file, + svn_fs_t *fs, + svn_revnum_t rev, + apr_pool_t *result_pool) { *file = init_revision_file(fs, rev, result_pool); - return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, FALSE, - result_pool, scratch_pool)); + return SVN_NO_ERROR; } svn_error_t * -svn_fs_x__open_pack_or_rev_file_writable(svn_fs_x__revision_file_t** file, - svn_fs_t* fs, - svn_revnum_t rev, - apr_pool_t* result_pool, - apr_pool_t *scratch_pool) +svn_fs_x__rev_file_open_writable(svn_fs_x__revision_file_t** file, + svn_fs_t* fs, + svn_revnum_t rev, + apr_pool_t* result_pool, + apr_pool_t *scratch_pool) { *file = init_revision_file(fs, rev, result_pool); - return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, TRUE, - result_pool, scratch_pool)); + return svn_error_trace(open_pack_or_rev_file(*file, TRUE, scratch_pool)); } -svn_error_t * -svn_fs_x__auto_read_footer(svn_fs_x__revision_file_t *file) +/* If the revision file in FILE has not been opened, yet, do it now. */ +static svn_error_t * +auto_open(svn_fs_x__revision_file_t *file) { - if (file->l2p_offset == -1) + if (file->file == NULL) + SVN_ERR(open_pack_or_rev_file(file, FALSE, get_file_pool(file))); + + return SVN_NO_ERROR; +} + +/* If the footer data in FILE has not been read, yet, do so now. + * Index locations will only be read upon request as we assume they get + * cached and the FILE is usually used for REP data access only. + * Hence, the separate step. + */ +static svn_error_t * +auto_read_footer(svn_fs_x__revision_file_t *file) +{ + if (file->l2p_info.start == -1) { apr_off_t filesize = 0; unsigned char footer_length; svn_stringbuf_t *footer; /* Determine file size. */ + SVN_ERR(auto_open(file)); SVN_ERR(svn_io_file_seek(file->file, APR_END, &filesize, file->pool)); /* Read last byte (containing the length of the footer). */ @@ -258,22 +326,25 @@ svn_fs_x__auto_read_footer(svn_fs_x__revision_file_t *file) footer->data[footer->len] = '\0'; /* Extract index locations. */ - SVN_ERR(svn_fs_x__parse_footer(&file->l2p_offset, &file->l2p_checksum, - &file->p2l_offset, &file->p2l_checksum, - footer, file->start_revision, - file->pool)); - file->footer_offset = filesize - footer_length - 1; + SVN_ERR(svn_fs_x__parse_footer(&file->l2p_info.start, + &file->l2p_info.checksum, + &file->p2l_info.start, + &file->p2l_info.checksum, + footer, file->file_info.start_revision, + filesize - footer_length - 1, file->pool)); + file->l2p_info.end = file->p2l_info.start; + file->p2l_info.end = filesize - footer_length - 1; } return SVN_NO_ERROR; } svn_error_t * -svn_fs_x__open_proto_rev_file(svn_fs_x__revision_file_t **file, - svn_fs_t *fs, - svn_fs_x__txn_id_t txn_id, - apr_pool_t* result_pool, - apr_pool_t *scratch_pool) +svn_fs_x__rev_file_open_proto_rev(svn_fs_x__revision_file_t **file, + svn_fs_t *fs, + svn_fs_x__txn_id_t txn_id, + apr_pool_t* result_pool, + apr_pool_t *scratch_pool) { apr_file_t *apr_file; SVN_ERR(svn_io_file_open(&apr_file, @@ -282,12 +353,12 @@ svn_fs_x__open_proto_rev_file(svn_fs_x__revision_file_t **file, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, result_pool)); - return svn_error_trace(svn_fs_x__wrap_temp_rev_file(file, fs, apr_file, + return svn_error_trace(svn_fs_x__rev_file_wrap_temp(file, fs, apr_file, result_pool)); } svn_error_t * -svn_fs_x__wrap_temp_rev_file(svn_fs_x__revision_file_t **file, +svn_fs_x__rev_file_wrap_temp(svn_fs_x__revision_file_t **file, svn_fs_t *fs, apr_file_t *temp_file, apr_pool_t *result_pool) @@ -300,17 +371,169 @@ svn_fs_x__wrap_temp_rev_file(svn_fs_x__revision_file_t **file, } svn_error_t * +svn_fs_x__rev_file_info(svn_fs_x__rev_file_info_t *info, + svn_fs_x__revision_file_t *file) +{ + SVN_ERR(auto_open(file)); + + *info = file->file_info; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_x__rev_file_name(const char **filename, + svn_fs_x__revision_file_t *file, + apr_pool_t *result_pool) +{ + SVN_ERR(auto_open(file)); + + return svn_error_trace(svn_io_file_name_get(filename, file->file, + result_pool)); +} + +svn_error_t * +svn_fs_x__rev_file_stream(svn_stream_t **stream, + svn_fs_x__revision_file_t *file) +{ + SVN_ERR(auto_open(file)); + + *stream = file->stream; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_x__rev_file_get(apr_file_t **apr_file, + svn_fs_x__revision_file_t *file) +{ + SVN_ERR(auto_open(file)); + + *apr_file = file->file; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_x__rev_file_l2p_index(svn_fs_x__packed_number_stream_t **stream, + svn_fs_x__revision_file_t *file) +{ + if (file->l2p_stream == NULL) + { + SVN_ERR(auto_read_footer(file)); + SVN_ERR(svn_fs_x__packed_stream_open(&file->l2p_stream, + file->file, + file->l2p_info.start, + file->l2p_info.end, + SVN_FS_X__L2P_STREAM_PREFIX, + (apr_size_t)file->block_size, + file->pool, + file->pool)); + } + + *stream = file->l2p_stream; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_x__rev_file_p2l_index(svn_fs_x__packed_number_stream_t **stream, + svn_fs_x__revision_file_t *file) +{ + if (file->p2l_stream== NULL) + { + SVN_ERR(auto_read_footer(file)); + SVN_ERR(svn_fs_x__packed_stream_open(&file->p2l_stream, + file->file, + file->p2l_info.start, + file->p2l_info.end, + SVN_FS_X__P2L_STREAM_PREFIX, + (apr_size_t)file->block_size, + file->pool, + file->pool)); + } + + *stream = file->p2l_stream; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_x__rev_file_l2p_info(svn_fs_x__index_info_t *info, + svn_fs_x__revision_file_t *file) +{ + SVN_ERR(auto_read_footer(file)); + *info = file->l2p_info; + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_x__rev_file_p2l_info(svn_fs_x__index_info_t *info, + svn_fs_x__revision_file_t *file) +{ + SVN_ERR(auto_read_footer(file)); + *info = file->p2l_info; + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_x__rev_file_data_size(svn_filesize_t *size, + svn_fs_x__revision_file_t *file) +{ + SVN_ERR(auto_read_footer(file)); + *size = file->l2p_info.start; + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_x__rev_file_seek(svn_fs_x__revision_file_t *file, + apr_off_t *buffer_start, + apr_off_t offset) +{ + SVN_ERR(auto_open(file)); + return svn_error_trace(svn_io_file_aligned_seek(file->file, + file->block_size, + buffer_start, offset, + file->pool)); +} + +svn_error_t * +svn_fs_x__rev_file_offset(apr_off_t *offset, + svn_fs_x__revision_file_t *file) +{ + SVN_ERR(auto_open(file)); + return svn_error_trace(svn_io_file_get_offset(offset, file->file, + file->pool)); +} + +svn_error_t * +svn_fs_x__rev_file_read(svn_fs_x__revision_file_t *file, + void *buf, + apr_size_t nbytes) +{ + SVN_ERR(auto_open(file)); + return svn_error_trace(svn_io_file_read_full2(file->file, buf, nbytes, + NULL, NULL, file->pool)); +} + +svn_error_t * svn_fs_x__close_revision_file(svn_fs_x__revision_file_t *file) { + /* Close sub-objects properly */ if (file->stream) SVN_ERR(svn_stream_close(file->stream)); if (file->file) SVN_ERR(svn_io_file_close(file->file, file->pool)); + /* Release the memory. */ + if (file->pool) + svn_pool_clear(file->pool); + + /* Reset pointers to objects previously allocated from FILE->POOL. */ file->file = NULL; file->stream = NULL; file->l2p_stream = NULL; file->p2l_stream = NULL; + /* Cause any index data getters to re-read the footer. */ + file->l2p_info.start = -1; return SVN_NO_ERROR; } |