Mercurial > hg
annotate mercurial/transaction.py @ 6858:8f256bf98219
Add support for multiple possible bisect results (issue1228, issue1182)
The real reason for both issue is that bisect can not handle cases where there
are multiple possibilities for the result.
Example (from issue1228):
rev 0 -> good
rev 1 -> skipped
rev 2 -> skipped
rev 3 -> skipped
rev 4 -> bad
Note that this patch does not only fix the reported Assertion Error but also
the problem of a non converging bisect:
hg init
for i in `seq 3`; do echo $i > $i; hg add $i; hg ci -m$i; done
hg bisect -b 2
hg bisect -g 0
hg bisect -s
From this state on, you can:
a) mark as bad forever (non converging!)
b) mark as good to get an inconsistent state
c) skip for the Assertion Error
Minor description and code edits by pmezard.
author | Bernhard Leiner <bleiner@gmail.com> |
---|---|
date | Sat, 02 Aug 2008 22:10:10 +0200 |
parents | 53ed9b40cfc4 |
children | c9b8f2820bc0 |
rev | line source |
---|---|
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
1 # transaction.py - simple journalling scheme for mercurial |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
2 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
3 # This transaction scheme is intended to gracefully handle program |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
4 # errors and interruptions. More serious failures like system crashes |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
5 # can be recovered with an fsck-like tool. As the whole repository is |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
6 # effectively log-structured, this should amount to simply truncating |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
7 # anything that isn't referenced in the changelog. |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
8 # |
2859 | 9 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
10 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
11 # This software may be used and distributed according to the terms |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
12 # of the GNU General Public License, incorporated herein by reference. |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
13 |
3891 | 14 from i18n import _ |
3877
abaee83ce0a6
Replace demandload with new demandimport
Matt Mackall <mpm@selenic.com>
parents:
2859
diff
changeset
|
15 import os |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
16 |
1559
59b3639df0a9
Convert all classes to new-style classes by deriving them from object.
Eric Hopper <hopper@omnifarious.org>
parents:
1541
diff
changeset
|
17 class transaction(object): |
6065
53ed9b40cfc4
make the journal/undo files from transactions inherit the mode from .hg/store
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
5865
diff
changeset
|
18 def __init__(self, report, opener, journal, after=None, createmode=None): |
162 | 19 self.journal = None |
20 | |
1806
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
21 self.count = 1 |
582 | 22 self.report = report |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
23 self.opener = opener |
95 | 24 self.after = after |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
25 self.entries = [] |
42
91f1fa847158
Fix multiple changes to file per transaction
mpm@selenic.com
parents:
13
diff
changeset
|
26 self.map = {} |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
27 self.journal = journal |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
28 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
29 self.file = open(self.journal, "w") |
6065
53ed9b40cfc4
make the journal/undo files from transactions inherit the mode from .hg/store
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
5865
diff
changeset
|
30 if createmode is not None: |
53ed9b40cfc4
make the journal/undo files from transactions inherit the mode from .hg/store
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
5865
diff
changeset
|
31 os.chmod(self.journal, createmode & 0666) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
32 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
33 def __del__(self): |
558
0ceea19182a9
transaction: __del__ should do nothing if the journal already exists
mpm@selenic.com
parents:
515
diff
changeset
|
34 if self.journal: |
0ceea19182a9
transaction: __del__ should do nothing if the journal already exists
mpm@selenic.com
parents:
515
diff
changeset
|
35 if self.entries: self.abort() |
0ceea19182a9
transaction: __del__ should do nothing if the journal already exists
mpm@selenic.com
parents:
515
diff
changeset
|
36 self.file.close() |
0ceea19182a9
transaction: __del__ should do nothing if the journal already exists
mpm@selenic.com
parents:
515
diff
changeset
|
37 try: os.unlink(self.journal) |
0ceea19182a9
transaction: __del__ should do nothing if the journal already exists
mpm@selenic.com
parents:
515
diff
changeset
|
38 except: pass |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
39 |
2084 | 40 def add(self, file, offset, data=None): |
42
91f1fa847158
Fix multiple changes to file per transaction
mpm@selenic.com
parents:
13
diff
changeset
|
41 if file in self.map: return |
2084 | 42 self.entries.append((file, offset, data)) |
43 self.map[file] = len(self.entries) - 1 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
44 # add enough data to the journal to do the truncate |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
45 self.file.write("%s\0%d\n" % (file, offset)) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
46 self.file.flush() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
47 |
2084 | 48 def find(self, file): |
49 if file in self.map: | |
50 return self.entries[self.map[file]] | |
51 return None | |
52 | |
53 def replace(self, file, offset, data=None): | |
54 if file not in self.map: | |
55 raise KeyError(file) | |
56 index = self.map[file] | |
57 self.entries[index] = (file, offset, data) | |
58 self.file.write("%s\0%d\n" % (file, offset)) | |
59 self.file.flush() | |
60 | |
1806
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
61 def nest(self): |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
62 self.count += 1 |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
63 return self |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
64 |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
65 def running(self): |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
66 return self.count > 0 |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
67 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
68 def close(self): |
1806
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
69 self.count -= 1 |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
70 if self.count != 0: |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
71 return |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
72 self.file.close() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
73 self.entries = [] |
95 | 74 if self.after: |
785 | 75 self.after() |
95 | 76 else: |
77 os.unlink(self.journal) | |
573 | 78 self.journal = None |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
79 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
80 def abort(self): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
81 if not self.entries: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
82 |
1402
9d2c2e6b32b5
i18n part2: use '_' for all strings who are part of the user interface
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1400
diff
changeset
|
83 self.report(_("transaction abort!\n")) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
84 |
2084 | 85 for f, o, ignore in self.entries: |
108 | 86 try: |
87 self.opener(f, "a").truncate(o) | |
88 except: | |
1402
9d2c2e6b32b5
i18n part2: use '_' for all strings who are part of the user interface
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1400
diff
changeset
|
89 self.report(_("failed to truncate %s\n") % f) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
90 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
91 self.entries = [] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
92 |
1402
9d2c2e6b32b5
i18n part2: use '_' for all strings who are part of the user interface
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
1400
diff
changeset
|
93 self.report(_("rollback completed\n")) |
515 | 94 |
162 | 95 def rollback(opener, file): |
2084 | 96 files = {} |
162 | 97 for l in open(file).readlines(): |
98 f, o = l.split('\0') | |
2084 | 99 files[f] = o |
100 for f in files: | |
101 o = files[f] | |
162 | 102 opener(f, "a").truncate(int(o)) |
103 os.unlink(file) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
104 |