summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin McCarthy <kevin@8t8.us>2020-02-08 11:34:13 -0800
committerKevin McCarthy <kevin@8t8.us>2020-02-10 15:30:17 -0800
commit0f8a079d1cc66878ddfa68476f8ea7abdb6fd7e8 (patch)
tree82a09aead8224f619262acff607cce28c36f60da
parent376716eb6fd43982abca56707b809ccd6d8741a6 (diff)
Speed up thread sort when many long threads exist.
Merge request !75 reported a massive slowdown opening a mailbox with many long threads: on the order of an hour. This is because mutt_set_virtual() was iterating through the whole thread for each message. After taking a closer look at current Mutt behavior, it seems the num_hidden count is only needed in the root thread. Quoting my comment in the merge request: The index-format expando %M only applies to root level headers, so there are no issues there. The only concern is the pattern ~v. Limiting always resets collapsed and num_hidden, so there also can't be any issues there. Tagging and other pattern operators only work on visible messages. So tagging while threads are sorted will only tag the root messages of collapsed threads. However, if you sort by thread, collapse a thread, and then sort by date, the collapsed and num_hidden fields are not reset for each header. In theory this would allow us to tag ~v with date ordering. However, in master the num_hidden is only set (by mutt_set_virtual()) for visible messages with a virtual number. So even in master, switching to date-order and tagging ~v will only tag the root messages of each collapsed thread. This commit removes the num_hidden setting in mutt_set_virtual(), instead directly assigning that value in the roothdr during a collapse operation. A subsequent commit will fix the behavior of ~v, when switching sorting from threaded to something else, by putting num_hidden in every header in the thread. This is technically a change in behavior, so I will make that commit in the master branch. Thanks to Score_Under for the pull request and for testing my alternate solutions.
-rw-r--r--mutt.h9
-rw-r--r--protos.h1
-rw-r--r--thread.c15
3 files changed, 14 insertions, 11 deletions
diff --git a/mutt.h b/mutt.h
index 836c6c81..60649fac 100644
--- a/mutt.h
+++ b/mutt.h
@@ -203,9 +203,8 @@ typedef enum
#define MUTT_THREAD_COLLAPSE (1<<0)
#define MUTT_THREAD_UNCOLLAPSE (1<<1)
-#define MUTT_THREAD_GET_HIDDEN (1<<2)
-#define MUTT_THREAD_UNREAD (1<<3)
-#define MUTT_THREAD_NEXT_UNREAD (1<<4)
+#define MUTT_THREAD_UNREAD (1<<2)
+#define MUTT_THREAD_NEXT_UNREAD (1<<3)
enum
{
@@ -882,7 +881,9 @@ typedef struct header
/* the following are used to support collapsing threads */
unsigned int collapsed : 1; /* is this message part of a collapsed thread? */
unsigned int limited : 1; /* is this message in a limited view? */
- size_t num_hidden; /* number of hidden messages in this view */
+ size_t num_hidden; /* number of hidden messages in this view.
+ * only valid for the root header, when
+ * collapsed is set. */
short recipient; /* user_is_recipient()'s return value, cached */
diff --git a/protos.h b/protos.h
index 5626359c..3f271c30 100644
--- a/protos.h
+++ b/protos.h
@@ -52,7 +52,6 @@ int _mutt_aside_thread (HEADER *, short, short);
#define mutt_collapse_thread(x,y) _mutt_traverse_thread (x,y,MUTT_THREAD_COLLAPSE)
#define mutt_uncollapse_thread(x,y) _mutt_traverse_thread (x,y,MUTT_THREAD_UNCOLLAPSE)
-#define mutt_get_hidden(x,y)_mutt_traverse_thread (x,y,MUTT_THREAD_GET_HIDDEN)
#define mutt_thread_contains_unread(x,y) _mutt_traverse_thread (x,y,MUTT_THREAD_UNREAD)
#define mutt_thread_next_unread(x,y) _mutt_traverse_thread(x,y,MUTT_THREAD_NEXT_UNREAD)
int _mutt_traverse_thread (CONTEXT *ctx, HEADER *hdr, int flag);
diff --git a/thread.c b/thread.c
index 5c6adda2..9680108f 100644
--- a/thread.c
+++ b/thread.c
@@ -1132,7 +1132,6 @@ void mutt_set_virtual (CONTEXT *ctx)
ctx->vcount++;
ctx->vsize += cur->content->length + cur->content->offset -
cur->content->hdr_offset + padding;
- cur->num_hidden = mutt_get_hidden (ctx, cur);
}
}
}
@@ -1146,7 +1145,7 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag)
int min_unread_msgno = INT_MAX, min_unread = cur->virtual;
#define CHECK_LIMIT (!ctx->pattern || cur->limited)
- if ((Sort & SORT_MASK) != SORT_THREADS && !(flag & MUTT_THREAD_GET_HIDDEN))
+ if ((Sort & SORT_MASK) != SORT_THREADS)
{
mutt_error (_("Threading is not enabled."));
return (cur->virtual);
@@ -1194,11 +1193,13 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag)
{
/* return value depends on action requested */
if (flag & (MUTT_THREAD_COLLAPSE | MUTT_THREAD_UNCOLLAPSE))
+ {
+ if (roothdr)
+ roothdr->num_hidden = num_hidden;
return (final);
+ }
else if (flag & MUTT_THREAD_UNREAD)
return ((old && new) ? new : (old ? old : new));
- else if (flag & MUTT_THREAD_GET_HIDDEN)
- return (num_hidden);
else if (flag & MUTT_THREAD_NEXT_UNREAD)
return (min_unread);
}
@@ -1280,11 +1281,13 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag)
/* return value depends on action requested */
if (flag & (MUTT_THREAD_COLLAPSE | MUTT_THREAD_UNCOLLAPSE))
+ {
+ if (roothdr)
+ roothdr->num_hidden = num_hidden + 1;
return (final);
+ }
else if (flag & MUTT_THREAD_UNREAD)
return ((old && new) ? new : (old ? old : new));
- else if (flag & MUTT_THREAD_GET_HIDDEN)
- return (num_hidden+1);
else if (flag & MUTT_THREAD_NEXT_UNREAD)
return (min_unread);