On Mon, Apr 21, 2014 at 10:21 AM, Ivan Zhakov <i...@visualsvn.com> wrote:
> On 20 April 2014 22:35, <stef...@apache.org> wrote: > > Author: stefan2 > > Date: Sun Apr 20 18:35:43 2014 > > New Revision: 1588815 > > > > URL: http://svn.apache.org/r1588815 > > Log: > > Enable FSFS to take out more than file lock at once through a single > call. > > Use that functionality to take out the new pack lock for upgrade, hotcopy > > and recovery. Also, disallow new TXNs during upgrade and recovery. > > > > The core is the introduction of a new data type describing a lock to take > > out, which can be nested / chained. Switch all existing lock function to > > using that infrastructure. > > > [...] > > > + switch (lock_id) > > + { > > + case write_lock: baton->mutex = ffsd->fs_write_lock; > > + baton->lock_path = path_lock(baton->fs, > > + baton->lock_pool); > > + baton->is_global_lock = TRUE; > > + break; > Please use standard indentation. > Done in r1589243. > > + > > +/* Return the baton for the innermost lock of a (potential) lock chain. > > + The baton shall take out LOCK_ID from FS and execute BODY with BATON > > + while the lock is being held. Allocate the result in a sub-pool of > POOL. > > + */ > > +static with_lock_baton_t * > > +create_lock_baton(svn_fs_t *fs, > > + lock_id_t lock_id, > > + svn_error_t *(*body)(void *baton, > > + apr_pool_t *pool), > > + void *baton, > > + apr_pool_t *pool) > > +{ > > + apr_pool_t *lock_pool = svn_pool_create(pool); > > + with_lock_baton_t *result = apr_pcalloc(lock_pool, sizeof(*result)); > > + > > + result->fs = fs; > > + result->body = body; > > + result->baton = baton; > > + result->lock_pool = lock_pool; > > + result->is_inner_most_lock = TRUE; > > + result->is_outer_most_lock = TRUE; > > + > > + init_lock_baton(result, lock_id); > > + > > + return result; > > +} > > + > > +/* Return a baton that wraps NESTED and requests LOCK_ID as additional > lock. > > + */ > > +static with_lock_baton_t * > > +chain_lock_baton(lock_id_t lock_id, > > + with_lock_baton_t *nested) > > +{ > > + apr_pool_t *lock_pool = nested->lock_pool; > > + with_lock_baton_t *result = apr_pcalloc(lock_pool, sizeof(*result)); > > + > > + result->fs = nested->fs; > > + result->body = with_lock; > > + result->baton = nested; > > + result->lock_pool = lock_pool; > > + result->is_inner_most_lock = FALSE; > > + result->is_outer_most_lock = TRUE; > > + nested->is_outer_most_lock = FALSE; > > + > > + init_lock_baton(result, lock_id); > > + > > + return result; > > +} > > + > I don't see bugs in the code above, but it is very hard to read and > understand what is going on and what fields are initialized in > different cases. > All fields are always being initialized. r1589373 explains all init. values now. > -/* Run BODY (with BATON and POOL) while the txn-current file > > - of FS is locked. */ > > svn_error_t * > > svn_fs_fs__with_txn_current_lock(svn_fs_t *fs, > > svn_error_t *(*body)(void *baton, > > @@ -243,18 +382,34 @@ svn_fs_fs__with_txn_current_lock(svn_fs_ > > void *baton, > > apr_pool_t *pool) > > { > > + return svn_error_trace( > > + with_lock(create_lock_baton(fs, txn_lock, body, baton, pool), > > + pool)); > > +} > > + > > +svn_error_t * > > +svn_fs_fs__with_all_locks(svn_fs_t *fs, > > + svn_boolean_t allow_new_txns, > > + svn_error_t *(*body)(void *baton, > > + apr_pool_t *pool), > > + void *baton, > > + apr_pool_t *pool) > I think that the following function signature will be much easier to > use and *implement*. > I dropped the ALLOW_NEW_TXNS parameter from the signature in r1589250. It is now as simple as the the specific lock functions. I honestly believe that neither of the following alternative would result in code that is easier to maintain: * Use 3 nested, conditional SVN_MUTEX__WITH_LOCK + with_some_lock_file calls. That would require at least 2 new body functions and 1 (maybe 2) new baton struct. Basically, we would then run the same sequence calling e.g. with_txn_current_lock and let the baton chain unroll. Less flexible, less obvious, less efficient. * Add a special function that conditionally takes out 3 mutexes (without using the convenient macro) and up to 3 file locks - always being anxious not to miss an error condition or to leak a lock. That's be some brittle code that's also hard to extend once we decide to add more locks. > svn_fs_fs__with_locks_many(svn_fs_t *fs, > svn_boolean_t write_lock, > svn_boolean_t txn_lock, > svn_booelan_t pack_lock, > ...) > Patches are welcome. > Seriously, could you tell me in what order locks are obtained without > debugger? May be I'm dumb but I cannot answer this question. Coding in > way that only author understand the code is bad thing especially for > open source project IMHO. > r1589376 explicitly documents the lock acquisition order, now. I don't think the code is harder to understand than any of our stream handling code because it uses the same pattern. As a bonus, all the relevant code is in a single location (as opposed to streams meandering through numerous source files - with good reason). -- Stefan^2.