Show More
@@ -1759,19 +1759,30 b' class workingctx(committablectx):' | |||||
1759 | # update dirstate for files that are actually clean |
|
1759 | # update dirstate for files that are actually clean | |
1760 | if fixup: |
|
1760 | if fixup: | |
1761 | try: |
|
1761 | try: | |
|
1762 | oldid = self._repo.dirstate.identity() | |||
|
1763 | ||||
1762 | # updating the dirstate is optional |
|
1764 | # updating the dirstate is optional | |
1763 | # so we don't wait on the lock |
|
1765 | # so we don't wait on the lock | |
1764 | # wlock can invalidate the dirstate, so cache normal _after_ |
|
1766 | # wlock can invalidate the dirstate, so cache normal _after_ | |
1765 | # taking the lock |
|
1767 | # taking the lock | |
1766 | with self._repo.wlock(False): |
|
1768 | with self._repo.wlock(False): | |
1767 |
|
|
1769 | if self._repo.dirstate.identity() == oldid: | |
1768 | for f in fixup: |
|
1770 | normal = self._repo.dirstate.normal | |
1769 |
|
|
1771 | for f in fixup: | |
1770 | # write changes out explicitly, because nesting |
|
1772 | normal(f) | |
1771 | # wlock at runtime may prevent 'wlock.release()' |
|
1773 | # write changes out explicitly, because nesting | |
1772 | # after this block from doing so for subsequent |
|
1774 | # wlock at runtime may prevent 'wlock.release()' | |
1773 | # changing files |
|
1775 | # after this block from doing so for subsequent | |
1774 | self._repo.dirstate.write(self._repo.currenttransaction()) |
|
1776 | # changing files | |
|
1777 | tr = self._repo.currenttransaction() | |||
|
1778 | self._repo.dirstate.write(tr) | |||
|
1779 | else: | |||
|
1780 | # in this case, writing changes out breaks | |||
|
1781 | # consistency, because .hg/dirstate was | |||
|
1782 | # already changed simultaneously after last | |||
|
1783 | # caching (see also issue5584 for detail) | |||
|
1784 | self._repo.ui.debug('skip updating dirstate: ' | |||
|
1785 | 'identity mismatch\n') | |||
1775 | except error.LockError: |
|
1786 | except error.LockError: | |
1776 | pass |
|
1787 | pass | |
1777 | return modified, deleted, fixup |
|
1788 | return modified, deleted, fixup |
@@ -95,3 +95,65 b' anyway.' | |||||
95 | ! d |
|
95 | ! d | |
96 | ! dir1/c |
|
96 | ! dir1/c | |
97 | ! e |
|
97 | ! e | |
|
98 | ||||
|
99 | $ rmdir d e | |||
|
100 | $ hg update -C -q . | |||
|
101 | ||||
|
102 | Test that dirstate changes aren't written out at the end of "hg | |||
|
103 | status", if .hg/dirstate is already changed simultaneously before | |||
|
104 | acquisition of wlock in workingctx._checklookup(). | |||
|
105 | ||||
|
106 | This avoidance is important to keep consistency of dirstate in race | |||
|
107 | condition (see issue5584 for detail). | |||
|
108 | ||||
|
109 | $ hg parents -q | |||
|
110 | 1:* (glob) | |||
|
111 | ||||
|
112 | $ hg debugrebuilddirstate | |||
|
113 | $ hg debugdirstate | |||
|
114 | n 0 -1 unset a | |||
|
115 | n 0 -1 unset b | |||
|
116 | n 0 -1 unset d | |||
|
117 | n 0 -1 unset dir1/c | |||
|
118 | n 0 -1 unset e | |||
|
119 | ||||
|
120 | $ cat > $TESTTMP/dirstaterace.sh <<EOF | |||
|
121 | > # This script assumes timetable of typical issue5584 case below: | |||
|
122 | > # | |||
|
123 | > # 1. "hg status" loads .hg/dirstate | |||
|
124 | > # 2. "hg status" confirms clean-ness of FILE | |||
|
125 | > # 3. "hg update -C 0" updates the working directory simultaneously | |||
|
126 | > # (FILE is removed, and FILE is dropped from .hg/dirstate) | |||
|
127 | > # 4. "hg status" acquires wlock | |||
|
128 | > # (.hg/dirstate is re-loaded = no FILE entry in dirstate) | |||
|
129 | > # 5. "hg status" marks FILE in dirstate as clean | |||
|
130 | > # (FILE entry is added to in-memory dirstate) | |||
|
131 | > # 6. "hg status" writes dirstate changes into .hg/dirstate | |||
|
132 | > # (FILE entry is written into .hg/dirstate) | |||
|
133 | > # | |||
|
134 | > # To reproduce similar situation easily and certainly, #2 and #3 | |||
|
135 | > # are swapped. "hg cat" below ensures #2 on "hg status" side. | |||
|
136 | > | |||
|
137 | > hg update -q -C 0 | |||
|
138 | > hg cat -r 1 b > b | |||
|
139 | > EOF | |||
|
140 | ||||
|
141 | "hg status" below should excludes "e", of which exec flag is set, for | |||
|
142 | portability of test scenario, because unsure but missing "e" is | |||
|
143 | treated differently in _checklookup() according to runtime platform. | |||
|
144 | ||||
|
145 | - "missing(!)" on POSIX, "pctx[f].cmp(self[f])" raises ENOENT | |||
|
146 | - "modified(M)" on Windows, "self.flags(f) != pctx.flags(f)" is True | |||
|
147 | ||||
|
148 | $ hg status --config extensions.dirstaterace=$TESTTMP/dirstaterace.py --debug -X path:e | |||
|
149 | skip updating dirstate: identity mismatch | |||
|
150 | M a | |||
|
151 | ! d | |||
|
152 | ! dir1/c | |||
|
153 | ||||
|
154 | $ hg parents -q | |||
|
155 | 0:* (glob) | |||
|
156 | $ hg files | |||
|
157 | a | |||
|
158 | $ hg debugdirstate | |||
|
159 | n * * * a (glob) |
General Comments 0
You need to be logged in to leave comments.
Login now