Merge lp:~spiv/bzr/debug-flag-relock into lp:bzr
- debug-flag-relock
- Merge into bzr.dev
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~spiv/bzr/debug-flag-relock |
Merge into: | lp:bzr |
Diff against target: |
231 lines 7 files modified
NEWS (+4/-0) bzrlib/branch.py (+6/-1) bzrlib/help_topics/en/debug-flags.txt (+5/-3) bzrlib/lock.py (+21/-0) bzrlib/remote.py (+6/-2) bzrlib/repofmt/pack_repo.py (+7/-0) bzrlib/repository.py (+4/-1) |
To merge this branch: | bzr merge lp:~spiv/bzr/debug-flag-relock |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Pool | Approve | ||
John A Meinel | Approve | ||
Vincent Ladeuil | Pending | ||
Review via email: mp+12972@code.launchpad.net |
This proposal supersedes a proposal from 2009-10-07.
Commit message
Description of the change
Andrew Bennetts (spiv) wrote : Posted in a previous version of this proposal | # |
Martin Pool (mbp) wrote : Posted in a previous version of this proposal | # |
That sounds good.
I think note() may not be the best interface to call because the ui
changes turn it into something more like "display a message to the
user" and you wouldn't want popup dialogs for each hit. But maybe
that's the best one for now and I can change it later.
So I think it's actually an idea for me to add a kind of 'loud mutter'
rather than a change for you.
The duplication is ugly though - I think you should put this into a
(possibly mixed in) base class.
--
Martin <http://
Vincent Ladeuil (vila) wrote : Posted in a previous version of this proposal | # |
More a tweak really.
You lost your 'manner' for --strict-locks in reordering the help messages.
Andrew Bennetts (spiv) wrote : | # |
I've removed the duplication with a mixin, and fixed the 'manner' glitch in debug-flags.txt.
p.s.:
$ ./bzr -Drelock push
BzrBranch7(
CHKInventoryRep
BzrBranch7(
CHKInventoryRep
Using saved push location: lp:~spiv/bzr/debug-flag-relock
BzrBranch7(
CHKInventoryRep
Pushed up to revision 4734.
HPSS calls: 23 (2 vfs) SmartSSHClientM
John A Meinel (jameinel) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Andrew Bennetts wrote:
> Andrew Bennetts has proposed merging lp:~spiv/bzr/debug-flag-relock into lp:bzr.
>
> Requested reviews:
> Martin Pool (mbp):
> Vincent Ladeuil (vila)
>
>
So do I understand correctly that this is only triggered when an object
*loses* the lock and then re-acquires it?
So doing:
foo.lock_read()
foo.lock_read()
foo.unlock()
foo.unlock()
would not trigger it, but
foo.lock_read()
foo.unlock()
foo.lock_read()
foo.unlock()
would.
I agree that we should probably have a hook, or some sort of mechanism
for testing this, as it is worthwhile to test. Perhaps you could have a
global state in "lock" like our "symbol_
review: approve
Subject to Martin/Vincent's vote, since they reviewed first.
John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAkr
odkAoIaGHnfDPa0
=UHav
-----END PGP SIGNATURE-----
Andrew Bennetts (spiv) wrote : | # |
John A Meinel wrote:
[...]
> So doing:
>
> foo.lock_read()
> foo.lock_read()
> foo.unlock()
> foo.unlock()
>
> would not trigger it, but
>
> foo.lock_read()
> foo.unlock()
> foo.lock_read()
> foo.unlock()
>
> would.
That's correct.
> I agree that we should probably have a hook, or some sort of mechanism
> for testing this, as it is worthwhile to test. Perhaps you could have a
> global state in "lock" like our "symbol_
You mean so that tests can assert “X was locked once”, rather than so that
we can test this debug flag? I think that would be nice, but it's probably
best to let whoever writes the first test along those lines (quite possibly
me!) do that refactoring. i.e. I think it's easy to add this sort of thing
later, and that it is best to add this sort of thing when it will actually
be used so we know we got the API right.
-Andrew.
Martin Pool (mbp) : | # |
Preview Diff
1 | === modified file 'NEWS' | |||
2 | --- NEWS 2009-10-08 16:15:00 +0000 | |||
3 | +++ NEWS 2009-10-08 22:56:11 +0000 | |||
4 | @@ -202,6 +202,10 @@ | |||
5 | 202 | Internals | 202 | Internals |
6 | 203 | ********* | 203 | ********* |
7 | 204 | 204 | ||
8 | 205 | * Added ``-Drelock`` debug flag. It will ``note`` a message every time a | ||
9 | 206 | repository or branch object is unlocked then relocked the same way. | ||
10 | 207 | (Andrew Bennetts) | ||
11 | 208 | |||
12 | 205 | * ``BTreeLeafParser.extract_key`` has been tweaked slightly to reduce | 209 | * ``BTreeLeafParser.extract_key`` has been tweaked slightly to reduce |
13 | 206 | mallocs while parsing the index (approx 3=>1 mallocs per key read). | 210 | mallocs while parsing the index (approx 3=>1 mallocs per key read). |
14 | 207 | This results in a 10% speedup while reading an index. | 211 | This results in a 10% speedup while reading an index. |
15 | 208 | 212 | ||
16 | === modified file 'bzrlib/branch.py' | |||
17 | --- bzrlib/branch.py 2009-09-30 07:02:41 +0000 | |||
18 | +++ bzrlib/branch.py 2009-10-08 22:56:11 +0000 | |||
19 | @@ -49,6 +49,7 @@ | |||
20 | 49 | from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises | 49 | from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises |
21 | 50 | from bzrlib.hooks import HookPoint, Hooks | 50 | from bzrlib.hooks import HookPoint, Hooks |
22 | 51 | from bzrlib.inter import InterObject | 51 | from bzrlib.inter import InterObject |
23 | 52 | from bzrlib.lock import _RelockDebugMixin | ||
24 | 52 | from bzrlib import registry | 53 | from bzrlib import registry |
25 | 53 | from bzrlib.symbol_versioning import ( | 54 | from bzrlib.symbol_versioning import ( |
26 | 54 | deprecated_in, | 55 | deprecated_in, |
27 | @@ -2079,7 +2080,7 @@ | |||
28 | 2079 | _legacy_formats[0].network_name(), _legacy_formats[0].__class__) | 2080 | _legacy_formats[0].network_name(), _legacy_formats[0].__class__) |
29 | 2080 | 2081 | ||
30 | 2081 | 2082 | ||
32 | 2082 | class BzrBranch(Branch): | 2083 | class BzrBranch(Branch, _RelockDebugMixin): |
33 | 2083 | """A branch stored in the actual filesystem. | 2084 | """A branch stored in the actual filesystem. |
34 | 2084 | 2085 | ||
35 | 2085 | Note that it's "local" in the context of the filesystem; it doesn't | 2086 | Note that it's "local" in the context of the filesystem; it doesn't |
36 | @@ -2131,6 +2132,8 @@ | |||
37 | 2131 | return self.control_files.is_locked() | 2132 | return self.control_files.is_locked() |
38 | 2132 | 2133 | ||
39 | 2133 | def lock_write(self, token=None): | 2134 | def lock_write(self, token=None): |
40 | 2135 | if not self.is_locked(): | ||
41 | 2136 | self._note_lock('w') | ||
42 | 2134 | # All-in-one needs to always unlock/lock. | 2137 | # All-in-one needs to always unlock/lock. |
43 | 2135 | repo_control = getattr(self.repository, 'control_files', None) | 2138 | repo_control = getattr(self.repository, 'control_files', None) |
44 | 2136 | if self.control_files == repo_control or not self.is_locked(): | 2139 | if self.control_files == repo_control or not self.is_locked(): |
45 | @@ -2146,6 +2149,8 @@ | |||
46 | 2146 | raise | 2149 | raise |
47 | 2147 | 2150 | ||
48 | 2148 | def lock_read(self): | 2151 | def lock_read(self): |
49 | 2152 | if not self.is_locked(): | ||
50 | 2153 | self._note_lock('r') | ||
51 | 2149 | # All-in-one needs to always unlock/lock. | 2154 | # All-in-one needs to always unlock/lock. |
52 | 2150 | repo_control = getattr(self.repository, 'control_files', None) | 2155 | repo_control = getattr(self.repository, 'control_files', None) |
53 | 2151 | if self.control_files == repo_control or not self.is_locked(): | 2156 | if self.control_files == repo_control or not self.is_locked(): |
54 | 2152 | 2157 | ||
55 | === modified file 'bzrlib/help_topics/en/debug-flags.txt' | |||
56 | --- bzrlib/help_topics/en/debug-flags.txt 2009-08-20 05:02:45 +0000 | |||
57 | +++ bzrlib/help_topics/en/debug-flags.txt 2009-10-08 22:56:11 +0000 | |||
58 | @@ -22,16 +22,18 @@ | |||
59 | 22 | -Dhttp Trace http connections, requests and responses. | 22 | -Dhttp Trace http connections, requests and responses. |
60 | 23 | -Dindex Trace major index operations. | 23 | -Dindex Trace major index operations. |
61 | 24 | -Dknit Trace knit operations. | 24 | -Dknit Trace knit operations. |
62 | 25 | -Dstrict_locks Trace when OS locks are potentially used in a non-portable | ||
63 | 26 | manner. | ||
64 | 27 | -Dlock Trace when lockdir locks are taken or released. | 25 | -Dlock Trace when lockdir locks are taken or released. |
65 | 28 | -Dprogress Trace progress bar operations. | 26 | -Dprogress Trace progress bar operations. |
66 | 29 | -Dmerge Emit information for debugging merges. | 27 | -Dmerge Emit information for debugging merges. |
67 | 30 | -Dno_apport Don't use apport to report crashes. | 28 | -Dno_apport Don't use apport to report crashes. |
68 | 31 | -Dunlock Some errors during unlock are treated as warnings. | ||
69 | 32 | -Dpack Emit information about pack operations. | 29 | -Dpack Emit information about pack operations. |
70 | 30 | -Drelock Emit a message every time a branch or repository object is | ||
71 | 31 | unlocked then relocked the same way. | ||
72 | 33 | -Dsftp Trace SFTP internals. | 32 | -Dsftp Trace SFTP internals. |
73 | 34 | -Dstream Trace fetch streams. | 33 | -Dstream Trace fetch streams. |
74 | 34 | -Dstrict_locks Trace when OS locks are potentially used in a non-portable | ||
75 | 35 | manner. | ||
76 | 36 | -Dunlock Some errors during unlock are treated as warnings. | ||
77 | 35 | -DIDS_never Never use InterDifferingSerializer when fetching. | 37 | -DIDS_never Never use InterDifferingSerializer when fetching. |
78 | 36 | -DIDS_always Always use InterDifferingSerializer to fetch if appropriate | 38 | -DIDS_always Always use InterDifferingSerializer to fetch if appropriate |
79 | 37 | for the format, even for non-local fetches. | 39 | for the format, even for non-local fetches. |
80 | 38 | 40 | ||
81 | === modified file 'bzrlib/lock.py' | |||
82 | --- bzrlib/lock.py 2009-07-31 16:51:48 +0000 | |||
83 | +++ bzrlib/lock.py 2009-10-08 22:56:11 +0000 | |||
84 | @@ -518,3 +518,24 @@ | |||
85 | 518 | # We default to using the first available lock class. | 518 | # We default to using the first available lock class. |
86 | 519 | _lock_type, WriteLock, ReadLock = _lock_classes[0] | 519 | _lock_type, WriteLock, ReadLock = _lock_classes[0] |
87 | 520 | 520 | ||
88 | 521 | |||
89 | 522 | class _RelockDebugMixin(object): | ||
90 | 523 | """Mixin support for -Drelock flag. | ||
91 | 524 | |||
92 | 525 | Add this as a base class then call self._note_lock with 'r' or 'w' when | ||
93 | 526 | acquiring a read- or write-lock. If this object was previously locked (and | ||
94 | 527 | locked the same way), and -Drelock is set, then this will trace.note a | ||
95 | 528 | message about it. | ||
96 | 529 | """ | ||
97 | 530 | |||
98 | 531 | _prev_lock = None | ||
99 | 532 | |||
100 | 533 | def _note_lock(self, lock_type): | ||
101 | 534 | if 'relock' in debug.debug_flags and self._prev_lock == lock_type: | ||
102 | 535 | if lock_type == 'r': | ||
103 | 536 | type_name = 'read' | ||
104 | 537 | else: | ||
105 | 538 | type_name = 'write' | ||
106 | 539 | trace.note('%r was %s locked again', self, type_name) | ||
107 | 540 | self._prev_lock = lock_type | ||
108 | 541 | |||
109 | 521 | 542 | ||
110 | === modified file 'bzrlib/remote.py' | |||
111 | --- bzrlib/remote.py 2009-10-08 01:50:30 +0000 | |||
112 | +++ bzrlib/remote.py 2009-10-08 22:56:11 +0000 | |||
113 | @@ -619,7 +619,7 @@ | |||
114 | 619 | return self._custom_format._serializer | 619 | return self._custom_format._serializer |
115 | 620 | 620 | ||
116 | 621 | 621 | ||
118 | 622 | class RemoteRepository(_RpcHelper): | 622 | class RemoteRepository(_RpcHelper, lock._RelockDebugMixin): |
119 | 623 | """Repository accessed over rpc. | 623 | """Repository accessed over rpc. |
120 | 624 | 624 | ||
121 | 625 | For the moment most operations are performed using local transport-backed | 625 | For the moment most operations are performed using local transport-backed |
122 | @@ -949,6 +949,7 @@ | |||
123 | 949 | def lock_read(self): | 949 | def lock_read(self): |
124 | 950 | # wrong eventually - want a local lock cache context | 950 | # wrong eventually - want a local lock cache context |
125 | 951 | if not self._lock_mode: | 951 | if not self._lock_mode: |
126 | 952 | self._note_lock('r') | ||
127 | 952 | self._lock_mode = 'r' | 953 | self._lock_mode = 'r' |
128 | 953 | self._lock_count = 1 | 954 | self._lock_count = 1 |
129 | 954 | self._unstacked_provider.enable_cache(cache_misses=True) | 955 | self._unstacked_provider.enable_cache(cache_misses=True) |
130 | @@ -974,6 +975,7 @@ | |||
131 | 974 | 975 | ||
132 | 975 | def lock_write(self, token=None, _skip_rpc=False): | 976 | def lock_write(self, token=None, _skip_rpc=False): |
133 | 976 | if not self._lock_mode: | 977 | if not self._lock_mode: |
134 | 978 | self._note_lock('w') | ||
135 | 977 | if _skip_rpc: | 979 | if _skip_rpc: |
136 | 978 | if self._lock_token is not None: | 980 | if self._lock_token is not None: |
137 | 979 | if token != self._lock_token: | 981 | if token != self._lock_token: |
138 | @@ -2082,7 +2084,7 @@ | |||
139 | 2082 | return self._custom_format.supports_set_append_revisions_only() | 2084 | return self._custom_format.supports_set_append_revisions_only() |
140 | 2083 | 2085 | ||
141 | 2084 | 2086 | ||
143 | 2085 | class RemoteBranch(branch.Branch, _RpcHelper): | 2087 | class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin): |
144 | 2086 | """Branch stored on a server accessed by HPSS RPC. | 2088 | """Branch stored on a server accessed by HPSS RPC. |
145 | 2087 | 2089 | ||
146 | 2088 | At the moment most operations are mapped down to simple file operations. | 2090 | At the moment most operations are mapped down to simple file operations. |
147 | @@ -2319,6 +2321,7 @@ | |||
148 | 2319 | def lock_read(self): | 2321 | def lock_read(self): |
149 | 2320 | self.repository.lock_read() | 2322 | self.repository.lock_read() |
150 | 2321 | if not self._lock_mode: | 2323 | if not self._lock_mode: |
151 | 2324 | self._note_lock('r') | ||
152 | 2322 | self._lock_mode = 'r' | 2325 | self._lock_mode = 'r' |
153 | 2323 | self._lock_count = 1 | 2326 | self._lock_count = 1 |
154 | 2324 | if self._real_branch is not None: | 2327 | if self._real_branch is not None: |
155 | @@ -2344,6 +2347,7 @@ | |||
156 | 2344 | 2347 | ||
157 | 2345 | def lock_write(self, token=None): | 2348 | def lock_write(self, token=None): |
158 | 2346 | if not self._lock_mode: | 2349 | if not self._lock_mode: |
159 | 2350 | self._note_lock('w') | ||
160 | 2347 | # Lock the branch and repo in one remote call. | 2351 | # Lock the branch and repo in one remote call. |
161 | 2348 | remote_tokens = self._remote_lock_write(token) | 2352 | remote_tokens = self._remote_lock_write(token) |
162 | 2349 | self._lock_token, self._repo_lock_token = remote_tokens | 2353 | self._lock_token, self._repo_lock_token = remote_tokens |
163 | 2350 | 2354 | ||
164 | === modified file 'bzrlib/repofmt/pack_repo.py' | |||
165 | --- bzrlib/repofmt/pack_repo.py 2009-09-30 07:02:41 +0000 | |||
166 | +++ bzrlib/repofmt/pack_repo.py 2009-10-08 22:56:11 +0000 | |||
167 | @@ -73,6 +73,7 @@ | |||
168 | 73 | ) | 73 | ) |
169 | 74 | from bzrlib.trace import ( | 74 | from bzrlib.trace import ( |
170 | 75 | mutter, | 75 | mutter, |
171 | 76 | note, | ||
172 | 76 | warning, | 77 | warning, |
173 | 77 | ) | 78 | ) |
174 | 78 | 79 | ||
175 | @@ -2300,6 +2301,9 @@ | |||
176 | 2300 | if self._write_lock_count == 1: | 2301 | if self._write_lock_count == 1: |
177 | 2301 | self._transaction = transactions.WriteTransaction() | 2302 | self._transaction = transactions.WriteTransaction() |
178 | 2302 | if not locked: | 2303 | if not locked: |
179 | 2304 | if 'relock' in debug.debug_flags and self._prev_lock == 'w': | ||
180 | 2305 | note('%r was write locked again', self) | ||
181 | 2306 | self._prev_lock = 'w' | ||
182 | 2303 | for repo in self._fallback_repositories: | 2307 | for repo in self._fallback_repositories: |
183 | 2304 | # Writes don't affect fallback repos | 2308 | # Writes don't affect fallback repos |
184 | 2305 | repo.lock_read() | 2309 | repo.lock_read() |
185 | @@ -2312,6 +2316,9 @@ | |||
186 | 2312 | else: | 2316 | else: |
187 | 2313 | self.control_files.lock_read() | 2317 | self.control_files.lock_read() |
188 | 2314 | if not locked: | 2318 | if not locked: |
189 | 2319 | if 'relock' in debug.debug_flags and self._prev_lock == 'r': | ||
190 | 2320 | note('%r was read locked again', self) | ||
191 | 2321 | self._prev_lock = 'r' | ||
192 | 2315 | for repo in self._fallback_repositories: | 2322 | for repo in self._fallback_repositories: |
193 | 2316 | repo.lock_read() | 2323 | repo.lock_read() |
194 | 2317 | self._refresh_data() | 2324 | self._refresh_data() |
195 | 2318 | 2325 | ||
196 | === modified file 'bzrlib/repository.py' | |||
197 | --- bzrlib/repository.py 2009-10-08 01:50:30 +0000 | |||
198 | +++ bzrlib/repository.py 2009-10-08 22:56:11 +0000 | |||
199 | @@ -50,6 +50,7 @@ | |||
200 | 50 | """) | 50 | """) |
201 | 51 | 51 | ||
202 | 52 | from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises | 52 | from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises |
203 | 53 | from bzrlib.lock import _RelockDebugMixin | ||
204 | 53 | from bzrlib.inter import InterObject | 54 | from bzrlib.inter import InterObject |
205 | 54 | from bzrlib.inventory import ( | 55 | from bzrlib.inventory import ( |
206 | 55 | Inventory, | 56 | Inventory, |
207 | @@ -856,7 +857,7 @@ | |||
208 | 856 | # Repositories | 857 | # Repositories |
209 | 857 | 858 | ||
210 | 858 | 859 | ||
212 | 859 | class Repository(object): | 860 | class Repository(_RelockDebugMixin): |
213 | 860 | """Repository holding history for one or more branches. | 861 | """Repository holding history for one or more branches. |
214 | 861 | 862 | ||
215 | 862 | The repository holds and retrieves historical information including | 863 | The repository holds and retrieves historical information including |
216 | @@ -1381,6 +1382,7 @@ | |||
217 | 1381 | locked = self.is_locked() | 1382 | locked = self.is_locked() |
218 | 1382 | result = self.control_files.lock_write(token=token) | 1383 | result = self.control_files.lock_write(token=token) |
219 | 1383 | if not locked: | 1384 | if not locked: |
220 | 1385 | self._note_lock('w') | ||
221 | 1384 | for repo in self._fallback_repositories: | 1386 | for repo in self._fallback_repositories: |
222 | 1385 | # Writes don't affect fallback repos | 1387 | # Writes don't affect fallback repos |
223 | 1386 | repo.lock_read() | 1388 | repo.lock_read() |
224 | @@ -1391,6 +1393,7 @@ | |||
225 | 1391 | locked = self.is_locked() | 1393 | locked = self.is_locked() |
226 | 1392 | self.control_files.lock_read() | 1394 | self.control_files.lock_read() |
227 | 1393 | if not locked: | 1395 | if not locked: |
228 | 1396 | self._note_lock('r') | ||
229 | 1394 | for repo in self._fallback_repositories: | 1397 | for repo in self._fallback_repositories: |
230 | 1395 | repo.lock_read() | 1398 | repo.lock_read() |
231 | 1396 | self._refresh_data() | 1399 | self._refresh_data() |
This is an idea I had while looking at bug 389413. It adds a -Drelock debug flag to make noise about cases where we probably should take more care to just hold one lock rather than locking/ unlocking/ locking- again.
Here's some sample output:
$ ./bzr diff -c 4148 . -Drelock > /dev/null 'file:/ //home/ andrew/ warthogs/ bzr/debug- flag-relock/ ') was read locked again ository( 'file:/ //home/ andrew/ warthogs/ bzr/.bzr/ repository/ ') was read locked again ository( 'file:/ //home/ andrew/ warthogs/ bzr/.bzr/ repository/ ') was read locked again ository( 'file:/ //home/ andrew/ warthogs/ bzr/.bzr/ repository/ ') was read locked again 'file:/ //home/ andrew/ warthogs/ bzr/debug- flag-relock/ ') was read locked again ository( 'file:/ //home/ andrew/ warthogs/ bzr/.bzr/ repository/ ') was read locked again 'file:/ //home/ andrew/ warthogs/ bzr/debug- flag-relock/ ') was read locked again ository( 'file:/ //home/ andrew/ warthogs/ bzr/.bzr/ repository/ ') was read locked again ository( 'file:/ //home/ andrew/ warthogs/ bzr/.bzr/ repository/ ') was read locked again ository( 'file:/ //home/ andrew/ warthogs/ bzr/.bzr/ repository/ ') was read locked again 'file:/ //home/ andrew/ warthogs/ bzr/debug- flag-relock/ ') was read locked again
BzrBranch7(
CHKInventoryRep
CHKInventoryRep
CHKInventoryRep
BzrBranch7(
CHKInventoryRep
BzrBranch7(
CHKInventoryRep
CHKInventoryRep
CHKInventoryRep
BzrBranch7(
Hopefully that gives some idea of how much we can improve :)
Possibly we should have a more generic hook point for lock/unlock operations so that tests can assert "object X is only locked once", similar to the existing HPSS effort tests... but this seems cheap and useful. (The existing hook points for lockdir lock_acquired/ lock_released would only catch lock_write, not lock_read, so they aren't sufficient for this case.)