Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/merge.py @ 42529:d29db0a0c4eb
update: fix spurious unclean status bug shown by previous commit
The crux of the problem is:
- the dirstate is corrupted (the sizes/dates are assigned to the wrong files)
- because when worker.worker is used with a return value (batchget in
merge.py here), the return value when worker.worker effectively parallelizes
is permuted
- this is because worker.worker's partition of input and combination of output
values are not inverses of one another: it split [1,2,3,4,5,6] into
[[1,3,5],[2,4,6]], but combines that into [1,3,5,2,4,6].
Given that worker.worker doesn't call its function argument on contiguous
chunks on the input arguments, sticking with lists means we'd need to
know the relation between the inputs of worker.worker function argument
(for instance, requiring that every input element is mapped to exactly
one output element). It seems better to instead switch return values to
dicts, which can combined reliably with a straighforward restriction.
Differential Revision: https://phab.mercurial-scm.org/D6581
author | Valentin Gatien-Baron <valentin.gatienbaron@gmail.com> |
---|---|
date | Thu, 27 Jun 2019 11:39:35 +0200 |
parents | 87a34c767384 |
children | a4ca0610c754 7b80ad5af239 |
comparison
equal
deleted
inserted
replaced
42528:64a873ca7135 | 42529:d29db0a0c4eb |
---|---|
1470 | 1470 |
1471 mctx is the context to get from | 1471 mctx is the context to get from |
1472 | 1472 |
1473 Yields arbitrarily many (False, tuple) for progress updates, followed by | 1473 Yields arbitrarily many (False, tuple) for progress updates, followed by |
1474 exactly one (True, filedata). When wantfiledata is false, filedata is an | 1474 exactly one (True, filedata). When wantfiledata is false, filedata is an |
1475 empty list. When wantfiledata is true, filedata[i] is a triple (mode, size, | 1475 empty dict. When wantfiledata is true, filedata[f] is a triple (mode, size, |
1476 mtime) of the file written for action[i]. | 1476 mtime) of the file f written for each action. |
1477 """ | 1477 """ |
1478 filedata = [] | 1478 filedata = {} |
1479 verbose = repo.ui.verbose | 1479 verbose = repo.ui.verbose |
1480 fctx = mctx.filectx | 1480 fctx = mctx.filectx |
1481 ui = repo.ui | 1481 ui = repo.ui |
1482 i = 0 | 1482 i = 0 |
1483 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)): | 1483 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)): |
1507 atomictemp=atomictemp) | 1507 atomictemp=atomictemp) |
1508 if wantfiledata: | 1508 if wantfiledata: |
1509 s = wfctx.lstat() | 1509 s = wfctx.lstat() |
1510 mode = s.st_mode | 1510 mode = s.st_mode |
1511 mtime = s[stat.ST_MTIME] | 1511 mtime = s[stat.ST_MTIME] |
1512 filedata.append((mode, size, mtime)) # for dirstate.normal | 1512 filedata[f] = ((mode, size, mtime)) # for dirstate.normal |
1513 if i == 100: | 1513 if i == 100: |
1514 yield False, (i, f) | 1514 yield False, (i, f) |
1515 i = 0 | 1515 i = 0 |
1516 i += 1 | 1516 i += 1 |
1517 if i > 0: | 1517 if i > 0: |
1668 prog = worker.worker(repo.ui, cost, batchget, | 1668 prog = worker.worker(repo.ui, cost, batchget, |
1669 (repo, mctx, wctx, wantfiledata), | 1669 (repo, mctx, wctx, wantfiledata), |
1670 actions[ACTION_GET], | 1670 actions[ACTION_GET], |
1671 threadsafe=threadsafe, | 1671 threadsafe=threadsafe, |
1672 hasretval=True) | 1672 hasretval=True) |
1673 getfiledata = [] | 1673 getfiledata = {} |
1674 for final, res in prog: | 1674 for final, res in prog: |
1675 if final: | 1675 if final: |
1676 getfiledata = res | 1676 getfiledata = res |
1677 else: | 1677 else: |
1678 i, item = res | 1678 i, item = res |
1801 mfiles = set(a[0] for a in actions[ACTION_MERGE]) | 1801 mfiles = set(a[0] for a in actions[ACTION_MERGE]) |
1802 for k, acts in extraactions.iteritems(): | 1802 for k, acts in extraactions.iteritems(): |
1803 actions[k].extend(acts) | 1803 actions[k].extend(acts) |
1804 if k == ACTION_GET and wantfiledata: | 1804 if k == ACTION_GET and wantfiledata: |
1805 # no filedata until mergestate is updated to provide it | 1805 # no filedata until mergestate is updated to provide it |
1806 getfiledata.extend([None] * len(acts)) | 1806 for a in acts: |
1807 getfiledata[a[0]] = None | |
1807 # Remove these files from actions[ACTION_MERGE] as well. This is | 1808 # Remove these files from actions[ACTION_MERGE] as well. This is |
1808 # important because in recordupdates, files in actions[ACTION_MERGE] | 1809 # important because in recordupdates, files in actions[ACTION_MERGE] |
1809 # are processed after files in other actions, and the merge driver | 1810 # are processed after files in other actions, and the merge driver |
1810 # might add files to those actions via extraactions above. This can | 1811 # might add files to those actions via extraactions above. This can |
1811 # lead to a file being recorded twice, with poor results. This is | 1812 # lead to a file being recorded twice, with poor results. This is |
1871 # keep | 1872 # keep |
1872 for f, args, msg in actions.get(ACTION_KEEP, []): | 1873 for f, args, msg in actions.get(ACTION_KEEP, []): |
1873 pass | 1874 pass |
1874 | 1875 |
1875 # get | 1876 # get |
1876 for i, (f, args, msg) in enumerate(actions.get(ACTION_GET, [])): | 1877 for f, args, msg in actions.get(ACTION_GET, []): |
1877 if branchmerge: | 1878 if branchmerge: |
1878 repo.dirstate.otherparent(f) | 1879 repo.dirstate.otherparent(f) |
1879 else: | 1880 else: |
1880 parentfiledata = getfiledata[i] if getfiledata else None | 1881 parentfiledata = getfiledata[f] if getfiledata else None |
1881 repo.dirstate.normal(f, parentfiledata=parentfiledata) | 1882 repo.dirstate.normal(f, parentfiledata=parentfiledata) |
1882 | 1883 |
1883 # merge | 1884 # merge |
1884 for f, args, msg in actions.get(ACTION_MERGE, []): | 1885 for f, args, msg in actions.get(ACTION_MERGE, []): |
1885 f1, f2, fa, move, anc = args | 1886 f1, f2, fa, move, anc = args |