1 Return-Path: <dmitry.kurochkin@gmail.com>
\r
2 X-Original-To: notmuch@notmuchmail.org
\r
3 Delivered-To: notmuch@notmuchmail.org
\r
4 Received: from localhost (localhost [127.0.0.1])
\r
5 by olra.theworths.org (Postfix) with ESMTP id 71F5B429E27
\r
6 for <notmuch@notmuchmail.org>; Mon, 7 Nov 2011 20:34:53 -0800 (PST)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=-0.799 tagged_above=-999 required=5
\r
12 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,
\r
13 FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled
\r
14 Received: from olra.theworths.org ([127.0.0.1])
\r
15 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
16 with ESMTP id szeFB-HruJIX for <notmuch@notmuchmail.org>;
\r
17 Mon, 7 Nov 2011 20:34:52 -0800 (PST)
\r
18 Received: from mail-bw0-f53.google.com (mail-bw0-f53.google.com
\r
19 [209.85.214.53]) (using TLSv1 with cipher RC4-SHA (128/128 bits))
\r
20 (No client certificate requested)
\r
21 by olra.theworths.org (Postfix) with ESMTPS id 4D065431FB6
\r
22 for <notmuch@notmuchmail.org>; Mon, 7 Nov 2011 20:34:52 -0800 (PST)
\r
23 Received: by bkaq10 with SMTP id q10so88250bka.26
\r
24 for <notmuch@notmuchmail.org>; Mon, 07 Nov 2011 20:34:49 -0800 (PST)
\r
25 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;
\r
26 h=from:to:subject:in-reply-to:references:user-agent:date:message-id
\r
27 :mime-version:content-type;
\r
28 bh=guJO5VtJYdYEu5Ut/R+jv3pK/W4WgiY4akkXkDp4hCA=;
\r
29 b=Xq27+zSA9iOEiz4s/Se6LWSBAibdfEUH+F54YXGeiwxCY8v0Gvzli/aDzWVXPNi9gR
\r
30 UHNmV2ZEmYCduxWYt0eqaJ9bjCyZcjzlhHRKlAxiOmzFuSz9Zj1/JtqX6QCOOqAD6vqH
\r
31 WDkqx5Bhuda1FRRzVfuIlf/GjeUMgvPfrGw8I=
\r
32 Received: by 10.204.9.205 with SMTP id m13mr21080663bkm.32.1320726884572;
\r
33 Mon, 07 Nov 2011 20:34:44 -0800 (PST)
\r
34 Received: from localhost ([91.144.186.21])
\r
35 by mx.google.com with ESMTPS id z15sm233074bkv.4.2011.11.07.20.34.42
\r
36 (version=TLSv1/SSLv3 cipher=OTHER);
\r
37 Mon, 07 Nov 2011 20:34:43 -0800 (PST)
\r
38 From: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>
\r
39 To: Austin Clements <amdragon@MIT.EDU>, notmuch@notmuchmail.org
\r
40 Subject: Re: [PATCH] tag: Automatically limit to messages whose tags will
\r
42 In-Reply-To: <1320724523-23568-1-git-send-email-amdragon@mit.edu>
\r
43 References: <1320724523-23568-1-git-send-email-amdragon@mit.edu>
\r
44 User-Agent: Notmuch/0.9+34~g27fff04 (http://notmuchmail.org) Emacs/23.3.1
\r
45 (x86_64-pc-linux-gnu)
\r
46 Date: Tue, 08 Nov 2011 08:34:32 +0400
\r
47 Message-ID: <878vnrut9j.fsf@gmail.com>
\r
49 Content-Type: text/plain; charset=us-ascii
\r
50 X-BeenThere: notmuch@notmuchmail.org
\r
51 X-Mailman-Version: 2.1.13
\r
53 List-Id: "Use and development of the notmuch mail system."
\r
54 <notmuch.notmuchmail.org>
\r
55 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
56 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
57 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
58 List-Post: <mailto:notmuch@notmuchmail.org>
\r
59 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
60 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
61 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
62 X-List-Received-Date: Tue, 08 Nov 2011 04:34:53 -0000
\r
66 On Mon, 7 Nov 2011 22:55:23 -0500, Austin Clements <amdragon@MIT.EDU> wrote:
\r
67 > This optimizes the user's tagging query to exclude messages that won't
\r
68 > be affected by the tagging operation, saving computation and IO for
\r
69 > redundant tagging operations.
\r
72 > notmuch tag +notmuch to:notmuch@notmuchmail.org
\r
73 > will now use the query
\r
74 > ( to:notmuch@notmuchmail.org ) and (not tag:"notmuch")
\r
76 > In the past, we've often suggested that people do this exact
\r
77 > transformation by hand for slow tagging operations. This makes that
\r
80 Thanks! This is a very useful optimization.
\r
82 Does it work for multiple tags and tag removal? I.e.:
\r
84 notmuch tag -inbox -unread +sent from:dmitry.kurochkin@gmail.com
\r
86 can be converted to:
\r
88 notmuch tag -inbox -unread +sent from:dmitry.kurochkin@gmail.com and (tag:inbox or tag:unread or (not tag:sent))
\r
94 > I was about to implement this optimization in my initial tagging
\r
95 > script, but then I figured, why not just do it in notmuch so we can
\r
96 > stop telling people to do this by hand?
\r
99 > notmuch-tag.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
\r
100 > 2 files changed, 85 insertions(+), 0 deletions(-)
\r
102 > diff --git a/NEWS b/NEWS
\r
103 > index e00452a..9ca5e0c 100644
\r
106 > @@ -16,6 +16,15 @@ Add search terms to "notmuch dump"
\r
107 > search/show/tag. The output file argument of dump is deprecated in
\r
108 > favour of using stdout.
\r
113 > +Automatic tag query optimization
\r
115 > + "notmuch tag" now automatically optimizes the user's query to
\r
116 > + exclude messages whose tags won't change. In the past, we've
\r
117 > + suggested that people do this by hand; this is no longer necessary.
\r
119 > Notmuch 0.9 (2011-10-01)
\r
120 > ========================
\r
122 > diff --git a/notmuch-tag.c b/notmuch-tag.c
\r
123 > index dded39e..62c4bf1 100644
\r
124 > --- a/notmuch-tag.c
\r
125 > +++ b/notmuch-tag.c
\r
126 > @@ -30,6 +30,76 @@ handle_sigint (unused (int sig))
\r
131 > +_escape_tag (char *buf, const char *tag)
\r
133 > + const char *in = tag;
\r
134 > + char *out = buf;
\r
135 > + /* Boolean terms surrounded by double quotes can contain any
\r
136 > + * character. Double quotes are quoted by doubling them. */
\r
137 > + *(out++) = '"';
\r
139 > + if (*in == '"')
\r
140 > + *(out++) = '"';
\r
141 > + *(out++) = *(in++);
\r
143 > + *(out++) = '"';
\r
149 > +_optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[],
\r
150 > + int *add_tags, int add_tags_count,
\r
151 > + int *remove_tags, int remove_tags_count)
\r
153 > + /* This is subtler than it looks. Xapian ignores the '-' operator
\r
154 > + * at the beginning both queries and parenthesized groups and,
\r
155 > + * furthermore, the presence of a '-' operator at the beginning of
\r
156 > + * a group can inhibit parsing of the previous operator. Hence,
\r
157 > + * the user-provided query MUST appear first, but it is safe to
\r
158 > + * parenthesize and the exclusion part of the query must not use
\r
159 > + * the '-' operator (though the NOT operator is fine). */
\r
161 > + char *escaped, *query_string;
\r
162 > + const char *join = "";
\r
164 > + unsigned int max_tag_len = 0;
\r
166 > + /* Allocate a buffer for escaping tags. */
\r
167 > + for (i = 0; i < add_tags_count; i++)
\r
168 > + if (strlen (argv[add_tags[i]] + 1) > max_tag_len)
\r
169 > + max_tag_len = strlen (argv[add_tags[i]] + 1);
\r
170 > + for (i = 0; i < remove_tags_count; i++)
\r
171 > + if (strlen (argv[remove_tags[i]] + 1) > max_tag_len)
\r
172 > + max_tag_len = strlen (argv[remove_tags[i]] + 1);
\r
173 > + escaped = talloc_array(ctx, char, max_tag_len * 2 + 3);
\r
175 > + /* Build the new query string */
\r
176 > + if (strcmp (orig_query_string, "*") == 0)
\r
177 > + query_string = talloc_strdup (ctx, "(");
\r
179 > + query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);
\r
181 > + for (i = 0; i < add_tags_count; i++) {
\r
182 > + query_string = talloc_asprintf_append_buffer (
\r
183 > + query_string, "%snot tag:%s", join,
\r
184 > + _escape_tag (escaped, argv[add_tags[i]] + 1));
\r
187 > + for (i = 0; i < remove_tags_count; i++) {
\r
188 > + query_string = talloc_asprintf_append_buffer (
\r
189 > + query_string, "%stag:%s", join,
\r
190 > + _escape_tag (escaped, argv[remove_tags[i]] + 1));
\r
194 > + query_string = talloc_strdup_append_buffer (query_string, ")");
\r
196 > + talloc_free (escaped);
\r
197 > + return query_string;
\r
201 > notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[]))
\r
203 > @@ -93,6 +163,12 @@ notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[]))
\r
207 > + /* Optimize the query so it excludes messages that already have
\r
208 > + * the specified set of tags. */
\r
209 > + query_string = _optimize_tag_query (ctx, query_string, argv,
\r
210 > + add_tags, add_tags_count,
\r
211 > + remove_tags, remove_tags_count);
\r
213 > config = notmuch_config_open (ctx, NULL, NULL);
\r
214 > if (config == NULL)
\r
219 > _______________________________________________
\r
220 > notmuch mailing list
\r
221 > notmuch@notmuchmail.org
\r
222 > http://notmuchmail.org/mailman/listinfo/notmuch
\r