[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#986732: unblock: mutt/2.0.5-4



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package mutt

[ Reason ]
2.0.5-4 includes a patch to fix a slowness in opening messages due to coloring
which can amount to up to tens of seconds (see bugs.debian.org/985152).

[ Impact ]
Same as above.

[ Tests ]
No tests affected.

[ Risks ]
The change itself is trivial (see patch), and it has been already included in
the most recent version of mutt released.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
(Anything else the release team should know.)

unblock mutt/2.0.5-4
diff -Nru mutt-2.0.5/debian/changelog mutt-2.0.5/debian/changelog
--- mutt-2.0.5/debian/changelog	2021-02-16 21:34:09.000000000 +0100
+++ mutt-2.0.5/debian/changelog	2021-03-20 17:26:12.000000000 +0100
@@ -1,3 +1,11 @@
+mutt (2.0.5-4) unstable; urgency=medium
+
+  * debian/patches:
+    + upstream/985152-body-color-slowness.patch: fixes slowness (up to tens of
+      seconds) if body coloring is present (Closes: 985152).
+
+ -- Antonio Radici <antonio@debian.org>  Sat, 20 Mar 2021 17:26:12 +0100
+
 mutt (2.0.5-3) unstable; urgency=medium
 
   * debian/patches:
diff -Nru mutt-2.0.5/debian/patches/series mutt-2.0.5/debian/patches/series
--- mutt-2.0.5/debian/patches/series	2021-02-16 21:32:50.000000000 +0100
+++ mutt-2.0.5/debian/patches/series	2021-03-20 17:24:06.000000000 +0100
@@ -12,3 +12,4 @@
 misc/smime.rc.patch
 upstream/528233-readonly-open.patch
 upstream/980924-updated-german-translation.patch
+upstream/985152-body-color-slowness.patch
diff -Nru mutt-2.0.5/debian/patches/upstream/985152-body-color-slowness.patch mutt-2.0.5/debian/patches/upstream/985152-body-color-slowness.patch
--- mutt-2.0.5/debian/patches/upstream/985152-body-color-slowness.patch	1970-01-01 01:00:00.000000000 +0100
+++ mutt-2.0.5/debian/patches/upstream/985152-body-color-slowness.patch	2021-03-20 17:25:35.000000000 +0100
@@ -0,0 +1,163 @@
+From 53ffdb93b8a96efb7456f9430cf46a66ca7b9860 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Wed, 10 Mar 2021 15:09:49 -0800
+Subject: [PATCH] Improve body color matching speed by caching future matches.
+
+On a *very* long body (or header_partial) lines with multiple color
+lines that match, performance can be degraded.  For instance if there
+were moderately expensive regexp matches against "A" "B" and "C".  A
+line with:
+
+  A A A A A B A A C A A A B A A A C
+
+The B and C regexps were scanned again after every "A" match, despite
+that the result would be discarded again for the next A match.
+
+Change the color matching to cache the location of each color line
+match.  Discard the cache once the match offset passes that point.
+---
+ mutt_curses.h |  5 ++++
+ pager.c       | 64 ++++++++++++++++++++++++++++++++++++++++-----------
+ 2 files changed, 55 insertions(+), 14 deletions(-)
+
+--- a/mutt_curses.h
++++ b/mutt_curses.h
+@@ -154,9 +154,14 @@
+   int pair;
+   struct color_line *next;
+ 
++  regoff_t cached_rm_so;
++  regoff_t cached_rm_eo;
++
+   unsigned int stop_matching : 1; /* used by the pager for body patterns,
+                                      to prevent the color from being retried
+                                      once it fails. */
++  unsigned int cached : 1; /* indicates cached_rm_so and cached_rm_eo
++                            * hold the last match location */
+ } COLOR_LINE;
+ 
+ #define MUTT_PROGRESS_SIZE      (1<<0)  /* traffic-based progress */
+--- a/pager.c
++++ b/pager.c
+@@ -773,7 +773,7 @@
+ {
+   COLOR_LINE *color_line, *color_list;
+   regmatch_t pmatch[1];
+-  int found, offset, null_rx, i;
++  int i;
+ 
+   if (n == 0 || ISHEADER (lineInfo[n-1].type) ||
+       (check_protected_header_marker (raw) == 0))
+@@ -879,6 +879,8 @@
+       (lineInfo[n].type == MT_COLOR_HDEFAULT && option (OPTHEADERCOLORPARTIAL)))
+   {
+     size_t nl;
++    int has_nl = 0, found, offset, null_rx, has_reg_match;
++    regoff_t rm_so, rm_eo;
+ 
+     /* don't consider line endings part of the buffer
+      * for regex matching */
+@@ -896,8 +898,10 @@
+     while (color_line)
+     {
+       color_line->stop_matching = 0;
++      color_line->cached = 0;
+       color_line = color_line->next;
+     }
++
+     do
+     {
+       if (!buf[offset])
+@@ -908,11 +912,31 @@
+       color_line = color_list;
+       while (color_line)
+       {
+-	if (!color_line->stop_matching &&
+-            regexec (&color_line->rx, buf + offset, 1, pmatch,
+-		     (offset ? REG_NOTBOL : 0)) == 0)
++        has_reg_match = 0;
++	if (!color_line->stop_matching)
++        {
++          if (color_line->cached)
++          {
++            has_reg_match = 1;
++            rm_so = color_line->cached_rm_so;
++            rm_eo = color_line->cached_rm_eo;
++          }
++          else
++          {
++            if (regexec (&color_line->rx, buf + offset, 1, pmatch,
++                         (offset ? REG_NOTBOL : 0)) == 0)
++            {
++              has_reg_match = 1;
++              color_line->cached = 1;
++              rm_so = color_line->cached_rm_so = (pmatch[0].rm_so + offset);
++              rm_eo = color_line->cached_rm_eo = (pmatch[0].rm_eo + offset);
++            }
++          }
++        }
++
++        if (has_reg_match)
+ 	{
+-	  if (pmatch[0].rm_eo != pmatch[0].rm_so)
++	  if (rm_eo != rm_so)
+ 	  {
+ 	    if (!found)
+ 	    {
+@@ -928,28 +952,29 @@
+ 			      (lineInfo[n].chunks) * sizeof (struct syntax_t));
+ 	    }
+ 	    i = lineInfo[n].chunks - 1;
+-	    pmatch[0].rm_so += offset;
+-	    pmatch[0].rm_eo += offset;
+ 	    if (!found ||
+-		pmatch[0].rm_so < (lineInfo[n].syntax)[i].first ||
+-		(pmatch[0].rm_so == (lineInfo[n].syntax)[i].first &&
+-		 pmatch[0].rm_eo > (lineInfo[n].syntax)[i].last))
++		rm_so < (lineInfo[n].syntax)[i].first ||
++		(rm_so == (lineInfo[n].syntax)[i].first &&
++		 rm_eo > (lineInfo[n].syntax)[i].last))
+ 	    {
+ 	      (lineInfo[n].syntax)[i].color = color_line->pair;
+-	      (lineInfo[n].syntax)[i].first = pmatch[0].rm_so;
+-	      (lineInfo[n].syntax)[i].last = pmatch[0].rm_eo;
++	      (lineInfo[n].syntax)[i].first = rm_so;
++	      (lineInfo[n].syntax)[i].last = rm_eo;
+ 	    }
+ 	    found = 1;
+ 	    null_rx = 0;
+ 	  }
+ 	  else
+-	    null_rx = 1; /* empty regexp; don't add it, but keep looking */
++            null_rx = 1; /* empty regexp; don't add it, but keep looking */
+ 	}
+         /* Once a regexp fails to match, don't try matching it again.
+          * On very long lines this can cause a performance issue if there
+          * are other regexps that have many matches. */
+         else
++        {
+           color_line->stop_matching = 1;
++          color_line->cached = 0;
++        }
+ 	color_line = color_line->next;
+       }
+ 
+@@ -957,6 +982,18 @@
+ 	offset++; /* avoid degenerate cases */
+       else
+ 	offset = (lineInfo[n].syntax)[i].last;
++
++      /* Removed cached matches that aren't later in the buffer */
++      color_line = color_list;
++      while (color_line)
++      {
++        if (color_line->cached &&
++            color_line->cached_rm_so < offset)
++        {
++          color_line->cached = 0;
++        }
++	color_line = color_line->next;
++      }
+     } while (found || null_rx);
+     if (nl > 0)
+       buf[nl] = '\n';

Reply to: