Patchwork [2,of,5] blackbox: resurrect recursion guard

login
register
mail settings
Submitter Yuya Nishihara
Date Dec. 16, 2018, 8:30 a.m.
Message ID <51f6fb41be9b7b16157f.1544949035@mimosa>
Download mbox | patch
Permalink /patch/37206/
State New
Headers show

Comments

Yuya Nishihara - Dec. 16, 2018, 8:30 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1544868342 -32400
#      Sat Dec 15 19:05:42 2018 +0900
# Node ID 51f6fb41be9b7b16157f5fc3a421b04c037b455e
# Parent  f52cf621f392643960ac3cb5ff7bb17059bd040a
blackbox: resurrect recursion guard

If I added ui.log() to hg.repository() function, test-merge-subrepos.t
exploded. The problem is that the blackbox may create new repository instance
while logging is active, and the created repository owns its new ui derived
from the baseui, not from the ui which is processing the active logging.

I tried to work around the issue in ui.log(), but that turned out to be not
easy. We shouldn't globally lock the ui.log() since there may be more than
one active repo/ui instances in threaded environment. We could store the
logging state in thread-local storage, but that seems unnecessarily complex.
So this patch reintroduces the _inlog flag to per-repository logger instances.

Patch

diff --git a/hgext/blackbox.py b/hgext/blackbox.py
--- a/hgext/blackbox.py
+++ b/hgext/blackbox.py
@@ -96,11 +96,24 @@  class blackboxlogger(object):
         self._trackedevents = set(ui.configlist('blackbox', 'track'))
         self._maxfiles = ui.configint('blackbox', 'maxfiles')
         self._maxsize = ui.configbytes('blackbox', 'maxsize')
+        self._inlog = False
 
     def tracked(self, event):
         return b'*' in self._trackedevents or event in self._trackedevents
 
     def log(self, ui, event, msg, opts):
+        # self._log() -> ctx.dirty() may create new subrepo instance, which
+        # ui is derived from baseui. So the recursion guard in ui.log()
+        # doesn't work as it's local to the ui instance.
+        if self._inlog:
+            return
+        self._inlog = True
+        try:
+            self._log(ui, event, msg, opts)
+        finally:
+            self._inlog = False
+
+    def _log(self, ui, event, msg, opts):
         default = ui.configdate('devel', 'default-date')
         date = dateutil.datestr(default, ui.config('blackbox', 'date-format'))
         user = procutil.getuser()