Package: release.debian.org Severity: normal User: release.debian....@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 <anto...@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 <ke...@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';