##// END OF EJS Templates
merge with stable
Martin von Zweigbergk -
r42712:84aff7e2 merge default
parent child Browse files
Show More
@@ -365,6 +365,11 b' class bundlerepository(object):'
365 self.manstart = self._cgunpacker.tell()
365 self.manstart = self._cgunpacker.tell()
366 return c
366 return c
367
367
368 def _refreshchangelog(self):
369 # changelog for bundle repo are not filecache, this method is not
370 # applicable.
371 pass
372
368 @localrepo.unfilteredpropertycache
373 @localrepo.unfilteredpropertycache
369 def manifestlog(self):
374 def manifestlog(self):
370 self._cgunpacker.seek(self.manstart)
375 self._cgunpacker.seek(self.manstart)
@@ -1227,8 +1227,62 b' class localrepository(object):'
1227 @mixedrepostorecache(('bookmarks', 'plain'), ('bookmarks.current', 'plain'),
1227 @mixedrepostorecache(('bookmarks', 'plain'), ('bookmarks.current', 'plain'),
1228 ('bookmarks', ''), ('00changelog.i', ''))
1228 ('bookmarks', ''), ('00changelog.i', ''))
1229 def _bookmarks(self):
1229 def _bookmarks(self):
1230 # Since the multiple files involved in the transaction cannot be
1231 # written atomically (with current repository format), there is a race
1232 # condition here.
1233 #
1234 # 1) changelog content A is read
1235 # 2) outside transaction update changelog to content B
1236 # 3) outside transaction update bookmark file referring to content B
1237 # 4) bookmarks file content is read and filtered against changelog-A
1238 #
1239 # When this happens, bookmarks against nodes missing from A are dropped.
1240 #
1241 # Having this happening during read is not great, but it become worse
1242 # when this happen during write because the bookmarks to the "unknown"
1243 # nodes will be dropped for good. However, writes happen within locks.
1244 # This locking makes it possible to have a race free consistent read.
1245 # For this purpose data read from disc before locking are
1246 # "invalidated" right after the locks are taken. This invalidations are
1247 # "light", the `filecache` mechanism keep the data in memory and will
1248 # reuse them if the underlying files did not changed. Not parsing the
1249 # same data multiple times helps performances.
1250 #
1251 # Unfortunately in the case describe above, the files tracked by the
1252 # bookmarks file cache might not have changed, but the in-memory
1253 # content is still "wrong" because we used an older changelog content
1254 # to process the on-disk data. So after locking, the changelog would be
1255 # refreshed but `_bookmarks` would be preserved.
1256 # Adding `00changelog.i` to the list of tracked file is not
1257 # enough, because at the time we build the content for `_bookmarks` in
1258 # (4), the changelog file has already diverged from the content used
1259 # for loading `changelog` in (1)
1260 #
1261 # To prevent the issue, we force the changelog to be explicitly
1262 # reloaded while computing `_bookmarks`. The data race can still happen
1263 # without the lock (with a narrower window), but it would no longer go
1264 # undetected during the lock time refresh.
1265 #
1266 # The new schedule is as follow
1267 #
1268 # 1) filecache logic detect that `_bookmarks` needs to be computed
1269 # 2) cachestat for `bookmarks` and `changelog` are captured (for book)
1270 # 3) We force `changelog` filecache to be tested
1271 # 4) cachestat for `changelog` are captured (for changelog)
1272 # 5) `_bookmarks` is computed and cached
1273 #
1274 # The step in (3) ensure we have a changelog at least as recent as the
1275 # cache stat computed in (1). As a result at locking time:
1276 # * if the changelog did not changed since (1) -> we can reuse the data
1277 # * otherwise -> the bookmarks get refreshed.
1278 self._refreshchangelog()
1230 return bookmarks.bmstore(self)
1279 return bookmarks.bmstore(self)
1231
1280
1281 def _refreshchangelog(self):
1282 """make sure the in memory changelog match the on-disk one"""
1283 if ('changelog' in vars(self) and self.currenttransaction() is None):
1284 del self.changelog
1285
1232 @property
1286 @property
1233 def _activebookmark(self):
1287 def _activebookmark(self):
1234 return self._bookmarks.active
1288 return self._bookmarks.active
@@ -1748,7 +1748,8 b' class TTest(Test):'
1748
1748
1749 el = m.group(1) + b"\n"
1749 el = m.group(1) + b"\n"
1750 if not self._iftest(conditions):
1750 if not self._iftest(conditions):
1751 retry = "retry" # Not required by listed features
1751 # listed feature missing, should not match
1752 return "retry", False
1752
1753
1753 if el.endswith(b" (esc)\n"):
1754 if el.endswith(b" (esc)\n"):
1754 if PYTHON3:
1755 if PYTHON3:
@@ -119,9 +119,13 b' We build a server side extension for thi'
119 > import atexit
119 > import atexit
120 > import os
120 > import os
121 > import time
121 > import time
122 > from mercurial import bookmarks, error, extensions
122 > import atexit
123 > def wrapinit(orig, self, repo):
123 > from mercurial import error, extensions, bookmarks
124 >
125 > def wait(repo):
124 > if not os.path.exists('push-A-started'):
126 > if not os.path.exists('push-A-started'):
127 > assert repo._currentlock(repo._lockref) is None
128 > assert repo._currentlock(repo._wlockref) is None
125 > repo.ui.status(b'setting raced push up\n')
129 > repo.ui.status(b'setting raced push up\n')
126 > with open('push-A-started', 'w'):
130 > with open('push-A-started', 'w'):
127 > pass
131 > pass
@@ -131,11 +135,15 b' We build a server side extension for thi'
131 > if clock <= 0:
135 > if clock <= 0:
132 > raise error.Abort("race scenario timed out")
136 > raise error.Abort("race scenario timed out")
133 > time.sleep(0.1)
137 > time.sleep(0.1)
134 > return orig(self, repo)
135 >
138 >
139 > def reposetup(ui, repo):
140 > class racedrepo(repo.__class__):
141 > @property
142 > def _bookmarks(self):
143 > wait(self)
144 > return super(racedrepo, self)._bookmarks
136 > repo.__class__ = racedrepo
145 > repo.__class__ = racedrepo
137 > def uisetup(ui):
146 >
138 > extensions.wrapfunction(bookmarks.bmstore, '__init__', wrapinit)
139 > def e():
147 > def e():
140 > with open('push-A-done', 'w'):
148 > with open('push-A-done', 'w'):
141 > pass
149 > pass
@@ -193,6 +201,7 b' Check raced push output.'
193 $ cat push-output.txt
201 $ cat push-output.txt
194 pushing to ssh://user@dummy/bookrace-server
202 pushing to ssh://user@dummy/bookrace-server
195 searching for changes
203 searching for changes
204 remote has heads on branch 'default' that are not known locally: f26c3b5167d1
196 remote: setting raced push up
205 remote: setting raced push up
197 remote: adding changesets
206 remote: adding changesets
198 remote: adding manifests
207 remote: adding manifests
@@ -501,6 +501,7 b' Try merging the other direction too'
501 $ hg debugpathcopies 0 4
501 $ hg debugpathcopies 0 4
502 x -> z (filelog !)
502 x -> z (filelog !)
503 y -> z (compatibility !)
503 y -> z (compatibility !)
504 y -> z (changeset !)
504 $ hg debugpathcopies 1 5
505 $ hg debugpathcopies 1 5
505 y -> z (no-filelog !)
506 y -> z (no-filelog !)
506 $ hg debugpathcopies 2 5
507 $ hg debugpathcopies 2 5
@@ -84,8 +84,8 b' Test basic extension support'
84 uipopulate called (1 times)
84 uipopulate called (1 times)
85 uipopulate called (1 times) (chg !)
85 uipopulate called (1 times) (chg !)
86 uipopulate called (1 times) (chg !)
86 uipopulate called (1 times) (chg !)
87 uipopulate called (1 times) (chg !)
87 uipopulate called (1 times)
88 reposetup called for a (chg !)
88 reposetup called for a
89 ui == repo.ui
89 ui == repo.ui
90 Foo
90 Foo
91 $ hg foo --debug
91 $ hg foo --debug
@@ -96,8 +96,8 b' Test basic extension support'
96 uipopulate called (1 times)
96 uipopulate called (1 times)
97 uipopulate called (1 times) (chg !)
97 uipopulate called (1 times) (chg !)
98 uipopulate called (1 times) (chg !)
98 uipopulate called (1 times) (chg !)
99 uipopulate called (1 times) (chg !)
99 uipopulate called (1 times)
100 reposetup called for a (chg !)
100 reposetup called for a
101 ui == repo.ui
101 ui == repo.ui
102 Foo
102 Foo
103
103
@@ -107,7 +107,7 b' Test basic extension support'
107 uisetup called [status] (no-chg !)
107 uisetup called [status] (no-chg !)
108 uipopulate called (1 times)
108 uipopulate called (1 times)
109 uipopulate called (1 times) (chg !)
109 uipopulate called (1 times) (chg !)
110 uipopulate called (1 times) (chg !)
110 uipopulate called (1 times)
111 reposetup called for a
111 reposetup called for a
112 ui == repo.ui
112 ui == repo.ui
113 uipopulate called (1 times)
113 uipopulate called (1 times)
@@ -61,8 +61,10 b' Cloning a specific file when stream clon'
61 Making sure we have the correct set of requirements
61 Making sure we have the correct set of requirements
62
62
63 $ cat .hg/requires
63 $ cat .hg/requires
64 dotencode (tree flat-fncache !)
64 dotencode (tree !)
65 fncache (tree flat-fncache !)
65 dotencode (flat-fncache !)
66 fncache (tree !)
67 fncache (flat-fncache !)
66 generaldelta
68 generaldelta
67 narrowhg-experimental
69 narrowhg-experimental
68 revlogv1
70 revlogv1
@@ -75,8 +77,9 b' Making sure store has the required files'
75 $ ls .hg/store/
77 $ ls .hg/store/
76 00changelog.i
78 00changelog.i
77 00manifest.i
79 00manifest.i
78 data (tree flat-fncache !)
80 data
79 fncache (tree flat-fncache !)
81 fncache (tree !)
82 fncache (flat-fncache !)
80 meta (tree !)
83 meta (tree !)
81 narrowspec
84 narrowspec
82 undo
85 undo
@@ -124,7 +124,7 b' added upstream revisions.'
124 adding manifests
124 adding manifests
125 adding widest/ revisions (tree !)
125 adding widest/ revisions (tree !)
126 adding file changes
126 adding file changes
127 adding widest/f revisions (tree !)
127 adding widest/f revisions
128 added 0 changesets with 1 changes to 1 files
128 added 0 changesets with 1 changes to 1 files
129 bundle2-input-part: total payload size * (glob)
129 bundle2-input-part: total payload size * (glob)
130 bundle2-input-bundle: 0 parts total
130 bundle2-input-bundle: 0 parts total
@@ -1936,3 +1936,70 b' Test automatic pattern replacement'
1936 running 1 tests using 1 parallel processes
1936 running 1 tests using 1 parallel processes
1937 .
1937 .
1938 # Ran 1 tests, 0 skipped, 0 failed.
1938 # Ran 1 tests, 0 skipped, 0 failed.
1939
1940 Test conditional output matching
1941 ================================
1942
1943 $ cat << EOF >> test-conditional-matching.t
1944 > #testcases foo bar
1945 > $ echo richtig
1946 > richtig (true !)
1947 > $ echo falsch
1948 > falsch (false !)
1949 > #if foo
1950 > $ echo arthur
1951 > arthur (bar !)
1952 > #endif
1953 > $ echo celeste
1954 > celeste (foo !)
1955 > $ echo zephir
1956 > zephir (bar !)
1957 > EOF
1958
1959 $ rt test-conditional-matching.t
1960 running 2 tests using 1 parallel processes
1961
1962 --- $TESTTMP/anothertests/cases/test-conditional-matching.t
1963 +++ $TESTTMP/anothertests/cases/test-conditional-matching.t#bar.err
1964 @@ -3,11 +3,13 @@
1965 richtig (true !)
1966 $ echo falsch
1967 falsch (false !)
1968 + falsch
1969 #if foo
1970 $ echo arthur
1971 arthur \(bar !\) (re)
1972 #endif
1973 $ echo celeste
1974 celeste \(foo !\) (re)
1975 + celeste
1976 $ echo zephir
1977 zephir \(bar !\) (re)
1978
1979 ERROR: test-conditional-matching.t#bar output changed
1980 !
1981 --- $TESTTMP/anothertests/cases/test-conditional-matching.t
1982 +++ $TESTTMP/anothertests/cases/test-conditional-matching.t#foo.err
1983 @@ -3,11 +3,14 @@
1984 richtig (true !)
1985 $ echo falsch
1986 falsch (false !)
1987 + falsch
1988 #if foo
1989 $ echo arthur
1990 arthur \(bar !\) (re)
1991 + arthur
1992 #endif
1993 $ echo celeste
1994 celeste \(foo !\) (re)
1995 $ echo zephir
1996 zephir \(bar !\) (re)
1997 + zephir
1998
1999 ERROR: test-conditional-matching.t#foo output changed
2000 !
2001 Failed test-conditional-matching.t#bar: output changed
2002 Failed test-conditional-matching.t#foo: output changed
2003 # Ran 2 tests, 0 skipped, 2 failed.
2004 python hash seed: * (glob)
2005 [1]
General Comments 0
You need to be logged in to leave comments. Login now