Re: [PATCH v3 12/19] initial_ref_transaction_commit(): check for duplicate refs
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Jun 23, 2015, 17:44 UTC
- Message-ID
- <xmqqd20me2uq.fsf@gitster.dls.corp.google.com>
- In-Reply-To
- <558906A4.8060106@alum.mit.edu>
Michael Haggerty <mhagger@alum.mit.edu> writes:
Show 20 quoted lines
> On 06/22/2015 11:06 PM, Junio C Hamano wrote:
> ...
>> What I am wondering is if we could turn the safety logic that appear
>> here (i.e. no existing refs must be assumed by the set of updates,
>> etc.) into an optimization cue and implement this as a special case
>> helper to ref_transaction_commit(), i.e.
>>
>> ref_transaction_commit(...)
>> {
>> if (updates are all initial creation &&
>> no existing refs in repository)
>> return initial_ref_transaction_commit(...);
>> /* otherwise we do the usual thing */
>> ...
>> }
>>
>> and have "clone" call ref_transaction_commit() as usual.
>
> The safety logic in this function is (approximately) necessary, but not
> sufficient, to guarantee safety.Oh, no question about it, and you do not even have to bring up an insane "user runs random commands while Git is hard working on it" non use-case ;-)
Show 7 quoted lines
> One of the shortcuts that it takes is > not locking the references while they are being created. Therefore, it > would be unsafe for one process to call ref_transaction_commit() while > another is calling initial_ref_transaction_commit(). So the caller has > to "know" somehow that no other processes are working in the repository > for this optimization to be safe. It conveys that knowledge by calling > initial_ref_transaction_commit() rather than ref_transaction_commit().
OK. So the answer to my first question "is the initial creation logic too fragile" is a resounding "yes"; the caller should know that it is too crazy for the user to be competing with what it is doing before deciding to call initial_ref_transaction_commit(), hence we cannot automatically detect if it is safe from within ref_transaction_commit() to use this logic as an optimization.
Show 11 quoted lines
> But I think if anything it would make more sense to go the other direction: > > * Teach ref_transaction_commit() an option that asks it to write > references updates to packed-refs instead of loose refs (but > locking the references as usual). > > * Change clone to use ref_transaction_commit() like everybody > else, passing it the new REFS_WRITE_TO_PACKED_REFS option. > > Then clone would participate in the normal locking protocol, and it > wouldn't *matter* if another process runs before the clone is finished.
Yeah, I thought that was actually I was driving at, and doing so without that write-to-packed-refs option, which I'd prefer to leave it as an optimization inside ref_transaction_commit().
Except that I missed that the initial_* variant is even more aggressive (i.e. not locking), so no such optimization is safe.
Show 9 quoted lines
> There would also be some consistency benefits. For example, if > core.logallrefupdates is set globally or on the command line, the > initial reference creations would be reflogged. And other operations > that write references in bulk could use the new > REFS_WRITE_TO_PACKED_REFS option to prevent loose reference proliferation. > > But I don't think any of this is a problem in practice, and I think we > can live with using the optimized-but-not-100%-safe > initial_ref_transaction_commit() for cloning.
OK.