[PATCH 6 of 6] transaction: add atomic groups to transaction logic
Henrik Stuart
hg at hstuart.dk
Wed Apr 22 07:58:48 UTC 2009
# HG changeset patch
# User Henrik Stuart <hg at hstuart.dk>
# Date 1240384802 -7200
# Node ID d5ab1e8c1d4dcb0007b692ff3957851500fc53ea
# Parent 6e2e7f523c56f0caf1a8d7400ba1e1d33919f0f1
transaction: add atomic groups to transaction logic
When performing a strip operation on a repository it is vital that all the
truncations are performed, or that none of them are. This is done by adding
atomic blocks to the journal. If a partial atomic block is written, and they
can be nested, then it will not be executed on a hg repair, and a warning
will be written that the journal contains a partial atomic block.
Co-contributor: Sune Foldager <cryo at cyanite.org>
diff -r 6e2e7f523c56 -r d5ab1e8c1d4d mercurial/repair.py
--- a/mercurial/repair.py Wed Apr 22 09:20:01 2009 +0200
+++ b/mercurial/repair.py Wed Apr 22 09:20:02 2009 +0200
@@ -9,6 +9,7 @@
import changegroup, os
from node import nullrev, short
from i18n import _
+from transaction import transaction
def _bundle(repo, bases, heads, node, suffix, extranodes=None):
"""create a bundle with the specified revisions as a backup"""
@@ -124,13 +125,16 @@
tr = repo.transaction()
offset = len(tr.entries)
+ tr.start_atomic()
cl.strip(striprev, tr)
mfst.strip(striprev, tr)
for f in fs:
f.strip(striprev, tr)
+ tr.end_atomic()
+ tr.flush()
try:
- for i in xrange(offset, len(tr.entries)):
+ for i in xrange(offset + 1, len(tr.entries) - 1):
file, troffset, ignore = tr.entries[i]
repo.sopener(file, 'a').truncate(troffset)
tr.close()
diff -r 6e2e7f523c56 -r d5ab1e8c1d4d mercurial/transaction.py
--- a/mercurial/transaction.py Wed Apr 22 09:20:01 2009 +0200
+++ b/mercurial/transaction.py Wed Apr 22 09:20:02 2009 +0200
@@ -25,16 +25,40 @@
return _active
def _journal_playback(journal, opener, entries, unlink=True):
- for f, o, ignore in entries:
- if o or not unlink:
- opener(f, 'a').truncate(o)
+ i, end = 0, len(entries)
+
+ def find_atomic_end(offset):
+ count = 0
+ while offset < end:
+ if entries[offset] == transaction.atomic_start:
+ count += 1
+ elif entries[offset] == transaction.atomic_end:
+ count -= 1
+ if count == 0:
+ return offset
+ offset += 1
+ return -1
+
+ while i < end:
+ if entries[i] == transaction.atomic_start:
+ atomic_end = find_atomic_end(i)
+ if atomic_end == -1:
+ raise error.Abort(_('incomplete atomic section in journal - will not replay\n'))
+ elif entries[i] == transaction.atomic_end:
+ pass
else:
- try:
- fn = opener(f).name
- os.unlink(fn)
- except OSError, inst:
- if inst.errno != errno.ENOENT:
- raise
+ f, o, ignore = entries[i]
+ if o or not unlink:
+ opener(f, 'a').truncate(o)
+ else:
+ try:
+ fn = opener(f).name
+ os.unlink(fn)
+ except OSError, inst:
+ if inst.errno != errno.ENOENT:
+ raise
+
+ i += 1
os.unlink(journal)
@@ -59,6 +83,19 @@
if self.entries: self._abort()
self.file.close()
+ atomic_start = 'start atomic\n'
+ atomic_end = 'end atomic\n'
+
+ @active
+ def start_atomic(self):
+ self.entries.append(transaction.atomic_start)
+ self._write(transaction.atomic_start)
+
+ @active
+ def end_atomic(self):
+ self.entries.append(transaction.atomic_end)
+ self._write(transaction.atomic_end)
+
@active
def add(self, file, offset, data=None):
if file in self.map: return
@@ -135,7 +172,10 @@
entries = []
for l in open(file).readlines():
- f, o = l.split('\0')
- entries.append((f, int(o), None))
+ if l in [transaction.atomic_start, transaction.atomic_end]:
+ entries.append(l)
+ else:
+ f, o = l.split('\0')
+ entries.append((f, int(o), None))
_journal_playback(file, opener, entries)
diff -r 6e2e7f523c56 -r d5ab1e8c1d4d tests/test-repair-strip.out
--- a/tests/test-repair-strip.out Wed Apr 22 09:20:01 2009 +0200
+++ b/tests/test-repair-strip.out Wed Apr 22 09:20:02 2009 +0200
@@ -21,10 +21,12 @@
2 warnings encountered!
2 integrity errors encountered!
% journal contents
+start atomic
00changelog.i
00manifest.i
data/b.i
data/c.i
+end atomic
rolling back interrupted transaction
checking changesets
checking manifests
@@ -73,10 +75,12 @@
5 integrity errors encountered!
(first damaged changeset appears to be 3)
% journal contents
+start atomic
00changelog.i
00manifest.i
data/b.i
data/c.i
+end atomic
rolling back interrupted transaction
checking changesets
checking manifests
More information about the Mercurial-devel
mailing list