phases: avoid N² behavior in `advanceboundary`
We allowed duplicated entries in the deque, which each entry could potentially
insert all its ancestors. So advancing boundary for the full repository would
mean each revision would walk all its ancestors, resulting in O(N²) iteration.
For repository of any decent size, N² is quickly insane.
We introduce a simple set to avoid this and get back to reasonable performance.
# logexceptions.py - Write files containing info about Mercurial exceptions
#
# Copyright 2017 Olivia Mackall <olivia@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
import inspect
import os
import sys
import traceback
import uuid
from mercurial import (
dispatch,
extensions,
)
def handleexception(orig, ui):
res = orig(ui)
if not ui.environ.get(b'HGEXCEPTIONSDIR'):
return res
dest = os.path.join(
ui.environ[b'HGEXCEPTIONSDIR'], str(uuid.uuid4()).encode('ascii')
)
exc_type, exc_value, exc_tb = sys.exc_info()
stack = []
tb = exc_tb
while tb:
stack.append(tb)
tb = tb.tb_next
stack.reverse()
hgframe = 'unknown'
hgline = 'unknown'
# Find the first Mercurial frame in the stack.
for tb in stack:
mod = inspect.getmodule(tb)
if not mod.__name__.startswith(('hg', 'mercurial')):
continue
frame = tb.tb_frame
try:
with open(inspect.getsourcefile(tb), 'r') as fh:
hgline = fh.readlines()[frame.f_lineno - 1].strip()
except (IndexError, OSError):
pass
hgframe = '%s:%d' % (frame.f_code.co_filename, frame.f_lineno)
break
primary = traceback.extract_tb(exc_tb)[-1]
primaryframe = '%s:%d' % (primary.filename, primary.lineno)
with open(dest, 'wb') as fh:
parts = [
str(exc_value),
primaryframe,
hgframe,
hgline,
ui.environ[b'TESTNAME'].decode('utf-8', 'replace'),
]
fh.write(b'\0'.join(p.encode('utf-8', 'replace') for p in parts))
def extsetup(ui):
extensions.wrapfunction(dispatch, 'handlecommandexception', handleexception)