comparison hgext/largefiles/overrides.py @ 42456:87a34c767384

merge: fix race that could cause wrong size in dirstate The problem is that hg merge/update/etc work the following way: 1. figure out what files to update 2. apply the update to disk 3. apply the update to in-memory dirstate 4. write dirstate where step3 looks at the filesystem and assumes it sees the result of step2. If a file is changed between step2 and step3, step3 will record incorrect information in the dirstate. I avoid this by passing the size step3 needs directly from step2, for the common path (not implemented for change/delete conflicts for instance). I didn't fix the same race for the exec bit for now, because it's less likely to be problematic and I had trouble due to the fact that the dirstate stores the permissions differently from the manifest (st_mode vs '' 'l' 'x'), in combination with tests that pretend that symlinks are not supported. However, I moved the lstat from step3 to step2, which should tighten the race window markedly, both for the exec bit and for the mtime. Differential Revision: https://phab.mercurial-scm.org/D6475
author Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
date Mon, 27 May 2019 16:55:46 -0400
parents 1eb2fc21da12
children 421fdf30c37c
comparison
equal deleted inserted replaced
42455:5ca136bbd3f6 42456:87a34c767384
513 actions[standin] = ('r', None, 'replaced by non-standin') 513 actions[standin] = ('r', None, 'replaced by non-standin')
514 514
515 return actions, diverge, renamedelete 515 return actions, diverge, renamedelete
516 516
517 @eh.wrapfunction(merge, 'recordupdates') 517 @eh.wrapfunction(merge, 'recordupdates')
518 def mergerecordupdates(orig, repo, actions, branchmerge): 518 def mergerecordupdates(orig, repo, actions, branchmerge, getfiledata):
519 if 'lfmr' in actions: 519 if 'lfmr' in actions:
520 lfdirstate = lfutil.openlfdirstate(repo.ui, repo) 520 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
521 for lfile, args, msg in actions['lfmr']: 521 for lfile, args, msg in actions['lfmr']:
522 # this should be executed before 'orig', to execute 'remove' 522 # this should be executed before 'orig', to execute 'remove'
523 # before all other actions 523 # before all other actions
524 repo.dirstate.remove(lfile) 524 repo.dirstate.remove(lfile)
525 # make sure lfile doesn't get synclfdirstate'd as normal 525 # make sure lfile doesn't get synclfdirstate'd as normal
526 lfdirstate.add(lfile) 526 lfdirstate.add(lfile)
527 lfdirstate.write() 527 lfdirstate.write()
528 528
529 return orig(repo, actions, branchmerge) 529 return orig(repo, actions, branchmerge, getfiledata)
530 530
531 # Override filemerge to prompt the user about how they wish to merge 531 # Override filemerge to prompt the user about how they wish to merge
532 # largefiles. This will handle identical edits without prompting the user. 532 # largefiles. This will handle identical edits without prompting the user.
533 @eh.wrapfunction(filemerge, '_filemerge') 533 @eh.wrapfunction(filemerge, '_filemerge')
534 def overridefilemerge(origfn, premerge, repo, wctx, mynode, orig, fcd, fco, fca, 534 def overridefilemerge(origfn, premerge, repo, wctx, mynode, orig, fcd, fco, fca,