stef...@apache.org wrote on Sun, Oct 31, 2010 at 15:22:31 -0000: > Author: stefan2 > Date: Sun Oct 31 15:22:31 2010 > New Revision: 1029381 > > URL: http://svn.apache.org/viewvc?rev=1029381&view=rev > Log: > Fix another packing issue. Due to concurrent access alone > it may happen that between determining the rev file name > and actually opening it, that very revision may get packed > (actually, get deleted after packing). > > The file handle cache adds another issue: an open file handle > may not be suitable due to different open flags and the file > must be re-opened. While the existing handle would have > kept the file content alive, opening a new handle to the same > file will fail if the file was deleted before. > > Since there can be only one transition from non-packed to > packed, we need to retry only once if we could not find the > revision file in question. > > * subversion/libsvn_fs_fs/fs_fs.c > (open_pack_or_rev_file): retry once because the file might have > gotten packed. > > Modified: > subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c > > Modified: subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c > URL: > http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c?rev=1029381&r1=1029380&r2=1029381&view=diff > ============================================================================== > --- subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c (original) > +++ subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c Sun Oct > 31 15:22:31 2010 > @@ -1939,34 +1939,54 @@ open_pack_or_rev_file(svn_file_handle_ca (the unidiff is unreadable, so I'll just paste the whole function) > static svn_error_t * > open_pack_or_rev_file(svn_file_handle_cache__handle_t **file, > svn_fs_t *fs, > svn_revnum_t rev, > apr_off_t offset, > int cookie, > apr_pool_t *pool) > { > svn_error_t *err; > const char *path; > svn_boolean_t retry = FALSE; > fs_fs_data_t *ffd = fs->fsap_data; > > do > { > /* make sure file has a defined state */ > *file = NULL; > err = svn_fs_fs__path_rev_absolute(&path, fs, rev, pool); >
So, now this call is inside the retry loop. But it does its own retry loop already. Looking at svn_fs_fs__path_rev_absolute()'s other callers, they all run under the fsfs write lock (which pack operations also acquire) except for the one in lock.c. So, I suppose we can remove the retry logic from svn_fs_fs__path_rev_absolute() and add it in lock.c (where it's currently absent). Also, svn_fs_fs__path_rev_absolute()'s docstring could warn that its result is "unstable" (points to a path that may vanish under certain conditions). > if (! err) > { > /* open the revision file in buffered r/o mode */ > err = svn_file_handle_cache__open(file, > ffd->file_handle_cache, > path, > APR_READ | APR_BUFFERED, > APR_OS_DEFAULT, > offset, > cookie, > pool); > > /* if that succeeded, there must be an underlying APR file */ > assert(err || svn_file_handle_cache__get_apr_handle(*file)); > } > > if (err && APR_STATUS_IS_ENOENT(err->apr_err)) > { > /* Could not open the file. This may happen if the > * file once existed but got packed later. Note that > * the file handle cache may have had an open handle > * to the old file but had to close it in the function > * call above due to different open flags. > */ > svn_error_clear(err); > > /* if that was our 2nd attempt, leave it at that. */ > if (retry) > return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL, > _("No such revision %ld"), rev); > > /* we failed for the first time. Refresh caches & retry. */ > SVN_ERR(svn_file_handle_cache__flush(ffd->file_handle_cache)); > SVN_ERR(update_min_unpacked_rev(fs, pool)); > > retry = TRUE; > } Need "else\n return svn_error_return(err);" here, to prevent leaking the error when retry=TRUE. > } > while (err && retry); > > return svn_error_return(err); > }