Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.c Tue Oct 11 09:11:50 2016 @@ -203,6 +203,9 @@ struct svn_fs_x__batch_fsync_t /* Counts the number of completed fsync tasks. */ waitable_counter_t *counter; + + /* Perform fsyncs only if this flag has been set. */ + svn_boolean_t flush_to_disk; }; /* Data structures for concurrent fsync execution are only available if @@ -299,10 +302,12 @@ fsync_batch_cleanup(void *data) svn_error_t * svn_fs_x__batch_fsync_create(svn_fs_x__batch_fsync_t **result_p, + svn_boolean_t flush_to_disk, apr_pool_t *result_pool) { svn_fs_x__batch_fsync_t *result = apr_pcalloc(result_pool, sizeof(*result)); result->files = svn_hash__make(result_pool); + result->flush_to_disk = flush_to_disk; SVN_ERR(waitable_counter__create(&result->counter, result_pool)); apr_pool_cleanup_register(result_pool, result, fsync_batch_cleanup, @@ -493,33 +498,38 @@ svn_fs_x__batch_fsync_run(svn_fs_x__batc waitable_counter__reset(batch->counter)); /* Start the actual fsyncing process. */ - for (hi = apr_hash_first(scratch_pool, batch->files); - hi; - hi = apr_hash_next(hi)) + if (batch->flush_to_disk) { - to_sync_t *to_sync = apr_hash_this_val(hi); + for (hi = apr_hash_first(scratch_pool, batch->files); + hi; + hi = apr_hash_next(hi)) + { + to_sync_t *to_sync = apr_hash_this_val(hi); #if APR_HAS_THREADS - /* If there are multiple fsyncs to perform, run them in parallel. - * Otherwise, skip the thread-pool and synchronization overhead. */ - if (apr_hash_count(batch->files) > 1) - { - apr_status_t status = APR_SUCCESS; - status = apr_thread_pool_push(thread_pool, flush_task, to_sync, - 0, NULL); - if (status) - to_sync->result = svn_error_wrap_apr(status, _("Can't push task")); + /* If there are multiple fsyncs to perform, run them in parallel. + * Otherwise, skip the thread-pool and synchronization overhead. */ + if (apr_hash_count(batch->files) > 1) + { + apr_status_t status = APR_SUCCESS; + status = apr_thread_pool_push(thread_pool, flush_task, to_sync, + 0, NULL); + if (status) + to_sync->result = svn_error_wrap_apr(status, + _("Can't push task")); + else + tasks++; + } else - tasks++; - } - else #endif - { - to_sync->result = svn_error_trace(svn_io_file_flush_to_disk - (to_sync->file, to_sync->pool)); + { + to_sync->result = svn_error_trace(svn_io_file_flush_to_disk + (to_sync->file, + to_sync->pool)); + } } } @@ -534,7 +544,9 @@ svn_fs_x__batch_fsync_run(svn_fs_x__batc hi = apr_hash_next(hi)) { to_sync_t *to_sync = apr_hash_this_val(hi); - chain = svn_error_compose_create(chain, to_sync->result); + if (batch->flush_to_disk) + chain = svn_error_compose_create(chain, to_sync->result); + chain = svn_error_compose_create(chain, svn_io_file_close(to_sync->file, scratch_pool));
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.h (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/batch_fsync.h Tue Oct 11 09:11:50 2016 @@ -52,9 +52,12 @@ typedef struct svn_fs_x__batch_fsync_t s svn_error_t * svn_fs_x__batch_fsync_init(void); -/* Set *RESULT_P to a new batch fsync structure, allocated in RESULT_POOL. */ +/* Set *RESULT_P to a new batch fsync structure, allocated in RESULT_POOL. + * If FLUSH_TO_DISK is not set, the resulting struct will not actually use + * fsync. */ svn_error_t * svn_fs_x__batch_fsync_create(svn_fs_x__batch_fsync_t **result_p, + svn_boolean_t flush_to_disk, apr_pool_t *result_pool); /* Open the file at FILENAME for read and write access. Return it in *FILE Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.c Tue Oct 11 09:11:50 2016 @@ -55,6 +55,7 @@ block_read(void **result, svn_fs_t *fs, const svn_fs_x__id_t *id, svn_fs_x__revision_file_t *revision_file, + void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool); @@ -352,6 +353,7 @@ get_node_revision_body(svn_fs_x__noderev SVN_ERR(block_read((void **)noderev_p, fs, id, revision_file, + NULL, result_pool, scratch_pool)); SVN_ERR(svn_fs_x__close_revision_file(revision_file)); @@ -698,7 +700,7 @@ create_rep_state_body(rep_state_t **rep_ /* populate the cache if appropriate */ if (SVN_IS_VALID_REVNUM(revision)) { - SVN_ERR(block_read(NULL, fs, &rs->rep_id, rs->sfile->rfile, + SVN_ERR(block_read(NULL, fs, &rs->rep_id, rs->sfile->rfile, NULL, result_pool, scratch_pool)); SVN_ERR(svn_cache__set(ffd->rep_header_cache, &key, rh, scratch_pool)); @@ -1310,7 +1312,7 @@ read_delta_window(svn_txdelta_window_t * && svn_fs_x__is_revision(rs->rep_id.change_set) && rs->window_cache) { - SVN_ERR(block_read(NULL, rs->sfile->fs, &rs->rep_id, file, + SVN_ERR(block_read(NULL, rs->sfile->fs, &rs->rep_id, file, NULL, result_pool, scratch_pool)); /* reading the whole block probably also provided us with the @@ -1341,7 +1343,7 @@ read_delta_window(svn_txdelta_window_t * SVN_ERR(svn_fs_x__rev_file_get(&apr_file, file)); SVN_ERR(svn_txdelta_skip_svndiff_window(apr_file, rs->ver, iterpool)); rs->chunk_index++; - SVN_ERR(svn_fs_x__get_file_offset(&start_offset, apr_file, iterpool)); + SVN_ERR(svn_io_file_get_offset(&start_offset, apr_file, iterpool)); rs->current = start_offset - rs->start; if (rs->current >= rs->size) @@ -1405,7 +1407,8 @@ read_container_window(svn_stringbuf_t ** { SVN_ERR(auto_open_shared_file(rs->sfile)); SVN_ERR(block_read((void **)&extractor, fs, &rs->rep_id, - rs->sfile->rfile, result_pool, scratch_pool)); + rs->sfile->rfile, NULL, + result_pool, scratch_pool)); } SVN_ERR(svn_fs_x__extractor_drive(nwin, extractor, rs->current, size, @@ -2646,8 +2649,13 @@ svn_fs_x__rep_contents_dir(apr_array_hea SVN_ERR(get_dir_contents(dir, fs, noderev, result_pool, scratch_pool)); *entries_p = dir->entries; - /* Update the cache, if we are to use one. */ - SVN_ERR(svn_cache__set(cache, &key, dir, scratch_pool)); + /* Update the cache, if we are to use one. + * + * Don't even attempt to serialize very large directories; it would cause + * an unnecessary memory allocation peak. 100 bytes/entry is about right. + */ + if (svn_cache__is_cachable(cache, 100 * dir->entries->nelts)) + SVN_ERR(svn_cache__set(cache, &key, dir, scratch_pool)); return SVN_NO_ERROR; } @@ -2699,7 +2707,7 @@ svn_fs_x__rep_contents_dir_entry(svn_fs_ *hint = baton.hint; /* fetch data from disk if we did not find it in the cache */ - if (! found) + if (! found || baton.out_of_date) { svn_fs_x__dirent_t *entry; svn_fs_x__dirent_t *entry_copy = NULL; @@ -2709,8 +2717,12 @@ svn_fs_x__rep_contents_dir_entry(svn_fs_ SVN_ERR(get_dir_contents(&dir, fs, noderev, scratch_pool, scratch_pool)); - /* Update the cache, if we are to use one. */ - if (cache) + /* Update the cache, if we are to use one. + * + * Don't even attempt to serialize very large directories; it would + * cause an unnecessary memory allocation peak. 150 bytes / entry is + * about right. */ + if (cache && svn_cache__is_cachable(cache, 150 * dir.entries->nelts)) SVN_ERR(svn_cache__set(cache, &key, &dir, scratch_pool)); /* find desired entry and return a copy in POOL, if found */ @@ -2792,72 +2804,104 @@ svn_fs_x__get_proplist(apr_hash_t **prop return SVN_NO_ERROR; } +svn_error_t * +svn_fs_x__create_changes_context(svn_fs_x__changes_context_t **context, + svn_fs_t *fs, + svn_revnum_t rev, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_fs_x__changes_context_t *result = apr_pcalloc(result_pool, + sizeof(*result)); + result->fs = fs; + result->revision = rev; + + SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool)); + SVN_ERR(svn_fs_x__rev_file_init(&result->revision_file, fs, rev, + result_pool)); + *context = result; + return SVN_NO_ERROR; +} svn_error_t * svn_fs_x__get_changes(apr_array_header_t **changes, - svn_fs_t *fs, - svn_revnum_t rev, - apr_pool_t *result_pool) + svn_fs_x__changes_context_t *context, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - svn_fs_x__revision_file_t *revision_file; svn_boolean_t found; - svn_fs_x__data_t *ffd = fs->fsap_data; - apr_pool_t *scratch_pool = svn_pool_create(result_pool); + svn_fs_x__data_t *ffd = context->fs->fsap_data; svn_fs_x__id_t id; - id.change_set = svn_fs_x__change_set_by_rev(rev); + id.change_set = svn_fs_x__change_set_by_rev(context->revision); id.number = SVN_FS_X__ITEM_INDEX_CHANGES; - /* Provide revision file. */ - - SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool)); - SVN_ERR(svn_fs_x__rev_file_init(&revision_file, fs, rev, scratch_pool)); - /* try cache lookup first */ - if (svn_fs_x__is_packed_rev(fs, rev)) + if (svn_fs_x__is_packed_rev(context->fs, context->revision)) { apr_off_t offset; - apr_uint32_t sub_item; svn_fs_x__pair_cache_key_t key; + svn_fs_x__changes_get_list_baton_t baton; + baton.start = (int)context->next; + baton.eol = &context->eol; - SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, revision_file, + SVN_ERR(svn_fs_x__item_offset(&offset, &baton.sub_item, context->fs, + context->revision_file, &id, scratch_pool)); - key.revision = svn_fs_x__packed_base_rev(fs, rev); + key.revision = svn_fs_x__packed_base_rev(context->fs, + context->revision); key.second = offset; SVN_ERR(svn_cache__get_partial((void **)changes, &found, ffd->changes_container_cache, &key, svn_fs_x__changes_get_list_func, - &sub_item, result_pool)); + &baton, result_pool)); } else { - SVN_ERR(svn_cache__get((void **) changes, &found, ffd->changes_cache, - &rev, result_pool)); + svn_fs_x__changes_list_t *changes_list; + svn_fs_x__pair_cache_key_t key; + key.revision = context->revision; + key.second = context->next; + + SVN_ERR(svn_cache__get((void **)&changes_list, &found, + ffd->changes_cache, &key, result_pool)); + + if (found) + { + /* Where to look next - if there is more data. */ + context->eol = changes_list->eol; + context->next_offset = changes_list->end_offset; + + /* Return the block as a "proper" APR array. */ + (*changes) = apr_array_make(result_pool, 0, sizeof(void *)); + (*changes)->elts = (char *)changes_list->changes; + (*changes)->nelts = changes_list->count; + (*changes)->nalloc = changes_list->count; + } } if (!found) { /* 'block-read' will also provide us with the desired data */ - SVN_ERR(block_read((void **)changes, fs, &id, revision_file, + SVN_ERR(block_read((void **)changes, context->fs, &id, + context->revision_file, context, result_pool, scratch_pool)); - - SVN_ERR(svn_fs_x__close_revision_file(revision_file)); } - SVN_ERR(dgb__log_access(fs, &id, *changes, SVN_FS_X__ITEM_TYPE_CHANGES, - scratch_pool)); + context->next += (*changes)->nelts; + + SVN_ERR(dgb__log_access(context->fs, &id, *changes, + SVN_FS_X__ITEM_TYPE_CHANGES, scratch_pool)); - svn_pool_destroy(scratch_pool); return SVN_NO_ERROR; } /* Fetch the representation data (header, txdelta / plain windows) - * addressed by ENTRY->ITEM in FS and cache it if caches are enabled. - * Read the data from the already open FILE and the wrapping - * STREAM object. If MAX_OFFSET is not -1, don't read windows that start + * addressed by ENTRY->ITEM in FS and cache it under KEY. Read the data + * from REV_FILE. If MAX_OFFSET is not -1, don't read windows that start * at or beyond that offset. Use SCRATCH_POOL for temporary allocations. */ static svn_error_t * @@ -2887,27 +2931,28 @@ block_read_contents(svn_fs_t *fs, /* For the given REV_FILE in FS, in *STREAM return a stream covering the * item specified by ENTRY. Also, verify the item's content by low-level - * checksum. Allocate the result in POOL. + * checksum. Allocate the result in RESULT_POOL. */ static svn_error_t * read_item(svn_stream_t **stream, svn_fs_t *fs, svn_fs_x__revision_file_t *rev_file, svn_fs_x__p2l_entry_t* entry, - apr_pool_t *pool) + apr_pool_t *result_pool) { apr_uint32_t digest; svn_checksum_t *expected, *actual; apr_uint32_t plain_digest; + svn_stringbuf_t *text; /* Read item into string buffer. */ - svn_stringbuf_t *text = svn_stringbuf_create_ensure(entry->size, pool); + text = svn_stringbuf_create_ensure(entry->size, result_pool); text->len = entry->size; text->data[text->len] = 0; SVN_ERR(svn_fs_x__rev_file_read(rev_file, text->data, text->len)); /* Return (construct, calculate) stream and checksum. */ - *stream = svn_stream_from_stringbuf(text, pool); + *stream = svn_stream_from_stringbuf(text, result_pool); digest = svn__fnv1a_32x4(text->data, text->len); /* Checksums will match most of the time. */ @@ -2918,79 +2963,114 @@ read_item(svn_stream_t **stream, * nice error messages. */ plain_digest = htonl(entry->fnv1_checksum); expected = svn_checksum__from_digest_fnv1a_32x4( - (const unsigned char *)&plain_digest, pool); + (const unsigned char *)&plain_digest, result_pool); plain_digest = htonl(digest); actual = svn_checksum__from_digest_fnv1a_32x4( - (const unsigned char *)&plain_digest, pool); + (const unsigned char *)&plain_digest, result_pool); /* Construct the full error message with all the info we have. */ - return svn_checksum_mismatch_err(expected, actual, pool, + return svn_checksum_mismatch_err(expected, actual, result_pool, _("Low-level checksum mismatch while reading\n" "%s bytes of meta data at offset %s "), - apr_psprintf(pool, "%" APR_OFF_T_FMT, entry->size), - apr_psprintf(pool, "%" APR_OFF_T_FMT, entry->offset)); + apr_psprintf(result_pool, "%" APR_OFF_T_FMT, entry->size), + apr_psprintf(result_pool, "%" APR_OFF_T_FMT, entry->offset)); } -/* Read all txdelta / plain windows following REP_HEADER in FS as described - * by ENTRY. Read the data from the already open FILE and the wrapping - * STREAM object. If MAX_OFFSET is not -1, don't read windows that start - * at or beyond that offset. Use SCRATCH_POOL for temporary allocations. - * If caching is not enabled, this is a no-op. +/* If not already cached or if MUST_READ is set, read the changed paths + * list addressed by ENTRY in FS and retúrn it in *CHANGES. Cache the + * result if caching is enabled. Read the data from REV_FILE. Trim the + * data in *CHANGES to the range given by CONTEXT. Allocate *CHANGES in + * RESUSLT_POOL and allocate temporaries in SCRATCH_POOL. */ static svn_error_t * block_read_changes(apr_array_header_t **changes, svn_fs_t *fs, svn_fs_x__revision_file_t *rev_file, svn_fs_x__p2l_entry_t* entry, + svn_fs_x__changes_context_t *context, svn_boolean_t must_read, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_fs_x__data_t *ffd = fs->fsap_data; svn_stream_t *stream; - svn_revnum_t revision = svn_fs_x__get_revnum(entry->items[0].change_set); - apr_size_t estimated_size; + svn_fs_x__pair_cache_key_t key; + svn_fs_x__changes_list_t changes_list; + + /* If we don't have to return any data, just read and cache the first + block. This means we won't cache the remaining blocks from longer + lists right away but only if they are actually needed. */ + apr_size_t next = must_read ? context->next : 0; + apr_size_t next_offset = must_read ? context->next_offset : 0; /* we don't support containers, yet */ SVN_ERR_ASSERT(entry->item_count == 1); + /* The item to read / write. */ + key.revision = svn_fs_x__get_revnum(entry->items[0].change_set); + key.second = next; + /* already in cache? */ if (!must_read) { svn_boolean_t is_cached = FALSE; - SVN_ERR(svn_cache__has_key(&is_cached, ffd->changes_cache, &revision, + SVN_ERR(svn_cache__has_key(&is_cached, ffd->changes_cache, &key, scratch_pool)); if (is_cached) return SVN_NO_ERROR; } - SVN_ERR(read_item(&stream, fs, rev_file, entry, scratch_pool)); + /* Verify the whole list only once. We don't use the STREAM any further. */ + if (!must_read || next == 0) + SVN_ERR(read_item(&stream, fs, rev_file, entry, scratch_pool)); + + /* Seek to the block to read within the changes list. */ + SVN_ERR(svn_fs_x__rev_file_seek(rev_file, NULL, + entry->offset + next_offset)); + SVN_ERR(svn_fs_x__rev_file_stream(&stream, rev_file)); /* read changes from revision file */ - SVN_ERR(svn_fs_x__read_changes(changes, stream, result_pool, scratch_pool)); + SVN_ERR(svn_fs_x__read_changes(changes, stream, SVN_FS_X__CHANGES_BLOCK_SIZE, + result_pool, scratch_pool)); + + SVN_ERR(svn_fs_x__rev_file_offset(&changes_list.end_offset, rev_file)); + changes_list.end_offset -= entry->offset; + changes_list.start_offset = next_offset; + changes_list.count = (*changes)->nelts; + changes_list.changes = (svn_fs_x__change_t **)(*changes)->elts; + changes_list.eol = (changes_list.count < SVN_FS_X__CHANGES_BLOCK_SIZE) + || (changes_list.end_offset + 1 >= entry->size); /* cache for future reference */ - /* Guesstimate for the size of the in-cache representation. */ - estimated_size = (apr_size_t)250 * (*changes)->nelts; + SVN_ERR(svn_cache__set(ffd->changes_cache, &key, &changes_list, + scratch_pool)); - /* Don't even serialize data that probably won't fit into the - * cache. This often implies that either CHANGES is very - * large, memory is scarce or both. Having a huge temporary - * copy would not be a good thing in either case. */ - if (svn_cache__is_cachable(ffd->changes_cache, estimated_size)) - SVN_ERR(svn_cache__set(ffd->changes_cache, &revision, *changes, - scratch_pool)); + /* Trim the result: + * Remove the entries that already been reported. */ + if (must_read) + { + context->next_offset = changes_list.end_offset; + context->eol = changes_list.eol; + } return SVN_NO_ERROR; } +/* If not already cached or if MUST_READ is set, read the changed paths + * list container addressed by ENTRY in FS. Return the changes list + * identified by SUB_ITEM in *CHANGES, using CONTEXT to select a sub-range + * within that list. Read the data from REV_FILE and cache the result. + * + * Allocate *CHANGES in RESUSLT_POOL and everything else in SCRATCH_POOL. + */ static svn_error_t * block_read_changes_container(apr_array_header_t **changes, svn_fs_t *fs, svn_fs_x__revision_file_t *rev_file, svn_fs_x__p2l_entry_t* entry, apr_uint32_t sub_item, + svn_fs_x__changes_context_t *context, svn_boolean_t must_read, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -3025,13 +3105,19 @@ block_read_changes_container(apr_array_h if (must_read) SVN_ERR(svn_fs_x__changes_get_list(changes, container, sub_item, - result_pool)); + context, result_pool)); SVN_ERR(svn_cache__set(ffd->changes_container_cache, &key, container, scratch_pool)); return SVN_NO_ERROR; } +/* If not already cached or if MUST_READ is set, read the node revision + * addressed by ENTRY in FS and return it in *NODEREV_P. Cache the + * result under KEY if caching is enabled. Read the data from REV_FILE. + * Allocate *NODEREV_P in RESUSLT_POOL and allocate temporaries in + * SCRATCH_POOL. + */ static svn_error_t * block_read_noderev(svn_fs_x__noderev_t **noderev_p, svn_fs_t *fs, @@ -3070,6 +3156,12 @@ block_read_noderev(svn_fs_x__noderev_t * return SVN_NO_ERROR; } +/* If not already cached or if MUST_READ is set, read the node revision + * container addressed by ENTRY in FS. Return the item identified by + * SUB_ITEM in *NODEREV_P. Read the data from REV_FILE and cache it. + * Allocate *NODEREV_P in RESUSLT_POOL and allocate temporaries in + * SCRATCH_POOL. + */ static svn_error_t * block_read_noderevs_container(svn_fs_x__noderev_t **noderev_p, svn_fs_t *fs, @@ -3116,6 +3208,12 @@ block_read_noderevs_container(svn_fs_x__ return SVN_NO_ERROR; } +/* If not already cached or if MUST_READ is set, read the representation + * container addressed by ENTRY in FS. Return an extractor object for the + * item identified by SUB_ITEM in *EXTRACTOR. Read the data from REV_FILE + * and cache it. Allocate *EXTRACTOR in RESUSLT_POOL and all temporaries + * in SCRATCH_POOL. + */ static svn_error_t * block_read_reps_container(svn_fs_x__rep_extractor_t **extractor, svn_fs_t *fs, @@ -3163,11 +3261,24 @@ block_read_reps_container(svn_fs_x__rep_ return SVN_NO_ERROR; } +/* Read the whole (e.g. 64kB) block containing the item identified by ID in + * FS and put all data into cache. If necessary and depending on heuristics, + * neighboring blocks may also get read. The data is being read from + * already open REVISION_FILE, which must be the correct rev / pack file + * w.r.t. ID->CHANGE_SET. + * + * For noderevs and changed path lists, the item fetched can be allocated + * RESULT_POOL and returned in *RESULT. Otherwise, RESULT must be NULL. + * The BATON is passed along to the extractor sub-functions and will be + * used only when constructing the *RESULT. SCRATCH_POOL will be used for + * all temporary allocations. + */ static svn_error_t * block_read(void **result, svn_fs_t *fs, const svn_fs_x__id_t *id, svn_fs_x__revision_file_t *revision_file, + void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -3258,7 +3369,7 @@ block_read(void **result, case SVN_FS_X__ITEM_TYPE_CHANGES: SVN_ERR(block_read_changes((apr_array_header_t **)&item, fs, revision_file, - entry, is_result, + entry, baton, is_result, pool, iterpool)); break; @@ -3267,7 +3378,8 @@ block_read(void **result, ((apr_array_header_t **)&item, fs, revision_file, entry, wanted_sub_item, - is_result, pool, iterpool)); + baton, is_result, + pool, iterpool)); break; case SVN_FS_X__ITEM_TYPE_NODEREVS_CONT: Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.h (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/cached_data.h Tue Oct 11 09:11:50 2016 @@ -168,13 +168,24 @@ svn_fs_x__get_proplist(apr_hash_t **prop apr_pool_t *result_pool, apr_pool_t *scratch_pool); -/* Fetch the list of change in revision REV in FS and return it in *CHANGES. - * Allocate the result in POOL. +/* Create a changes retrieval context object in *RESULT_POOL and return it + * in *CONTEXT. It will allow svn_fs_x__get_changes to fetch consecutive + * blocks (one per invocation) from REV's changed paths list in FS. + * Use SCRATCH_POOL for temporary allocations. */ +svn_error_t * +svn_fs_x__create_changes_context(svn_fs_x__changes_context_t **context, + svn_fs_t *fs, + svn_revnum_t rev, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Fetch the block of changes from the CONTEXT and return it in *CHANGES. + * Allocate the result in RESULT_POOL and use SCRATCH_POOL for temporaries. */ svn_error_t * svn_fs_x__get_changes(apr_array_header_t **changes, - svn_fs_t *fs, - svn_revnum_t rev, - apr_pool_t *pool); + svn_fs_x__changes_context_t *context, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); #endif Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/caching.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/caching.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/caching.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/caching.c Tue Oct 11 09:11:50 2016 @@ -69,9 +69,9 @@ normalize_key_part(const char *original, return normalized->data; } -/* *CACHE_TXDELTAS, *CACHE_FULLTEXTS and *CACHE_REVPROPS flags will be set - according to FS->CONFIG. *CACHE_NAMESPACE receives the cache prefix - to use. +/* *CACHE_TXDELTAS, *CACHE_FULLTEXTS, *CACHE_REVPROPS and *CACHE_NODEPROPS + flags will be set according to FS->CONFIG. *CACHE_NAMESPACE receives + the cache prefix to use. Allocate CACHE_NAMESPACE in RESULT_POOL. */ static svn_error_t * @@ -79,6 +79,7 @@ read_config(const char **cache_namespace svn_boolean_t *cache_txdeltas, svn_boolean_t *cache_fulltexts, svn_boolean_t *cache_revprops, + svn_boolean_t *cache_nodeprops, svn_fs_t *fs, apr_pool_t *result_pool) { @@ -137,6 +138,15 @@ read_config(const char **cache_namespace else *cache_revprops = TRUE; + /* by default, cache nodeprops: this will match pre-1.10 + * behavior where node properties caching was controlled + * by SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS configuration option. + */ + *cache_nodeprops + = svn_hash__get_bool(fs->config, + SVN_FS_CONFIG_FSFS_CACHE_NODEPROPS, + TRUE); + return SVN_NO_ERROR; } @@ -380,6 +390,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs svn_boolean_t cache_txdeltas; svn_boolean_t cache_fulltexts; svn_boolean_t cache_revprops; + svn_boolean_t cache_nodeprops; const char *cache_namespace; svn_boolean_t has_namespace; @@ -388,6 +399,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs &cache_txdeltas, &cache_fulltexts, &cache_revprops, + &cache_nodeprops, fs, scratch_pool)); @@ -430,7 +442,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs svn_fs_x__deserialize_dir_entries, sizeof(svn_fs_x__id_t), apr_pstrcat(scratch_pool, prefix, "DIR", SVN_VA_NULL), - SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, + SVN_CACHE__MEMBUFFER_HIGH_PRIORITY, has_namespace, fs, no_handler, FALSE, @@ -475,7 +487,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs 1, 8, /* 1k / entry; 8 entries total, rarely used */ svn_fs_x__serialize_changes, svn_fs_x__deserialize_changes, - sizeof(svn_revnum_t), + sizeof(svn_fs_x__pair_cache_key_t), apr_pstrcat(scratch_pool, prefix, "CHANGES", SVN_VA_NULL), 0, @@ -512,7 +524,7 @@ svn_fs_x__initialize_caches(svn_fs_t *fs SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, has_namespace, fs, - no_handler, !cache_fulltexts, + no_handler, !cache_nodeprops, fs->pool, scratch_pool)); /* if enabled, cache revprops */ Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/changes.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/changes.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/changes.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/changes.c Tue Oct 11 09:11:50 2016 @@ -21,6 +21,7 @@ */ #include "svn_private_config.h" +#include "svn_sorts.h" #include "private/svn_packed_data.h" @@ -37,8 +38,8 @@ /* the change contains a property modification */ #define CHANGE_PROP_MOD 0x00002 -/* the last part (rev_id) of node revision ID is a transaction ID */ -#define CHANGE_TXN_NODE 0x00004 +/* the change contains a mergeinfo modification */ +#define CHANGE_MERGEINFO_MOD 0x00004 /* (flags & CHANGE_NODE_MASK) >> CHANGE_NODE_SHIFT extracts the node type */ #define CHANGE_NODE_SHIFT 0x00003 @@ -52,16 +53,13 @@ /* (flags & CHANGE_KIND_MASK) >> CHANGE_KIND_SHIFT extracts the change type */ #define CHANGE_KIND_SHIFT 0x00005 -#define CHANGE_KIND_MASK 0x000E0 +#define CHANGE_KIND_MASK 0x00060 /* node types according to svn_fs_path_change_kind_t */ #define CHANGE_KIND_MODIFY 0x00000 #define CHANGE_KIND_ADD 0x00020 #define CHANGE_KIND_DELETE 0x00040 #define CHANGE_KIND_REPLACE 0x00060 -#define CHANGE_KIND_RESET 0x00080 -#define CHANGE_KIND_MOVE 0x000A0 -#define CHANGE_KIND_MOVEREPLACE 0x000C0 /* Our internal representation of a change */ typedef struct binary_change_t @@ -77,10 +75,6 @@ typedef struct binary_change_t svn_revnum_t copyfrom_rev; apr_size_t copyfrom_path; - /* Relevant parts of the node revision ID of the change. - * Empty, if REV_ID is not "used". */ - svn_fs_x__id_t noderev_id; - } binary_change_t; /* The actual container object. Change lists are concatenated into CHANGES @@ -138,20 +132,16 @@ append_change(svn_fs_x__changes_t *chang svn_fs_x__change_t *change) { binary_change_t binary_change = { 0 }; - svn_boolean_t is_txn_id; /* CHANGE must be sufficiently complete */ SVN_ERR_ASSERT(change); SVN_ERR_ASSERT(change->path.data); - /* Relevant parts of the revision ID of the change. */ - binary_change.noderev_id = change->noderev_id; - /* define the kind of change and what specific information is present */ - is_txn_id = svn_fs_x__is_txn(binary_change.noderev_id.change_set); binary_change.flags = (change->text_mod ? CHANGE_TEXT_MOD : 0) | (change->prop_mod ? CHANGE_PROP_MOD : 0) - | (is_txn_id ? CHANGE_TXN_NODE : 0) + | (change->mergeinfo_mod == svn_tristate_true + ? CHANGE_MERGEINFO_MOD : 0) | ((int)change->change_kind << CHANGE_KIND_SHIFT) | ((int)change->node_kind << CHANGE_NODE_SHIFT); @@ -222,8 +212,11 @@ svn_error_t * svn_fs_x__changes_get_list(apr_array_header_t **list, const svn_fs_x__changes_t *changes, apr_size_t idx, + svn_fs_x__changes_context_t *context, apr_pool_t *result_pool) { + int list_first; + int list_last; int first; int last; int i; @@ -242,8 +235,16 @@ svn_fs_x__changes_get_list(apr_array_hea idx, changes->offsets->nelts - 1); /* range of changes to return */ - first = APR_ARRAY_IDX(changes->offsets, (int)idx, int); - last = APR_ARRAY_IDX(changes->offsets, (int)idx + 1, int); + list_first = APR_ARRAY_IDX(changes->offsets, (int)idx, int); + list_last = APR_ARRAY_IDX(changes->offsets, (int)idx + 1, int); + + /* Restrict it to the sub-range requested by the caller. + * Clip the range to never exceed the list's content. */ + first = MIN(context->next + list_first, list_last); + last = MIN(first + SVN_FS_X__CHANGES_BLOCK_SIZE, list_last); + + /* Indicate to the caller whether the end of the list has been reached. */ + context->eol = last == list_last; /* construct result */ *list = apr_array_make(result_pool, last - first, @@ -260,13 +261,13 @@ svn_fs_x__changes_get_list(apr_array_hea &change->path.len, result_pool); - if (binary_change->noderev_id.change_set != SVN_FS_X__INVALID_CHANGE_SET) - change->noderev_id = binary_change->noderev_id; - change->change_kind = (svn_fs_path_change_kind_t) ((binary_change->flags & CHANGE_KIND_MASK) >> CHANGE_KIND_SHIFT); change->text_mod = (binary_change->flags & CHANGE_TEXT_MOD) != 0; change->prop_mod = (binary_change->flags & CHANGE_PROP_MOD) != 0; + change->mergeinfo_mod = (binary_change->flags & CHANGE_MERGEINFO_MOD) + ? svn_tristate_true + : svn_tristate_false; change->node_kind = (svn_node_kind_t) ((binary_change->flags & CHANGE_NODE_MASK) >> CHANGE_NODE_SHIFT); @@ -312,8 +313,6 @@ svn_fs_x__write_changes_container(svn_st svn_packed__create_int_substream(changes_stream, TRUE, FALSE); svn_packed__create_int_substream(changes_stream, TRUE, TRUE); svn_packed__create_int_substream(changes_stream, TRUE, FALSE); - svn_packed__create_int_substream(changes_stream, TRUE, TRUE); - svn_packed__create_int_substream(changes_stream, TRUE, FALSE); /* serialize offsets array */ for (i = 0; i < changes->offsets->nelts; ++i) @@ -331,9 +330,6 @@ svn_fs_x__write_changes_container(svn_st svn_packed__add_int(changes_stream, change->copyfrom_rev); svn_packed__add_uint(changes_stream, change->copyfrom_path); - - svn_packed__add_int(changes_stream, change->noderev_id.change_set); - svn_packed__add_uint(changes_stream, change->noderev_id.number); } /* write to disk */ @@ -388,9 +384,6 @@ svn_fs_x__read_changes_container(svn_fs_ change.copyfrom_rev = (svn_revnum_t)svn_packed__get_int(changes_stream); change.copyfrom_path = (apr_size_t)svn_packed__get_uint(changes_stream); - change.noderev_id.change_set = svn_packed__get_int(changes_stream); - change.noderev_id.number = svn_packed__get_uint(changes_stream); - APR_ARRAY_PUSH(changes->changes, binary_change_t) = change; } @@ -465,7 +458,8 @@ svn_fs_x__changes_get_list_func(void **o int i; apr_array_header_t *list; - apr_uint32_t idx = *(apr_uint32_t *)baton; + svn_fs_x__changes_get_list_baton_t *b = baton; + apr_uint32_t idx = b->sub_item; const svn_fs_x__changes_t *container = data; /* resolve all the sub-container pointers we need */ @@ -496,6 +490,12 @@ svn_fs_x__changes_get_list_func(void **o first = offsets[idx]; last = offsets[idx+1]; + /* Restrict range to the block requested by the BATON. + * Tell the caller whether we reached the end of the list. */ + first = MIN(first + b->start, last); + last = MIN(first + SVN_FS_X__CHANGES_BLOCK_SIZE, last); + *b->eol = last == offsets[idx+1]; + /* construct result */ list = apr_array_make(pool, last - first, sizeof(svn_fs_x__change_t*)); @@ -509,8 +509,6 @@ svn_fs_x__changes_get_list_func(void **o = svn_fs_x__string_table_get_func(paths, binary_change->path, &change->path.len, pool); - change->noderev_id = binary_change->noderev_id; - change->change_kind = (svn_fs_path_change_kind_t) ((binary_change->flags & CHANGE_KIND_MASK) >> CHANGE_KIND_SHIFT); change->text_mod = (binary_change->flags & CHANGE_TEXT_MOD) != 0; Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/changes.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/changes.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/changes.h (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/changes.h Tue Oct 11 09:11:50 2016 @@ -71,13 +71,15 @@ svn_fs_x__changes_estimate_size(const sv /* Read changes containers. */ -/* From CHANGES, extract the change list with the given IDX. Allocate - * the result in POOL and return it in *LIST. +/* From CHANGES, access the change list with the given IDX and extract the + * next entries according to CONTEXT. Allocate the result in RESULT_POOL + * and return it in *LIST. */ svn_error_t * svn_fs_x__changes_get_list(apr_array_header_t **list, const svn_fs_x__changes_t *changes, apr_size_t idx, + svn_fs_x__changes_context_t *context, apr_pool_t *result_pool); /* I/O interface. */ @@ -116,11 +118,25 @@ svn_fs_x__deserialize_changes_container( apr_size_t data_len, apr_pool_t *result_pool); +/* Baton type to be used with svn_fs_x__changes_get_list_func. */ +typedef struct svn_fs_x__changes_get_list_baton_t +{ + /* Sub-item to query */ + apr_uint32_t sub_item; + + /* Deliver data starting from this index within the changes list. */ + int start; + + /* To be set by svn_fs_x__changes_get_list_func: + Did we deliver the last change in that list? */ + svn_boolean_t *eol; +} svn_fs_x__changes_get_list_baton_t; + /* Implements svn_cache__partial_getter_func_t for svn_fs_x__changes_t, * setting *OUT to the change list (apr_array_header_t *) selected by - * the apr_uint32_t index passed in as *BATON. This function is similar - * to svn_fs_x__changes_get_list but operates on the cache serialized - * representation of the container. + * the svn_fs_x__changes_get_list_baton_t passed in as *BATON. This + * function is similar to svn_fs_x__changes_get_list but operates on + * the cache serialized representation of the container. */ svn_error_t * svn_fs_x__changes_get_list_func(void **out, Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c Tue Oct 11 09:11:50 2016 @@ -322,6 +322,7 @@ initialize_fs_struct(svn_fs_t *fs) { svn_fs_x__data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd)); ffd->revprop_generation = -1; + ffd->flush_to_disk = TRUE; fs->vtable = &fs_vtable; fs->fsap_data = ffd; Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/fs.h (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs.h Tue Oct 11 09:11:50 2016 @@ -37,7 +37,7 @@ #include "private/svn_sqlite.h" #include "private/svn_mutex.h" -#include "id.h" +#include "rev_file.h" #ifdef __cplusplus extern "C" { @@ -137,6 +137,11 @@ extern "C" { #define SVN_FS_X__USE_LOCK_MUTEX 0 #endif +/* Maximum number of changes we deliver per request when listing the + changed paths for a given revision. Anything > 0 will do. + At 100..300 bytes per entry, this limits the allocation to ~30kB. */ +#define SVN_FS_X__CHANGES_BLOCK_SIZE 100 + /* Private FSX-specific data shared between all svn_txn_t objects that relate to a particular transaction in a filesystem (as identified by transaction id and filesystem UUID). Objects of this type are @@ -319,8 +324,8 @@ typedef struct svn_fs_x__data_t the key is a (pack file revision, file offset) pair */ svn_cache__t *noderevs_container_cache; - /* Cache for change lists as APR arrays of svn_fs_x__change_t * objects; - the key is the revision */ + /* Cache for change lists n blocks as svn_fs_x__changes_list_t * objects; + the key is the (revision, first-element-in-block) pair. */ svn_cache__t *changes_cache; /* Cache for change_list_t containers; @@ -398,6 +403,9 @@ typedef struct svn_fs_x__data_t or dump / load cycles). */ const char *instance_id; + /* Ensure that all filesystem changes are written to disk. */ + svn_boolean_t flush_to_disk; + /* Pointer to svn_fs_open. */ svn_error_t *(*svn_fs_open_)(svn_fs_t **, const char *, apr_hash_t *, apr_pool_t *, apr_pool_t *); @@ -481,7 +489,8 @@ typedef struct svn_fs_x__noderev_t /* node kind */ svn_node_kind_t kind; - /* number of predecessors this node revision has (recursively). */ + /* Number of predecessors this node revision has (recursively). + A difference from the BDB backend is that it cannot be -1. */ int predecessor_count; /* representation key for this node's properties. may be NULL if @@ -521,29 +530,31 @@ typedef struct svn_fs_x__dirent_t /*** Change ***/ -typedef struct svn_fs_x__change_t +typedef svn_fs_path_change3_t svn_fs_x__change_t; + +/*** Context for reading changed paths lists iteratively. */ +typedef struct svn_fs_x__changes_context_t { - /* Path of the change. */ - svn_string_t path; + /* Repository to fetch from. */ + svn_fs_t *fs; - /* node revision id of changed path */ - svn_fs_x__id_t noderev_id; + /* Revision that we read from. */ + svn_revnum_t revision; - /* See svn_fs_path_change2_t for a description for the remaining elements. - */ - svn_fs_path_change_kind_t change_kind; - - svn_boolean_t text_mod; - svn_boolean_t prop_mod; - svn_node_kind_t node_kind; + /* Revision file object to use when needed. */ + svn_fs_x__revision_file_t *revision_file; - svn_boolean_t copyfrom_known; - svn_revnum_t copyfrom_rev; - const char *copyfrom_path; + /* Index of the next change to fetch. */ + apr_size_t next; + + /* Offset, within the changed paths list on disk, of the next change to + fetch. */ + apr_off_t next_offset; - svn_tristate_t mergeinfo_mod; -} svn_fs_x__change_t; + /* Has the end of the list been reached? */ + svn_boolean_t eol; +} svn_fs_x__changes_context_t; /*** Directory (only used at the cache interface) ***/ typedef struct svn_fs_x__dir_data_t Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.c Tue Oct 11 09:11:50 2016 @@ -201,7 +201,7 @@ svn_fs_x__write_format(svn_fs_t *fs, { SVN_ERR(svn_io_write_atomic2(path, sb->data, sb->len, NULL /* copy_perms_path */, - TRUE, scratch_pool)); + ffd->flush_to_disk, scratch_pool)); } /* And set the perms to make it read only */ @@ -535,6 +535,20 @@ write_config(svn_fs_t *fs, fsx_conf_contents, scratch_pool); } +/* Read / Evaluate the global configuration in FS->CONFIG to set up + * parameters in FS. */ +static svn_error_t * +read_global_config(svn_fs_t *fs) +{ + svn_fs_x__data_t *ffd = fs->fsap_data; + + ffd->flush_to_disk = !svn_hash__get_bool(fs->config, + SVN_FS_CONFIG_NO_FLUSH_TO_DISK, + FALSE); + + return SVN_NO_ERROR; +} + /* Read FS's UUID file and store the data in the FS struct. */ static svn_error_t * read_uuid(svn_fs_t *fs, @@ -603,6 +617,9 @@ svn_fs_x__open(svn_fs_t *fs, /* Read the configuration file. */ SVN_ERR(read_config(ffd, fs->path, fs->pool, scratch_pool)); + /* Global configuration options. */ + SVN_ERR(read_global_config(fs)); + ffd->youngest_rev_cache = 0; return SVN_NO_ERROR; @@ -860,8 +877,6 @@ write_revision_zero(svn_fs_t *fs, const char *path_revision_zero = svn_fs_x__path_rev(fs, 0, scratch_pool); apr_hash_t *proplist; svn_string_t date; - svn_stream_t *stream; - svn_stringbuf_t *revprops; apr_array_header_t *index_entries; svn_fs_x__p2l_entry_t *entry; @@ -934,15 +949,13 @@ write_revision_zero(svn_fs_t *fs, proplist = apr_hash_make(scratch_pool); svn_hash_sets(proplist, SVN_PROP_REVISION_DATE, &date); - revprops = svn_stringbuf_create_empty(scratch_pool); - stream = svn_stream_from_stringbuf(revprops, scratch_pool); - SVN_ERR(svn_fs_x__write_properties(stream, proplist, scratch_pool)); - SVN_ERR(svn_stream_close(stream)); - - SVN_ERR(svn_io_file_create_bytes(svn_fs_x__path_revprops(fs, 0, - scratch_pool), - revprops->data, revprops->len, - scratch_pool)); + SVN_ERR(svn_io_file_open(&apr_file, + svn_fs_x__path_revprops(fs, 0, scratch_pool), + APR_WRITE | APR_CREATE, APR_OS_DEFAULT, + scratch_pool)); + SVN_ERR(svn_fs_x__write_non_packed_revprops(apr_file, proplist, + scratch_pool)); + SVN_ERR(svn_io_file_close(apr_file, scratch_pool)); return SVN_NO_ERROR; } @@ -990,6 +1003,9 @@ svn_fs_x__create_file_tree(svn_fs_t *fs, SVN_ERR(write_config(fs, scratch_pool)); SVN_ERR(read_config(ffd, fs->path, fs->pool, scratch_pool)); + /* Global configuration options. */ + SVN_ERR(read_global_config(fs)); + /* Add revision 0. */ SVN_ERR(write_revision_zero(fs, scratch_pool)); @@ -1100,7 +1116,7 @@ svn_fs_x__set_uuid(svn_fs_t *fs, SVN_ERR(svn_io_write_atomic2(uuid_path, contents->data, contents->len, /* perms */ svn_fs_x__path_current(fs, scratch_pool), - TRUE, scratch_pool)); + ffd->flush_to_disk, scratch_pool)); } fs->uuid = apr_pstrdup(fs->pool, uuid); Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.c Tue Oct 11 09:11:50 2016 @@ -555,7 +555,7 @@ typedef struct hotcopy_body_baton_t { * An incremental hotcopy copies only changed or new files to the destination, * and removes files from the destination no longer present in the source. * While the incremental hotcopy is running, readers should still be able - * to access the destintation repository without error and should not see + * to access the destination repository without error and should not see * revisions currently in progress of being copied. Readers are able to see * new fully copied revisions even if the entire incremental hotcopy procedure * has not yet completed. Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/index.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/index.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/index.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/index.c Tue Oct 11 09:11:50 2016 @@ -57,7 +57,7 @@ const apr_uint64_t off_t_max = (sizeof(a : APR_INT32_MAX; /* We store P2L proto-index entries as 6 values, 64 bits each on disk. - * See also svn_fs_fs__p2l_proto_index_add_entry(). + * See also svn_fs_x__p2l_proto_index_add_entry(). */ #define P2L_PROTO_INDEX_ENTRY_SIZE (6 * sizeof(apr_uint64_t)) @@ -231,7 +231,7 @@ stream_error_create(svn_fs_x__packed_num apr_off_t offset; SVN_ERR(svn_io_file_name_get(&file_name, stream->file, stream->pool)); - SVN_ERR(svn_fs_x__get_file_offset(&offset, stream->file, stream->pool)); + SVN_ERR(svn_io_file_get_offset(&offset, stream->file, stream->pool)); return svn_error_createf(err, NULL, message, file_name, apr_psprintf(stream->pool, @@ -3166,7 +3166,7 @@ compare_p2l_entry_offsets(const void *lh } /* Cached data extraction utility. DATA is a P2L index page, e.g. an APR - * array of svn_fs_fs__p2l_entry_t elements. Return the entry for the item, + * array of svn_fs_x__p2l_entry_t elements. Return the entry for the item, * allocated in RESULT_POOL, starting at OFFSET or NULL if that's not an * the start offset of any item. Use SCRATCH_POOL for temporary allocations. */ Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/index.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/index.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/index.h (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/index.h Tue Oct 11 09:11:50 2016 @@ -206,7 +206,7 @@ svn_fs_x__p2l_index_append(svn_checksum_ /* Use the phys-to-log mapping files in FS to build a list of entries * that (at least partly) overlap with the range given by BLOCK_START * offset and BLOCK_SIZE in the rep / pack file containing REVISION. - * Return the array in *ENTRIES with svn_fs_fs__p2l_entry_t as elements, + * Return the array in *ENTRIES with svn_fs_x__p2l_entry_t as elements, * allocated in RESULT_POOL. REV_FILE determines whether to access single * rev or pack file data. If that is not available anymore (neither in * cache nor on disk), return an error. Use SCRATCH_POOL for temporary @@ -309,7 +309,7 @@ svn_fs_x__p2l_get_max_offset(apr_off_t * /* For FS, create a new L2P auto-deleting proto index file in POOL and return * its name in *PROTONAME. All entries to write are given in ENTRIES and - * entries are of type svn_fs_fs__p2l_entry_t* (sic!). The ENTRIES array + * entries are of type svn_fs_x__p2l_entry_t* (sic!). The ENTRIES array * will be reordered. Give the proto index file the lifetime of RESULT_POOL * and use SCRATCH_POOL for temporary allocations. */ @@ -322,7 +322,7 @@ svn_fs_x__l2p_index_from_p2l_entries(con /* For FS, create a new P2L auto-deleting proto index file in POOL and return * its name in *PROTONAME. All entries to write are given in ENTRIES and - * of type svn_fs_fs__p2l_entry_t*. The FVN1 checksums are not taken from + * of type svn_fs_x__p2l_entry_t*. The FVN1 checksums are not taken from * ENTRIES but are begin calculated from the current contents of REV_FILE * as we go. Give the proto index file the lifetime of RESULT_POOL and use * SCRATCH_POOL for temporary allocations. Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/lock.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/lock.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/lock.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/lock.c Tue Oct 11 09:11:50 2016 @@ -937,7 +937,7 @@ lock_body(void *baton, lb->result_pool)); /* The INFO->PATH is already allocated in LB->RESULT_POOL as a result - of svn_fspath__canonicalize() (see svn_fs_fs__lock()). */ + of svn_fspath__canonicalize() (see svn_fs_x__lock()). */ info->lock->path = info->path; info->lock->owner = apr_pstrdup(lb->result_pool, lb->fs->access_ctx->username); Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c Tue Oct 11 09:11:50 2016 @@ -829,14 +829,6 @@ read_change(svn_fs_x__change_t **change_ change = apr_pcalloc(result_pool, sizeof(*change)); last_str = line->data; - /* Get the node-id of the change. */ - str = svn_cstring_tokenize(" ", &last_str); - if (str == NULL) - return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, - _("Invalid changes line in rev-file")); - - SVN_ERR(svn_fs_x__id_parse(&change->noderev_id, str)); - /* Get the change type. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) @@ -982,10 +974,10 @@ read_change(svn_fs_x__change_t **change_ svn_error_t * svn_fs_x__read_changes(apr_array_header_t **changes, svn_stream_t *stream, + int max_count, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - svn_fs_x__change_t *change; apr_pool_t *iterpool; /* Pre-allocate enough room for most change lists. @@ -998,13 +990,16 @@ svn_fs_x__read_changes(apr_array_header_ */ *changes = apr_array_make(result_pool, 63, sizeof(svn_fs_x__change_t *)); - SVN_ERR(read_change(&change, stream, result_pool, scratch_pool)); iterpool = svn_pool_create(scratch_pool); - while (change) + for (; max_count > 0; --max_count) { - APR_ARRAY_PUSH(*changes, svn_fs_x__change_t*) = change; - SVN_ERR(read_change(&change, stream, result_pool, iterpool)); + svn_fs_x__change_t *change; svn_pool_clear(iterpool); + SVN_ERR(read_change(&change, stream, result_pool, iterpool)); + if (!change) + break; + + APR_ARRAY_PUSH(*changes, svn_fs_x__change_t*) = change; } svn_pool_destroy(iterpool); @@ -1044,7 +1039,6 @@ write_change_entry(svn_stream_t *stream, svn_fs_x__change_t *change, apr_pool_t *scratch_pool) { - const char *idstr; const char *change_string = NULL; const char *kind_string = ""; svn_stringbuf_t *buf; @@ -1070,8 +1064,6 @@ write_change_entry(svn_stream_t *stream, change->change_kind); } - idstr = svn_fs_x__id_unparse(&change->noderev_id, scratch_pool)->data; - SVN_ERR_ASSERT(change->node_kind == svn_node_dir || change->node_kind == svn_node_file); kind_string = apr_psprintf(scratch_pool, "-%s", @@ -1079,8 +1071,8 @@ write_change_entry(svn_stream_t *stream, ? SVN_FS_X__KIND_DIR : SVN_FS_X__KIND_FILE); - buf = svn_stringbuf_createf(scratch_pool, "%s %s%s %s %s %s %s\n", - idstr, change_string, kind_string, + buf = svn_stringbuf_createf(scratch_pool, "%s%s %s %s %s %s\n", + change_string, kind_string, change->text_mod ? FLAG_TRUE : FLAG_FALSE, change->prop_mod ? FLAG_TRUE : FLAG_FALSE, change->mergeinfo_mod == svn_tristate_true Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.h (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.h Tue Oct 11 09:11:50 2016 @@ -170,15 +170,17 @@ svn_fs_x__write_rep_header(svn_fs_x__rep svn_stream_t *stream, apr_pool_t *scratch_pool); -/* Read all the changes from STREAM and store them in *CHANGES, - allocated in RESULT_POOL. Do temporary allocations in SCRATCH_POOL. */ +/* Read up to MAX_COUNT of the changes from STREAM and store them in + *CHANGES, allocated in RESULT_POOL. Do temporary allocations in + SCRATCH_POOL. */ svn_error_t * svn_fs_x__read_changes(apr_array_header_t **changes, svn_stream_t *stream, + int max_count, apr_pool_t *result_pool, apr_pool_t *scratch_pool); -/* Callback function used by svn_fs_fs__read_changes_incrementally(), +/* Callback function used by svn_fs_x__read_changes_incrementally(), * asking the receiver to process to process CHANGE using BATON. CHANGE * and SCRATCH_POOL will not be valid beyond the current callback invocation. */ Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c Tue Oct 11 09:11:50 2016 @@ -391,7 +391,7 @@ static svn_error_t * copy_file_data(pack_context_t *context, apr_file_t *dest, apr_file_t *source, - apr_off_t size, + svn_filesize_t size, apr_pool_t *scratch_pool) { /* most non-representation items will be small. Minimize the buffer @@ -478,8 +478,8 @@ copy_item_to_temp(pack_context_t *contex svn_fs_x__p2l_entry_t *new_entry = svn_fs_x__p2l_entry_dup(entry, context->info_pool); - SVN_ERR(svn_fs_x__get_file_offset(&new_entry->offset, temp_file, - scratch_pool)); + SVN_ERR(svn_io_file_get_offset(&new_entry->offset, temp_file, + scratch_pool)); APR_ARRAY_PUSH(entries, svn_fs_x__p2l_entry_t *) = new_entry; SVN_ERR(svn_fs_x__rev_file_get(&file, rev_file)); @@ -572,8 +572,8 @@ copy_rep_to_temp(pack_context_t *context /* create a copy of ENTRY, make it point to the copy destination and * store it in CONTEXT */ entry = svn_fs_x__p2l_entry_dup(entry, context->info_pool); - SVN_ERR(svn_fs_x__get_file_offset(&entry->offset, context->reps_file, - scratch_pool)); + SVN_ERR(svn_io_file_get_offset(&entry->offset, context->reps_file, + scratch_pool)); add_item_rep_mapping(context, entry); /* read & parse the representation header */ @@ -698,8 +698,8 @@ copy_node_to_temp(pack_context_t *contex /* create a copy of ENTRY, make it point to the copy destination and * store it in CONTEXT */ entry = svn_fs_x__p2l_entry_dup(entry, context->info_pool); - SVN_ERR(svn_fs_x__get_file_offset(&entry->offset, context->reps_file, - scratch_pool)); + SVN_ERR(svn_io_file_get_offset(&entry->offset, context->reps_file, + scratch_pool)); add_item_rep_mapping(context, entry); /* copy the noderev to our temp file */ @@ -821,7 +821,7 @@ sort_reps(pack_context_t *context) /* Return the remaining unused bytes in the current block in CONTEXT's * pack file. */ -static apr_ssize_t +static apr_off_t get_block_left(pack_context_t *context) { svn_fs_x__data_t *ffd = context->fs->fsap_data; @@ -1603,8 +1603,8 @@ write_changes_containers(pack_context_t * the container */ SVN_ERR(svn_io_file_seek(temp_file, APR_SET, &entry->offset, iterpool)); - SVN_ERR(svn_fs_x__read_changes(&changes, temp_stream, scratch_pool, - iterpool)); + SVN_ERR(svn_fs_x__read_changes(&changes, temp_stream, INT_MAX, + scratch_pool, iterpool)); SVN_ERR(svn_fs_x__changes_append_list(&list_index, container, changes)); SVN_ERR_ASSERT(list_index == sub_items->nelts); block_left -= estimated_size; @@ -1839,20 +1839,15 @@ append_revision(pack_context_t *context, apr_pool_t *iterpool = svn_pool_create(scratch_pool); svn_fs_x__revision_file_t *rev_file; apr_file_t *file; - apr_finfo_t finfo; - - /* Get the size of the file. */ - const char *path = svn_dirent_join(context->shard_dir, - apr_psprintf(iterpool, "%ld", - context->start_rev), - scratch_pool); - SVN_ERR(svn_io_stat(&finfo, path, APR_FINFO_SIZE, scratch_pool)); + svn_filesize_t revfile_size; /* Copy all the bits from the rev file to the end of the pack file. */ SVN_ERR(svn_fs_x__rev_file_init(&rev_file, context->fs, context->start_rev, scratch_pool)); SVN_ERR(svn_fs_x__rev_file_get(&file, rev_file)); - SVN_ERR(copy_file_data(context, context->pack_file, file, finfo.size, + + SVN_ERR(svn_io_file_size_get(&revfile_size, file, scratch_pool)); + SVN_ERR(copy_file_data(context, context->pack_file, file, revfile_size, iterpool)); /* mark the start of a new revision */ @@ -1861,7 +1856,7 @@ append_revision(pack_context_t *context, /* read the phys-to-log index file until we covered the whole rev file. * That index contains enough info to build both target indexes from it. */ - while (offset < finfo.size) + while (offset < revfile_size) { /* read one cluster */ int i; @@ -1883,7 +1878,7 @@ append_revision(pack_context_t *context, /* process entry while inside the rev file */ offset = entry->offset; - if (offset < finfo.size) + if (offset < revfile_size) { /* there should be true containers */ SVN_ERR_ASSERT(entry->item_count == 1); @@ -1902,7 +1897,7 @@ append_revision(pack_context_t *context, } svn_pool_destroy(iterpool); - context->pack_offset += finfo.size; + context->pack_offset += revfile_size; return SVN_NO_ERROR; } @@ -2083,7 +2078,8 @@ pack_shard(const char *dir, scratch_pool)); /* Perform all fsyncs through this instance. */ - SVN_ERR(svn_fs_x__batch_fsync_create(&batch, scratch_pool)); + SVN_ERR(svn_fs_x__batch_fsync_create(&batch, ffd->flush_to_disk, + scratch_pool)); /* Some useful paths. */ pack_file_dir = svn_dirent_join(dir, Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c Tue Oct 11 09:11:50 2016 @@ -100,12 +100,16 @@ open_rep_cache(void *baton, 0, NULL, 0, fs->pool, scratch_pool)); - SVN_ERR(svn_sqlite__read_schema_version(&version, sdb, scratch_pool)); + SVN_SQLITE__ERR_CLOSE(svn_sqlite__read_schema_version(&version, sdb, + scratch_pool), + sdb); if (version < REP_CACHE_SCHEMA_FORMAT) { /* Must be 0 -- an uninitialized (no schema) database. Create the schema. Results in schema version of 1. */ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_SCHEMA)); + SVN_SQLITE__ERR_CLOSE(svn_sqlite__exec_statements(sdb, + STMT_CREATE_SCHEMA), + sdb); } /* This is used as a flag that the database is available so don't @@ -126,6 +130,21 @@ svn_fs_x__open_rep_cache(svn_fs_t *fs, } svn_error_t * +svn_fs_x__close_rep_cache(svn_fs_t *fs) +{ + svn_fs_x__data_t *ffd = fs->fsap_data; + + if (ffd->rep_cache_db) + { + SVN_ERR(svn_sqlite__close(ffd->rep_cache_db)); + ffd->rep_cache_db = NULL; + ffd->rep_cache_db_opened = 0; + } + + return SVN_NO_ERROR; +} + +svn_error_t * svn_fs_x__exists_rep_cache(svn_boolean_t *exists, svn_fs_t *fs, apr_pool_t *scratch_pool) @@ -236,7 +255,7 @@ svn_fs_x__walk_rep_reference(svn_fs_t *f If you extend this function, check the callsite to see if you have to make it not-ignore additional error codes. */ svn_error_t * -svn_fs_x__get_rep_reference(svn_fs_x__representation_t **rep, +svn_fs_x__get_rep_reference(svn_fs_x__representation_t **rep_p, svn_fs_t *fs, svn_checksum_t *checksum, apr_pool_t *result_pool, @@ -245,6 +264,7 @@ svn_fs_x__get_rep_reference(svn_fs_x__re svn_fs_x__data_t *ffd = fs->fsap_data; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; + svn_fs_x__representation_t *rep; SVN_ERR_ASSERT(ffd->rep_sharing_allowed); if (! ffd->rep_cache_db) @@ -263,24 +283,23 @@ svn_fs_x__get_rep_reference(svn_fs_x__re SVN_ERR(svn_sqlite__step(&have_row, stmt)); if (have_row) { - *rep = apr_pcalloc(result_pool, sizeof(**rep)); - memcpy((*rep)->sha1_digest, checksum->digest, - sizeof((*rep)->sha1_digest)); - (*rep)->has_sha1 = TRUE; - (*rep)->id.change_set = svn_sqlite__column_revnum(stmt, 0); - (*rep)->id.number = svn_sqlite__column_int64(stmt, 1); - (*rep)->size = svn_sqlite__column_int64(stmt, 2); - (*rep)->expanded_size = svn_sqlite__column_int64(stmt, 3); + rep = apr_pcalloc(result_pool, sizeof(*rep)); + memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest)); + rep->has_sha1 = TRUE; + rep->id.change_set = svn_sqlite__column_revnum(stmt, 0); + rep->id.number = svn_sqlite__column_int64(stmt, 1); + rep->size = svn_sqlite__column_int64(stmt, 2); + rep->expanded_size = svn_sqlite__column_int64(stmt, 3); } else - *rep = NULL; + rep = NULL; SVN_ERR(svn_sqlite__reset(stmt)); - if (*rep) + if (rep) { /* Check that REP refers to a revision that exists in FS. */ - svn_revnum_t revision = svn_fs_x__get_revnum((*rep)->id.change_set); + svn_revnum_t revision = svn_fs_x__get_revnum(rep->id.change_set); svn_error_t *err = svn_fs_x__ensure_revision_exists(revision, fs, scratch_pool); if (err) @@ -289,6 +308,7 @@ svn_fs_x__get_rep_reference(svn_fs_x__re svn_checksum_to_cstring_display(checksum, scratch_pool)); } + *rep_p = rep; return SVN_NO_ERROR; } Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.h URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.h?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.h (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.h Tue Oct 11 09:11:50 2016 @@ -40,6 +40,10 @@ svn_error_t * svn_fs_x__open_rep_cache(svn_fs_t *fs, apr_pool_t *scratch_pool); +/* Close the rep cache database associated with FS. */ +svn_error_t * +svn_fs_x__close_rep_cache(svn_fs_t *fs); + /* Set *EXISTS to TRUE iff the rep-cache DB file exists. */ svn_error_t * svn_fs_x__exists_rep_cache(svn_boolean_t *exists, @@ -61,11 +65,12 @@ svn_fs_x__walk_rep_reference(svn_fs_t *f apr_pool_t *scratch_pool); /* Return the representation REP in FS which has fulltext CHECKSUM. - REP is allocated in RESULT_POOL. If the rep cache database has not been - opened, just set *REP to NULL. Returns SVN_ERR_FS_CORRUPT if a reference - beyond HEAD is detected. Uses SCRATCH_POOL for temporary allocations. */ + *REP_P is allocated in RESULT_POOL. If the rep cache database has not + been opened, just set *REP_P to NULL. Returns SVN_ERR_FS_CORRUPT if + a reference beyond HEAD is detected. Uses SCRATCH_POOL for temporary + allocations.*/ svn_error_t * -svn_fs_x__get_rep_reference(svn_fs_x__representation_t **rep, +svn_fs_x__get_rep_reference(svn_fs_x__representation_t **rep_p, svn_fs_t *fs, svn_checksum_t *checksum, apr_pool_t *result_pool, Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c (original) +++ subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c Tue Oct 11 09:11:50 2016 @@ -192,7 +192,7 @@ get_file_pool(svn_fs_x__revision_file_t return file->pool; } -/* Core implementation of svn_fs_fs__open_pack_or_rev_file working on an +/* 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. */ @@ -490,8 +490,8 @@ svn_fs_x__rev_file_offset(apr_off_t *off svn_fs_x__revision_file_t *file) { SVN_ERR(auto_open(file)); - return svn_error_trace(svn_fs_x__get_file_offset(offset, file->file, - file->pool)); + return svn_error_trace(svn_io_file_get_offset(offset, file->file, + file->pool)); } svn_error_t *