Mercurial > public > mercurial-scm > hg-stable
annotate mercurial/transaction.py @ 8294:48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
This adds a change to the way that abort is processed, as it will not continue
truncating files beyond the first failure, otherwise the respective
functionality is maintained, i.e. abort will not unlink files, but rollback
will.
Co-contributor: Sune Foldager <cryo@cyanite.org>
author | Henrik Stuart <hg@hstuart.dk> |
---|---|
date | Mon, 04 May 2009 15:31:57 +0200 |
parents | 560af1bbfd6e |
children | c8e81f557da7 |
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 # |
8225
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
8071
diff
changeset
|
11 # This software may be used and distributed according to the terms of the |
46293a0c7e9f
updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents:
8071
diff
changeset
|
12 # GNU General Public License version 2, incorporated herein by reference. |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
13 |
3891 | 14 from i18n import _ |
7335
866d2715aff5
add missing import from 618140c75d8d
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
7334
diff
changeset
|
15 import os, errno |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
16 import error |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
17 |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
18 def active(func): |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
19 def _active(self, *args, **kwds): |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
20 if self.count == 0: |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
21 raise error.Abort(_( |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
22 'cannot use transaction when it is already committed/aborted')) |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
23 return func(self, *args, **kwds) |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
24 return _active |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
25 |
8294
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
26 def _playback(journal, report, opener, entries, unlink=True): |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
27 for f, o, ignore in entries: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
28 if o or not unlink: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
29 try: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
30 opener(f, 'a').truncate(o) |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
31 except: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
32 report(_("failed to truncate %s\n") % f) |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
33 raise |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
34 else: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
35 try: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
36 fn = opener(f).name |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
37 os.unlink(fn) |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
38 except OSError, inst: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
39 if inst.errno != errno.ENOENT: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
40 raise |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
41 os.unlink(journal) |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
42 |
1559
59b3639df0a9
Convert all classes to new-style classes by deriving them from object.
Eric Hopper <hopper@omnifarious.org>
parents:
1541
diff
changeset
|
43 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
|
44 def __init__(self, report, opener, journal, after=None, createmode=None): |
162 | 45 self.journal = None |
46 | |
1806
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
47 self.count = 1 |
582 | 48 self.report = report |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
49 self.opener = opener |
95 | 50 self.after = after |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
51 self.entries = [] |
42
91f1fa847158
Fix multiple changes to file per transaction
mpm@selenic.com
parents:
13
diff
changeset
|
52 self.map = {} |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
53 self.journal = journal |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
54 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
55 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
|
56 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
|
57 os.chmod(self.journal, createmode & 0666) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
58 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
59 def __del__(self): |
558
0ceea19182a9
transaction: __del__ should do nothing if the journal already exists
mpm@selenic.com
parents:
515
diff
changeset
|
60 if self.journal: |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
61 if self.entries: self._abort() |
558
0ceea19182a9
transaction: __del__ should do nothing if the journal already exists
mpm@selenic.com
parents:
515
diff
changeset
|
62 self.file.close() |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
63 |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
64 @active |
2084 | 65 def add(self, file, offset, data=None): |
42
91f1fa847158
Fix multiple changes to file per transaction
mpm@selenic.com
parents:
13
diff
changeset
|
66 if file in self.map: return |
2084 | 67 self.entries.append((file, offset, data)) |
68 self.map[file] = len(self.entries) - 1 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
69 # 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
|
70 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
|
71 self.file.flush() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
72 |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
73 @active |
2084 | 74 def find(self, file): |
75 if file in self.map: | |
76 return self.entries[self.map[file]] | |
77 return None | |
78 | |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
79 @active |
2084 | 80 def replace(self, file, offset, data=None): |
81 if file not in self.map: | |
82 raise KeyError(file) | |
83 index = self.map[file] | |
84 self.entries[index] = (file, offset, data) | |
85 self.file.write("%s\0%d\n" % (file, offset)) | |
86 self.file.flush() | |
87 | |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
88 @active |
1806
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
89 def nest(self): |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
90 self.count += 1 |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
91 return self |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
92 |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
93 def running(self): |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
94 return self.count > 0 |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
95 |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
96 @active |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
97 def close(self): |
1806
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
98 self.count -= 1 |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
99 if self.count != 0: |
a2c69737e65e
Automatic nesting into running transactions in the same repository.
mason@suse.com
parents:
1559
diff
changeset
|
100 return |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
101 self.file.close() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
102 self.entries = [] |
95 | 103 if self.after: |
785 | 104 self.after() |
95 | 105 else: |
106 os.unlink(self.journal) | |
573 | 107 self.journal = None |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
108 |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
109 @active |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
110 def abort(self): |
8289
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
111 self._abort() |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
112 |
fe8a3e56039f
transaction: ensure finished transactions are not reused
Henrik Stuart <hg@hstuart.dk>
parents:
8225
diff
changeset
|
113 def _abort(self): |
8290
560af1bbfd6e
transaction: reset transaction on abort
Henrik Stuart <hg@hstuart.dk>
parents:
8289
diff
changeset
|
114 self.count = 0 |
560af1bbfd6e
transaction: reset transaction on abort
Henrik Stuart <hg@hstuart.dk>
parents:
8289
diff
changeset
|
115 self.file.close() |
560af1bbfd6e
transaction: reset transaction on abort
Henrik Stuart <hg@hstuart.dk>
parents:
8289
diff
changeset
|
116 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
117 if not self.entries: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
118 |
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
|
119 self.report(_("transaction abort!\n")) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
120 |
8294
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
121 try: |
108 | 122 try: |
8294
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
123 _playback(self.journal, self.report, self.opener, self.entries, False) |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
124 self.report(_("rollback completed\n")) |
108 | 125 except: |
8294
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
126 self.report(_("rollback failed - please run hg recover\n")) |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
127 finally: |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
128 self.journal = None |
8290
560af1bbfd6e
transaction: reset transaction on abort
Henrik Stuart <hg@hstuart.dk>
parents:
8289
diff
changeset
|
129 |
560af1bbfd6e
transaction: reset transaction on abort
Henrik Stuart <hg@hstuart.dk>
parents:
8289
diff
changeset
|
130 |
8294
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
131 def rollback(opener, file, report): |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
132 entries = [] |
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
133 |
162 | 134 for l in open(file).readlines(): |
135 f, o = l.split('\0') | |
8294
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
136 entries.append((f, int(o), None)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
137 |
8294
48a382c23226
transaction: refactor transaction.abort and rollback to use the same code
Henrik Stuart <hg@hstuart.dk>
parents:
8290
diff
changeset
|
138 _playback(file, report, opener, entries) |