D1621: transaction: encodes tuples in changes['phases'] as 4 bit ints
joerg.sonnenberger (Joerg Sonnenberger)
phabricator at mercurial-scm.org
Sun Dec 10 16:11:17 EST 2017
joerg.sonnenberger updated this revision to Diff 4341.
joerg.sonnenberger edited the summary of this revision.
joerg.sonnenberger retitled this revision from "[PoC] transaction: split changes['phases'] into sets for src and target phase" to "transaction: encodes tuples in changes['phases'] as 4 bit ints".
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D1621?vs=4278&id=4341
REVISION DETAIL
https://phab.mercurial-scm.org/D1621
AFFECTED FILES
mercurial/localrepo.py
mercurial/phases.py
tests/testlib/ext-phase-report.py
CHANGE DETAILS
diff --git a/tests/testlib/ext-phase-report.py b/tests/testlib/ext-phase-report.py
--- a/tests/testlib/ext-phase-report.py
+++ b/tests/testlib/ext-phase-report.py
@@ -1,11 +1,12 @@
# tiny extension to report phase changes during transaction
from __future__ import absolute_import
+from mercurial import phases
def reposetup(ui, repo):
def reportphasemove(tr):
- for rev, move in sorted(tr.changes['phases'].iteritems()):
+ for rev, move in sorted(phases.phasechanges(tr)):
if move[0] is None:
ui.write(('test-debug-phase: new rev %d: x -> %d\n'
% (rev, move[1])))
diff --git a/mercurial/phases.py b/mercurial/phases.py
--- a/mercurial/phases.py
+++ b/mercurial/phases.py
@@ -186,17 +186,43 @@
headsbyphase[phase].append(node)
return headsbyphase
-def _trackphasechange(data, rev, old, new):
- """add a phase move the <data> dictionnary
- If data is None, nothing happens.
+_transitions = [(p1, p2) for p1 in allphases + [None] for p2 in allphases]
+phasemapping = dict(zip(_transitions, xrange(1, 1 + len(_transitions))))
+phasemapping2 = dict([
+ ((phasemapping[p1, p2], p3), phasemapping[p1, p3])
+ for p1 in allphases + [None]
+ for p2 in allphases
+ for p3 in allphases])
+phasemapping_reverse = dict([(p2, p1) for (p1, p2) in phasemapping.items()])
+
+def phasechange(tr, rev):
+ """get the recorded phase move for revision <rev>
+
+ If no change was recorded, None is returned.
"""
- if data is None:
- return
- existing = data.get(rev)
- if existing is not None:
- old = existing[0]
- data[rev] = (old, new)
+ data = tr.changes.get('phases', {})
+ transition = data.get(rev)
+ if not transition:
+ return None
+ return phasemapping_reverse[data[rev]]
+
+def phasechanges(tr):
+ """generate all recorded phase moves"""
+ data = tr.changes.get('phases', {})
+ for rev in data:
+ yield (rev, phasemapping_reverse[data[rev]])
+
+def initphasechange(tr):
+ tr.changes['phases'] = {}
+
+def addphasechange(tr, rev, old, new):
+ """add a phase move to the <tr> transaction"""
+ data = tr.changes.setdefault('phases', {})
+ if rev in data:
+ data[rev] = phasemapping2[data[rev], new]
+ else:
+ data[rev] = phasemapping[old, new]
class phasecache(object):
def __init__(self, repo, phasedefaults, _load=True):
@@ -337,13 +363,12 @@
repo = repo.unfiltered()
self._retractboundary(repo, tr, targetphase, nodes)
if tr is not None and 'phases' in tr.changes:
- phasetracking = tr.changes['phases']
torev = repo.changelog.rev
phase = self.phase
for n in nodes:
rev = torev(n)
revphase = phase(repo, rev)
- _trackphasechange(phasetracking, rev, None, revphase)
+ addphasechange(tr, rev, None, revphase)
repo.invalidatevolatilesets()
def advanceboundary(self, repo, tr, targetphase, nodes):
@@ -353,11 +378,6 @@
"""
# Be careful to preserve shallow-copied values: do not update
# phaseroots values, replace them.
- if tr is None:
- phasetracking = None
- else:
- phasetracking = tr.changes.get('phases')
-
repo = repo.unfiltered()
delroots = [] # set of root deleted by this path
@@ -371,9 +391,10 @@
olds = self.phaseroots[phase]
affected = repo.revs('%ln::%ln', olds, nodes)
- for r in affected:
- _trackphasechange(phasetracking, r, self.phase(repo, r),
- targetphase)
+ if tr:
+ for r in affected:
+ addphasechange(tr, r, self.phase(repo, r),
+ targetphase)
roots = set(ctx.node() for ctx in repo.set(
'roots((%ln::) - %ld)', olds, affected))
@@ -388,13 +409,8 @@
def retractboundary(self, repo, tr, targetphase, nodes):
oldroots = self.phaseroots[:targetphase + 1]
- if tr is None:
- phasetracking = None
- else:
- phasetracking = tr.changes.get('phases')
repo = repo.unfiltered()
- if (self._retractboundary(repo, tr, targetphase, nodes)
- and phasetracking is not None):
+ if self._retractboundary(repo, tr, targetphase, nodes) and tr:
# find the affected revisions
new = self.phaseroots[targetphase]
@@ -410,7 +426,7 @@
else: # public phase
revs = affected
for r in revs:
- _trackphasechange(phasetracking, r, phase, targetphase)
+ addphasechange(tr, r, phase, targetphase)
repo.invalidatevolatilesets()
def _retractboundary(self, repo, tr, targetphase, nodes):
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1242,7 +1242,8 @@
**pycompat.strkwargs(args))
if hook.hashook(repo.ui, 'pretxnclose-phase'):
cl = repo.unfiltered().changelog
- for rev, (old, new) in tr.changes['phases'].items():
+ phasechanges = phases.phasechanges(tr)
+ for rev, (old, new) in phasechanges:
args = tr.hookargs.copy()
node = hex(cl.node(rev))
args.update(phases.preparehookargs(node, old, new))
@@ -1277,7 +1278,7 @@
checkambigfiles=_cachedfiles)
tr.changes['revs'] = xrange(0, 0)
tr.changes['obsmarkers'] = set()
- tr.changes['phases'] = {}
+ phases.initphasechange(tr)
tr.changes['bookmarks'] = {}
tr.hookargs['txnid'] = txnid
@@ -1306,7 +1307,7 @@
if hook.hashook(repo.ui, 'txnclose-phase'):
cl = repo.unfiltered().changelog
- phasemv = sorted(tr.changes['phases'].items())
+ phasemv = sorted(phases.phasechanges(tr))
for rev, (old, new) in phasemv:
args = tr.hookargs.copy()
node = hex(cl.node(rev))
To: joerg.sonnenberger, #hg-reviewers, quark
Cc: yuja, quark, mercurial-devel
More information about the Mercurial-devel
mailing list