Re: [PATCH v4 13/16] add indexopts to notmuch python bindings.
[notmuch-archives.git] / 92 / 960bc65c742329a4e41c0c6eea78be928b819a
1 Return-Path: <amthrax@awakening.csail.mit.edu>\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 72D4F429E26\r
6         for <notmuch@notmuchmail.org>; Mon,  7 Nov 2011 19:52:55 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id 7ZyQ4FG7tTRZ for <notmuch@notmuchmail.org>;\r
16         Mon,  7 Nov 2011 19:52:54 -0800 (PST)\r
17 Received: from dmz-mailsec-scanner-5.mit.edu (DMZ-MAILSEC-SCANNER-5.MIT.EDU\r
18         [18.7.68.34])\r
19         by olra.theworths.org (Postfix) with ESMTP id A7E71431FB6\r
20         for <notmuch@notmuchmail.org>; Mon,  7 Nov 2011 19:52:54 -0800 (PST)\r
21 X-AuditID: 12074422-b7ff56d00000092f-6d-4eb8a79603eb\r
22 Received: from mailhub-auth-3.mit.edu ( [18.9.21.43])\r
23         by dmz-mailsec-scanner-5.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id CF.5D.02351.697A8BE4; Mon,  7 Nov 2011 22:52:54 -0500 (EST)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-3.mit.edu (8.13.8/8.9.2) with ESMTP id pA83qr6e005768; \r
27         Mon, 7 Nov 2011 22:52:53 -0500\r
28 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91])\r
29         (authenticated bits=0)\r
30         (User authenticated as amdragon@ATHENA.MIT.EDU)\r
31         by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id pA83qqDi006906\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Mon, 7 Nov 2011 22:52:53 -0500 (EST)\r
34 Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.77)\r
35         (envelope-from <amthrax@awakening.csail.mit.edu>)\r
36         id 1RNcmX-00069H-0T; Mon, 07 Nov 2011 22:55:29 -0500\r
37 From: Austin Clements <amdragon@MIT.EDU>\r
38 To: notmuch@notmuchmail.org\r
39 Subject: [PATCH] tag: Automatically limit to messages whose tags will actually\r
40         change.\r
41 Date: Mon,  7 Nov 2011 22:55:23 -0500\r
42 Message-Id: <1320724523-23568-1-git-send-email-amdragon@mit.edu>\r
43 X-Mailer: git-send-email 1.7.7.1\r
44 X-Brightmail-Tracker:\r
45  H4sIAAAAAAAAA+NgFlrCIsWRmVeSWpSXmKPExsUixCmqrTtt+Q4/g0fL2C2u35zJ7MDo8WzV\r
46         LeYAxigum5TUnMyy1CJ9uwSujK4l55gKGlQqbr3fxt7AeFq6i5GTQ0LAROLH/68sELaYxIV7\r
47         69m6GLk4hAT2MUpc2tvODpIQEljPKPH+XChE4gSTxL8j35kgnM2MErvbFzODVLEJaEhs27+c\r
48         EcQWEZCW2Hl3NmsXIwcHs4CaxJ8uFRBTWCBMouOSHUgFi4CqxPsnE8A6eQUcJI7cnsQOUiIh\r
49         oCCxbEf1BEbeBYwMqxhlU3KrdHMTM3OKU5N1i5MT8/JSi3RN9XIzS/RSU0o3MYICgN1FaQfj\r
50         z4NKhxgFOBiVeHhniu7wE2JNLCuuzD3EKMnBpCTKG78UKMSXlJ9SmZFYnBFfVJqTWnyIUYKD\r
51         WUmEV6kJKMebklhZlVqUD5OS5mBREufl2ungJySQnliSmp2aWpBaBJOV4eBQkuA9sgyoUbAo\r
52         NT21Ii0zpwQhzcTBCTKcB2j4SZAa3uKCxNzizHSI/ClGXY7Tfy6dYhRiycvPS5US510FUiQA\r
53         UpRRmgc3Bxa5rxjFgd4S5t0PUsUDjHq4Sa+AljABLWnX3QaypCQRISXVwGi0tntGNNNn3p0l\r
54         5ZX/pEP53m16kHhohcS39BL+5oPFQtX+fdt6tR27f2z5LbHi9bTeO57q21L1WKrWL3kq2hUW\r
55         tbZbpry1fdu0LxNqvkxqeNwX7JkxaU+Vbh3rvX7vguasBsUKiborXbUSHVYzDjifOHX+zf//\r
56         yTLR0genp3aKvG7wWnaoX4mlOCPRUIu5qDgRAK3+uzi3AgAA\r
57 X-BeenThere: notmuch@notmuchmail.org\r
58 X-Mailman-Version: 2.1.13\r
59 Precedence: list\r
60 List-Id: "Use and development of the notmuch mail system."\r
61         <notmuch.notmuchmail.org>\r
62 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
63         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
64 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
65 List-Post: <mailto:notmuch@notmuchmail.org>\r
66 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
67 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
68         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
69 X-List-Received-Date: Tue, 08 Nov 2011 03:52:55 -0000\r
70 \r
71 This optimizes the user's tagging query to exclude messages that won't\r
72 be affected by the tagging operation, saving computation and IO for\r
73 redundant tagging operations.\r
74 \r
75 For example,\r
76   notmuch tag +notmuch to:notmuch@notmuchmail.org\r
77 will now use the query\r
78   ( to:notmuch@notmuchmail.org ) and (not tag:"notmuch")\r
79 \r
80 In the past, we've often suggested that people do this exact\r
81 transformation by hand for slow tagging operations.  This makes that\r
82 unnecessary.\r
83 ---\r
84 I was about to implement this optimization in my initial tagging\r
85 script, but then I figured, why not just do it in notmuch so we can\r
86 stop telling people to do this by hand?\r
87 \r
88  NEWS          |    9 ++++++\r
89  notmuch-tag.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r
90  2 files changed, 85 insertions(+), 0 deletions(-)\r
91 \r
92 diff --git a/NEWS b/NEWS\r
93 index e00452a..9ca5e0c 100644\r
94 --- a/NEWS\r
95 +++ b/NEWS\r
96 @@ -16,6 +16,15 @@ Add search terms to  "notmuch dump"\r
97    search/show/tag. The output file argument of dump is deprecated in\r
98    favour of using stdout.\r
99  \r
100 +Optimizations\r
101 +-------------\r
102 +\r
103 +Automatic tag query optimization\r
104 +\r
105 +  "notmuch tag" now automatically optimizes the user's query to\r
106 +  exclude messages whose tags won't change.  In the past, we've\r
107 +  suggested that people do this by hand; this is no longer necessary.\r
108 +\r
109  Notmuch 0.9 (2011-10-01)\r
110  ========================\r
111  \r
112 diff --git a/notmuch-tag.c b/notmuch-tag.c\r
113 index dded39e..62c4bf1 100644\r
114 --- a/notmuch-tag.c\r
115 +++ b/notmuch-tag.c\r
116 @@ -30,6 +30,76 @@ handle_sigint (unused (int sig))\r
117      interrupted = 1;\r
118  }\r
119  \r
120 +static char *\r
121 +_escape_tag (char *buf, const char *tag)\r
122 +{\r
123 +    const char *in = tag;\r
124 +    char *out = buf;\r
125 +    /* Boolean terms surrounded by double quotes can contain any\r
126 +     * character.  Double quotes are quoted by doubling them. */\r
127 +    *(out++) = '"';\r
128 +    while (*in) {\r
129 +       if (*in == '"')\r
130 +           *(out++) = '"';\r
131 +       *(out++) = *(in++);\r
132 +    }\r
133 +    *(out++) = '"';\r
134 +    *out = 0;\r
135 +    return buf;\r
136 +}\r
137 +\r
138 +static char *\r
139 +_optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[],\r
140 +                    int *add_tags, int add_tags_count,\r
141 +                    int *remove_tags, int remove_tags_count)\r
142 +{\r
143 +    /* This is subtler than it looks.  Xapian ignores the '-' operator\r
144 +     * at the beginning both queries and parenthesized groups and,\r
145 +     * furthermore, the presence of a '-' operator at the beginning of\r
146 +     * a group can inhibit parsing of the previous operator.  Hence,\r
147 +     * the user-provided query MUST appear first, but it is safe to\r
148 +     * parenthesize and the exclusion part of the query must not use\r
149 +     * the '-' operator (though the NOT operator is fine). */\r
150 +\r
151 +    char *escaped, *query_string;\r
152 +    const char *join = "";\r
153 +    int i;\r
154 +    unsigned int max_tag_len = 0;\r
155 +\r
156 +    /* Allocate a buffer for escaping tags. */\r
157 +    for (i = 0; i < add_tags_count; i++)\r
158 +       if (strlen (argv[add_tags[i]] + 1) > max_tag_len)\r
159 +           max_tag_len = strlen (argv[add_tags[i]] + 1);\r
160 +    for (i = 0; i < remove_tags_count; i++)\r
161 +       if (strlen (argv[remove_tags[i]] + 1) > max_tag_len)\r
162 +           max_tag_len = strlen (argv[remove_tags[i]] + 1);\r
163 +    escaped = talloc_array(ctx, char, max_tag_len * 2 + 3);\r
164 +\r
165 +    /* Build the new query string */\r
166 +    if (strcmp (orig_query_string, "*") == 0)\r
167 +       query_string = talloc_strdup (ctx, "(");\r
168 +    else\r
169 +       query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string);\r
170 +\r
171 +    for (i = 0; i < add_tags_count; i++) {\r
172 +       query_string = talloc_asprintf_append_buffer (\r
173 +           query_string, "%snot tag:%s", join,\r
174 +           _escape_tag (escaped, argv[add_tags[i]] + 1));\r
175 +       join = " or ";\r
176 +    }\r
177 +    for (i = 0; i < remove_tags_count; i++) {\r
178 +       query_string = talloc_asprintf_append_buffer (\r
179 +           query_string, "%stag:%s", join,\r
180 +           _escape_tag (escaped, argv[remove_tags[i]] + 1));\r
181 +       join = " or ";\r
182 +    }\r
183 +\r
184 +    query_string = talloc_strdup_append_buffer (query_string, ")");\r
185 +\r
186 +    talloc_free (escaped);\r
187 +    return query_string;\r
188 +}\r
189 +\r
190  int\r
191  notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[]))\r
192  {\r
193 @@ -93,6 +163,12 @@ notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[]))\r
194         return 1;\r
195      }\r
196  \r
197 +    /* Optimize the query so it excludes messages that already have\r
198 +     * the specified set of tags. */\r
199 +    query_string = _optimize_tag_query (ctx, query_string, argv,\r
200 +                                       add_tags, add_tags_count,\r
201 +                                       remove_tags, remove_tags_count);\r
202 +\r
203      config = notmuch_config_open (ctx, NULL, NULL);\r
204      if (config == NULL)\r
205         return 1;\r
206 -- \r
207 1.7.7.1\r
208 \r