Alien-SVN
view release on metacpan or search on metacpan
src/subversion/subversion/libsvn_fs_fs/fs_fs.c view on Meta::CPAN
&& max_files_per_dir > 0)
{
needs_revprop_shard_cleanup = TRUE;
SVN_ERR(upgrade_pack_revprops(fs, pool));
}
/* Bump the format file. */
SVN_ERR(write_format(format_path, SVN_FS_FS__FORMAT_NUMBER,
max_files_per_dir, TRUE, pool));
/* Now, it is safe to remove the redundant revprop files. */
if (needs_revprop_shard_cleanup)
SVN_ERR(upgrade_cleanup_pack_revprops(fs, pool));
/* Done */
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_fs__upgrade(svn_fs_t *fs, apr_pool_t *pool)
{
return svn_fs_fs__with_write_lock(fs, upgrade_body, (void *)fs, pool);
}
/* Functions for dealing with recoverable errors on mutable files
*
* Revprops, current, and txn-current files are mutable; that is, they
* change as part of normal fsfs operation, in constrat to revs files, or
* the format file, which are written once at create (or upgrade) time.
* When more than one host writes to the same repository, we will
* sometimes see these recoverable errors when accesssing these files.
*
* These errors all relate to NFS, and thus we only use this retry code if
* ESTALE is defined.
*
** ESTALE
*
* In NFS v3 and under, the server doesn't track opened files. If you
* unlink(2) or rename(2) a file held open by another process *on the
* same host*, that host's kernel typically renames the file to
* .nfsXXXX and automatically deletes that when it's no longer open,
* but this behavior is not required.
*
* For obvious reasons, this does not work *across hosts*. No one
* knows about the opened file; not the server, and not the deleting
* client. So the file vanishes, and the reader gets stale NFS file
* handle.
*
** EIO, ENOENT
*
* Some client implementations (at least the 2.6.18.5 kernel that ships
* with Ubuntu Dapper) sometimes give spurious ENOENT (only on open) or
* even EIO errors when trying to read these files that have been renamed
* over on some other host.
*
** Solution
*
* Try open and read of such files in try_stringbuf_from_file(). Call
* this function within a loop of RECOVERABLE_RETRY_COUNT iterations
* (though, realistically, the second try will succeed).
*/
#define RECOVERABLE_RETRY_COUNT 10
/* Read the file at PATH and return its content in *CONTENT. *CONTENT will
* not be modified unless the whole file was read successfully.
*
* ESTALE, EIO and ENOENT will not cause this function to return an error
* unless LAST_ATTEMPT has been set. If MISSING is not NULL, indicate
* missing files (ENOENT) there.
*
* Use POOL for allocations.
*/
static svn_error_t *
try_stringbuf_from_file(svn_stringbuf_t **content,
svn_boolean_t *missing,
const char *path,
svn_boolean_t last_attempt,
apr_pool_t *pool)
{
svn_error_t *err = svn_stringbuf_from_file2(content, path, pool);
if (missing)
*missing = FALSE;
if (err)
{
*content = NULL;
if (APR_STATUS_IS_ENOENT(err->apr_err))
{
if (!last_attempt)
{
svn_error_clear(err);
if (missing)
*missing = TRUE;
return SVN_NO_ERROR;
}
}
#ifdef ESTALE
else if (APR_TO_OS_ERROR(err->apr_err) == ESTALE
|| APR_TO_OS_ERROR(err->apr_err) == EIO)
{
if (!last_attempt)
{
svn_error_clear(err);
return SVN_NO_ERROR;
}
}
#endif
}
return svn_error_trace(err);
}
/* Read the 'current' file FNAME and store the contents in *BUF.
Allocations are performed in POOL. */
static svn_error_t *
read_content(svn_stringbuf_t **content, const char *fname, apr_pool_t *pool)
{
src/subversion/subversion/libsvn_fs_fs/fs_fs.c view on Meta::CPAN
count = noderev->predecessor_count - 1;
/* Finding the delta base over a very long distance can become extremely
expensive for very deep histories, possibly causing client timeouts etc.
OTOH, this is a rare operation and its gains are minimal. Lets simply
start deltification anew close every other 1000 changes or so. */
if (walk > (int)ffd->max_deltification_walk)
{
*rep = NULL;
return SVN_NO_ERROR;
}
/* Walk back a number of predecessors equal to the difference
between count and the original predecessor count. (For example,
if noderev has ten predecessors and we want the eighth file rev,
walk back two predecessors.) */
base = noderev;
while ((count++) < noderev->predecessor_count)
{
SVN_ERR(svn_fs_fs__get_node_revision(&base, fs,
base->predecessor_id, pool));
/* If there is a shared rep along the way, we need to limit the
* length of the deltification chain.
*
* Please note that copied nodes - such as branch directories - will
* look the same (false positive) while reps shared within the same
* revision will not be caught (false negative).
*/
if (props)
{
if ( base->prop_rep
&& svn_fs_fs__id_rev(base->id) > base->prop_rep->revision)
maybe_shared_rep = TRUE;
}
else
{
if ( base->data_rep
&& svn_fs_fs__id_rev(base->id) > base->data_rep->revision)
maybe_shared_rep = TRUE;
}
}
/* return a suitable base representation */
*rep = props ? base->prop_rep : base->data_rep;
/* if we encountered a shared rep, it's parent chain may be different
* from the node-rev parent chain. */
if (*rep && maybe_shared_rep)
{
/* Check whether the length of the deltification chain is acceptable.
* Otherwise, shared reps may form a non-skipping delta chain in
* extreme cases. */
apr_pool_t *sub_pool = svn_pool_create(pool);
representation_t base_rep = **rep;
/* Some reasonable limit, depending on how acceptable longer linear
* chains are in this repo. Also, allow for some minimal chain. */
int max_chain_length = 2 * (int)ffd->max_linear_deltification + 2;
/* re-use open files between iterations */
svn_revnum_t rev_hint = SVN_INVALID_REVNUM;
apr_file_t *file_hint = NULL;
/* follow the delta chain towards the end but for at most
* MAX_CHAIN_LENGTH steps. */
for (; max_chain_length; --max_chain_length)
{
struct rep_state *rep_state;
struct rep_args *rep_args;
SVN_ERR(create_rep_state_body(&rep_state,
&rep_args,
&file_hint,
&rev_hint,
&base_rep,
fs,
sub_pool));
if (!rep_args->is_delta || !rep_args->base_revision)
break;
base_rep.revision = rep_args->base_revision;
base_rep.offset = rep_args->base_offset;
base_rep.size = rep_args->base_length;
base_rep.txn_id = NULL;
}
/* start new delta chain if the current one has grown too long */
if (max_chain_length == 0)
*rep = NULL;
svn_pool_destroy(sub_pool);
}
/* verify that the reps don't form a degenerated '*/
return SVN_NO_ERROR;
}
/* Something went wrong and the pool for the rep write is being
cleared before we've finished writing the rep. So we need
to remove the rep from the protorevfile and we need to unlock
the protorevfile. */
static apr_status_t
rep_write_cleanup(void *data)
{
struct rep_write_baton *b = data;
const char *txn_id = svn_fs_fs__id_txn_id(b->noderev->id);
svn_error_t *err;
/* Truncate and close the protorevfile. */
err = svn_io_file_trunc(b->file, b->rep_offset, b->pool);
err = svn_error_compose_create(err, svn_io_file_close(b->file, b->pool));
/* Remove our lock regardless of any preceeding errors so that the
being_written flag is always removed and stays consistent with the
file lock which will be removed no matter what since the pool is
going away. */
err = svn_error_compose_create(err, unlock_proto_rev(b->fs, txn_id,
b->lockcookie, b->pool));
if (err)
{
src/subversion/subversion/libsvn_fs_fs/fs_fs.c view on Meta::CPAN
svn_pool_clear(walker_baton->pool);
walker_baton->iteration_count = 0;
walker_baton->file_count = 0;
walker_baton->file_hint = NULL;
walker_baton->rev_hint = SVN_INVALID_REVNUM;
}
/* access the repo data */
previous_file = walker_baton->file_hint;
SVN_ERR(create_rep_state(&rs, &rep_args, &walker_baton->file_hint,
&walker_baton->rev_hint, rep, fs,
walker_baton->pool));
/* update resource usage counters */
walker_baton->iteration_count++;
if (previous_file != walker_baton->file_hint)
walker_baton->file_count++;
}
else
{
/* ### Should this be using read_rep_line() directly? */
SVN_ERR(create_rep_state(&rs, &rep_args, NULL, NULL, rep, fs,
scratch_pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_fs__verify(svn_fs_t *fs,
svn_revnum_t start,
svn_revnum_t end,
svn_fs_progress_notify_func_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
svn_boolean_t exists;
svn_revnum_t youngest = ffd->youngest_rev_cache; /* cache is current */
if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT)
return SVN_NO_ERROR;
/* Input validation. */
if (! SVN_IS_VALID_REVNUM(start))
start = 0;
if (! SVN_IS_VALID_REVNUM(end))
end = youngest;
SVN_ERR(ensure_revision_exists(fs, start, pool));
SVN_ERR(ensure_revision_exists(fs, end, pool));
/* rep-cache verification. */
SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, fs, pool));
if (exists)
{
/* provide a baton to allow the reuse of open file handles between
iterations (saves 2/3 of OS level file operations). */
verify_walker_baton_t *baton = apr_pcalloc(pool, sizeof(*baton));
baton->rev_hint = SVN_INVALID_REVNUM;
baton->pool = svn_pool_create(pool);
baton->last_notified_revision = SVN_INVALID_REVNUM;
baton->notify_func = notify_func;
baton->notify_baton = notify_baton;
/* tell the user that we are now ready to do *something* */
if (notify_func)
notify_func(SVN_INVALID_REVNUM, notify_baton, baton->pool);
/* Do not attempt to walk the rep-cache database if its file does
not exist, since doing so would create it --- which may confuse
the administrator. Don't take any lock. */
SVN_ERR(svn_fs_fs__walk_rep_reference(fs, start, end,
verify_walker, baton,
cancel_func, cancel_baton,
pool));
/* walker resource cleanup */
svn_pool_destroy(baton->pool);
}
return SVN_NO_ERROR;
}
/** Hotcopy. **/
/* Like svn_io_dir_file_copy(), but doesn't copy files that exist at
* the destination and do not differ in terms of kind, size, and mtime. */
static svn_error_t *
hotcopy_io_dir_file_copy(const char *src_path,
const char *dst_path,
const char *file,
apr_pool_t *scratch_pool)
{
const svn_io_dirent2_t *src_dirent;
const svn_io_dirent2_t *dst_dirent;
const char *src_target;
const char *dst_target;
/* Does the destination already exist? If not, we must copy it. */
dst_target = svn_dirent_join(dst_path, file, scratch_pool);
SVN_ERR(svn_io_stat_dirent2(&dst_dirent, dst_target, FALSE, TRUE,
scratch_pool, scratch_pool));
if (dst_dirent->kind != svn_node_none)
{
/* If the destination's stat information indicates that the file
* is equal to the source, don't bother copying the file again. */
src_target = svn_dirent_join(src_path, file, scratch_pool);
SVN_ERR(svn_io_stat_dirent2(&src_dirent, src_target, FALSE, FALSE,
scratch_pool, scratch_pool));
if (src_dirent->kind == dst_dirent->kind &&
src_dirent->special == dst_dirent->special &&
src_dirent->filesize == dst_dirent->filesize &&
src_dirent->mtime <= dst_dirent->mtime)
return SVN_NO_ERROR;
}
( run in 0.860 second using v1.01-cache-2.11-cpan-71847e10f99 )