From bc0a873b18cd77572c53369e5899134102f93e5e Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Mon, 23 Nov 2009 17:42:45 +0100 Subject: [PATCH] search : Extend "intial burst" optimization to return all results by chunks This way, the user gets a steady (but bursty) stream of reults. We double the chunk size each time since each successive chunk has to redo work from all previous chunks. Of course, the overall time is thereby slower, as the price we pay for increased responsiveness. With a search returning about 17000 thread results I measured a total time of 48.8 seconds before this change and 58.4 seconds afterwards. --- TODO | 5 +++++ notmuch-search.c | 50 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/TODO b/TODO index 65d6c75c..da8f7c9b 100644 --- a/TODO +++ b/TODO @@ -134,6 +134,11 @@ Add support for configuring "virtual tags" which are a tuple of (tag-name, search-specification). The database is responsible for ensuring that the virtual tag is always consistent. +Think about optimizing chunked searches (max-threads > 0) to avoid +repeating work. That would be saving state from the previous chunk and +reusing it if the next search is the next chunk with the same search +string. + General ------- Audit everything for dealing with out-of-memory (and drop xutil.c). diff --git a/notmuch-search.c b/notmuch-search.c index aa6662bd..fc2baaa7 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -20,12 +20,20 @@ #include "notmuch-client.h" -/* If the user asks for a *lot* of threads, lets give some results as - * quickly as possible and let the user read those while we compute - * the remainder. */ -#define NOTMUCH_SHOW_INITIAL_BURST 100 +/* If the user asks for more than this number of threads, then break + the results down into chunks so that results start appearing + quickly rather than the user having to wait until all results are + available before anything appears. -static void + Since each subsequent chunk ends up having to re-do threading work + done by all previous chunks, we double the chunk size repeatedly + until all desired results have been returned. +*/ +#define NOTMUCH_SEARCH_INITIAL_CHUNK_SIZE 100 + +/* Do the actual search for a chunk of threads and display the results, + (returning the number of threads found in this chunk). */ +static int do_search_threads (const void *ctx, notmuch_query_t *query, notmuch_sort_t sort, @@ -36,6 +44,7 @@ do_search_threads (const void *ctx, notmuch_tags_t *tags; time_t date; const char *relative_date; + int num_threads = 0; for (threads = notmuch_query_search_threads (query, first, max_threads); notmuch_threads_has_more (threads); @@ -44,6 +53,7 @@ do_search_threads (const void *ctx, int first_tag = 1; thread = notmuch_threads_get (threads); + num_threads++; if (sort == NOTMUCH_SORT_OLDEST_FIRST) date = notmuch_thread_get_oldest_date (thread); @@ -74,6 +84,8 @@ do_search_threads (const void *ctx, notmuch_thread_destroy (thread); } + + return num_threads; } int @@ -86,6 +98,8 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) int i, first = 0, max_threads = -1; char *opt, *end; notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST; + int chunk_size; + int threads_in_chunk; for (i = 0; i < argc && argv[i][0] == '-'; i++) { if (strcmp (argv[i], "--") == 0) { @@ -152,17 +166,25 @@ notmuch_search_command (void *ctx, int argc, char *argv[]) notmuch_query_set_sort (query, sort); - if (max_threads < 0 || max_threads > NOTMUCH_SHOW_INITIAL_BURST) - { - do_search_threads (ctx, query, sort, - first, NOTMUCH_SHOW_INITIAL_BURST); + /* If we receive a max-threads option, then the user is + responsible for any chunking and we return all results at + once. */ + if (max_threads < 0) + chunk_size = NOTMUCH_SEARCH_INITIAL_CHUNK_SIZE; + else + chunk_size = max_threads; - first += NOTMUCH_SHOW_INITIAL_BURST; - if (max_threads > 0) - max_threads -= NOTMUCH_SHOW_INITIAL_BURST; - } + do { + threads_in_chunk = do_search_threads (ctx, query, sort, + first, chunk_size); + if (chunk_size == max_threads) + break; - do_search_threads (ctx, query, sort, first, max_threads); + first += chunk_size; + + chunk_size *= 2; + + } while (threads_in_chunk); notmuch_query_destroy (query); notmuch_database_close (notmuch);