[RFC PATCH] test: add devel/test-in-docker.sh
[notmuch-archives.git] / a8 / 69f94562b731b9f8b69d3d222467d169d79adc
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 4603A431FB6\r
6         for <notmuch@notmuchmail.org>; Thu,  9 Dec 2010 13:00:17 -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\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none]\r
12         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 gQfeb00aapUE for <notmuch@notmuchmail.org>;\r
16         Thu,  9 Dec 2010 13:00:16 -0800 (PST)\r
17 Received: from dmz-mailsec-scanner-6.mit.edu (DMZ-MAILSEC-SCANNER-6.MIT.EDU\r
18         [18.7.68.35])\r
19         by olra.theworths.org (Postfix) with ESMTP id 59FC7431FB5\r
20         for <notmuch@notmuchmail.org>; Thu,  9 Dec 2010 13:00:16 -0800 (PST)\r
21 X-AuditID: 12074423-b7bd0ae000000a00-66-4d01435e3c07\r
22 Received: from mailhub-auth-1.mit.edu ( [18.9.21.35])\r
23         by dmz-mailsec-scanner-6.mit.edu (Symantec Brightmail Gateway) with\r
24         SMTP id 02.2A.02560.F53410D4; Thu,  9 Dec 2010 16:00:15 -0500 (EST)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-1.mit.edu (8.13.8/8.9.2) with ESMTP id oB9L0EEE011330; \r
27         Thu, 9 Dec 2010 16:00:14 -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 oB9L0CZh010008\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Thu, 9 Dec 2010 16:00:13 -0500 (EST)\r
34 Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.72)\r
35         (envelope-from <amthrax@awakening.csail.mit.edu>)\r
36         id 1PQnb2-0007Hk-SH; Thu, 09 Dec 2010 16:00:12 -0500\r
37 From: Austin Clements <amdragon@MIT.EDU>\r
38 To: notmuch@notmuchmail.org\r
39 Subject: [PATCH 1/5] Use a single unified pass to fetch scalar message\r
40         metadata.\r
41 Date: Thu,  9 Dec 2010 15:59:52 -0500\r
42 Message-Id: <1291928396-27937-2-git-send-email-amdragon@mit.edu>\r
43 X-Mailer: git-send-email 1.7.2.3\r
44 In-Reply-To: <1291928396-27937-1-git-send-email-amdragon@mit.edu>\r
45 References: <1291928396-27937-1-git-send-email-amdragon@mit.edu>\r
46 X-Brightmail-Tracker: AAAAARbjX5o=\r
47 Cc: Austin Clements <amdragon@mit.edu>\r
48 X-BeenThere: notmuch@notmuchmail.org\r
49 X-Mailman-Version: 2.1.13\r
50 Precedence: list\r
51 List-Id: "Use and development of the notmuch mail system."\r
52         <notmuch.notmuchmail.org>\r
53 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
54         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
55 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
56 List-Post: <mailto:notmuch@notmuchmail.org>\r
57 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
58 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
59         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
60 X-List-Received-Date: Thu, 09 Dec 2010 21:00:17 -0000\r
61 \r
62 This performs a single pass over a message's term list to fetch the\r
63 thread ID, message ID, and reply-to, rather than requiring a pass for\r
64 each.  Xapian decompresses the term list anew for each iteration, so\r
65 this reduces the amount of time spent decompressing message metadata.\r
66 \r
67 This reduces my inbox search from 3.102 seconds to 2.555 seconds (1.2X\r
68 faster).\r
69 ---\r
70  lib/message.cc |  197 ++++++++++++++++++++++++++++----------------------------\r
71  1 files changed, 98 insertions(+), 99 deletions(-)\r
72 \r
73 diff --git a/lib/message.cc b/lib/message.cc\r
74 index adcd07d..d6ab636 100644\r
75 --- a/lib/message.cc\r
76 +++ b/lib/message.cc\r
77 @@ -254,41 +254,106 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,\r
78      return message;\r
79  }\r
80  \r
81 -unsigned int\r
82 -_notmuch_message_get_doc_id (notmuch_message_t *message)\r
83 -{\r
84 -    return message->doc_id;\r
85 -}\r
86 -\r
87 -const char *\r
88 -notmuch_message_get_message_id (notmuch_message_t *message)\r
89 +static char *\r
90 +_notmuch_message_get_term (notmuch_message_t *message,\r
91 +                          Xapian::TermIterator &i, Xapian::TermIterator &end,\r
92 +                          const char *prefix)\r
93  {\r
94 -    Xapian::TermIterator i;\r
95 +    int prefix_len = strlen (prefix);\r
96 +    const char *term = NULL;\r
97 +    char *value;\r
98  \r
99 -    if (message->message_id)\r
100 -       return message->message_id;\r
101 +    i.skip_to (prefix);\r
102  \r
103 -    i = message->doc.termlist_begin ();\r
104 -    i.skip_to (_find_prefix ("id"));\r
105 +    if (i != end)\r
106 +       term = (*i).c_str ();\r
107  \r
108 -    if (i == message->doc.termlist_end ())\r
109 -       INTERNAL_ERROR ("Message with document ID of %d has no message ID.\n",\r
110 -                       message->doc_id);\r
111 +    if (!term || strncmp (term, prefix, prefix_len))\r
112 +       return NULL;\r
113  \r
114 -    message->message_id = talloc_strdup (message, (*i).c_str () + 1);\r
115 +    value = talloc_strdup (message, term + prefix_len);\r
116  \r
117  #if DEBUG_DATABASE_SANITY\r
118      i++;\r
119  \r
120 -    if (i != message->doc.termlist_end () &&\r
121 -       strncmp ((*i).c_str (), _find_prefix ("id"),\r
122 -                strlen (_find_prefix ("id"))) == 0)\r
123 -    {\r
124 -       INTERNAL_ERROR ("Mail (doc_id: %d) has duplicate message IDs",\r
125 -                       message->doc_id);\r
126 +    if (i != end && strncmp ((*i).c_str (), prefix, prefix_len) == 0) {\r
127 +       INTERNAL_ERROR ("Mail (doc_id: %d) has duplicate %s terms: %s and %s\n",\r
128 +                       message->doc_id, prefix, value,\r
129 +                       (*i).c_str () + prefix_len);\r
130      }\r
131  #endif\r
132  \r
133 +    return value;\r
134 +}\r
135 +\r
136 +void\r
137 +_notmuch_message_ensure_metadata (notmuch_message_t *message)\r
138 +{\r
139 +    Xapian::TermIterator i, end;\r
140 +    const char *thread_prefix = _find_prefix ("thread"),\r
141 +       *id_prefix = _find_prefix ("id"),\r
142 +       *replyto_prefix = _find_prefix ("replyto");\r
143 +\r
144 +    /* We do this all in a single pass because Xapian decompresses the\r
145 +     * term list every time you iterate over it.  Thus, while this is\r
146 +     * slightly more costly than looking up individual fields if only\r
147 +     * one field of the message object is actually used, it's a huge\r
148 +     * win as more fields are used. */\r
149 +\r
150 +    i = message->doc.termlist_begin ();\r
151 +    end = message->doc.termlist_end ();\r
152 +\r
153 +    /* Get thread */\r
154 +    if (!message->thread_id)\r
155 +       message->thread_id =\r
156 +           _notmuch_message_get_term (message, i, end, thread_prefix);\r
157 +\r
158 +    /* Get id */\r
159 +    assert (strcmp (thread_prefix, id_prefix) < 0);\r
160 +    if (!message->message_id)\r
161 +       message->message_id =\r
162 +           _notmuch_message_get_term (message, i, end, id_prefix);\r
163 +\r
164 +    /* Get reply to */\r
165 +    assert (strcmp (id_prefix, replyto_prefix) < 0);\r
166 +    if (!message->in_reply_to)\r
167 +       message->in_reply_to =\r
168 +           _notmuch_message_get_term (message, i, end, replyto_prefix);\r
169 +    /* It's perfectly valid for a message to have no In-Reply-To\r
170 +     * header. For these cases, we return an empty string. */\r
171 +    if (!message->in_reply_to)\r
172 +       message->in_reply_to = talloc_strdup (message, "");\r
173 +}\r
174 +\r
175 +static void\r
176 +_notmuch_message_invalidate_metadata (notmuch_message_t *message,\r
177 +                                     const char *prefix_name)\r
178 +{\r
179 +    if (strcmp ("thread", prefix_name) == 0) {\r
180 +       talloc_free (message->thread_id);\r
181 +       message->thread_id = NULL;\r
182 +    }\r
183 +\r
184 +    if (strcmp ("replyto", prefix_name) == 0) {\r
185 +       talloc_free (message->in_reply_to);\r
186 +       message->in_reply_to = NULL;\r
187 +    }\r
188 +}\r
189 +\r
190 +unsigned int\r
191 +_notmuch_message_get_doc_id (notmuch_message_t *message)\r
192 +{\r
193 +    return message->doc_id;\r
194 +}\r
195 +\r
196 +const char *\r
197 +notmuch_message_get_message_id (notmuch_message_t *message)\r
198 +{\r
199 +    if (!message->message_id)\r
200 +       _notmuch_message_ensure_metadata (message);\r
201 +    if (!message->message_id)\r
202 +       INTERNAL_ERROR ("Message with document ID of %u has no message ID.\n",\r
203 +                       message->doc_id);\r
204      return message->message_id;\r
205  }\r
206  \r
207 @@ -327,89 +392,19 @@ notmuch_message_get_header (notmuch_message_t *message, const char *header)\r
208  const char *\r
209  _notmuch_message_get_in_reply_to (notmuch_message_t *message)\r
210  {\r
211 -    const char *prefix = _find_prefix ("replyto");\r
212 -    int prefix_len = strlen (prefix);\r
213 -    Xapian::TermIterator i;\r
214 -    std::string in_reply_to;\r
215 -\r
216 -    if (message->in_reply_to)\r
217 -       return message->in_reply_to;\r
218 -\r
219 -    i = message->doc.termlist_begin ();\r
220 -    i.skip_to (prefix);\r
221 -\r
222 -    if (i != message->doc.termlist_end ())\r
223 -       in_reply_to = *i;\r
224 -\r
225 -    /* It's perfectly valid for a message to have no In-Reply-To\r
226 -     * header. For these cases, we return an empty string. */\r
227 -    if (i == message->doc.termlist_end () ||\r
228 -       strncmp (in_reply_to.c_str (), prefix, prefix_len))\r
229 -    {\r
230 -       message->in_reply_to = talloc_strdup (message, "");\r
231 -       return message->in_reply_to;\r
232 -    }\r
233 -\r
234 -    message->in_reply_to = talloc_strdup (message,\r
235 -                                         in_reply_to.c_str () + prefix_len);\r
236 -\r
237 -#if DEBUG_DATABASE_SANITY\r
238 -    i++;\r
239 -\r
240 -    in_reply_to = *i;\r
241 -\r
242 -    if (i != message->doc.termlist_end () &&\r
243 -       strncmp ((*i).c_str (), prefix, prefix_len) == 0)\r
244 -    {\r
245 -       INTERNAL_ERROR ("Message %s has duplicate In-Reply-To IDs: %s and %s\n",\r
246 -                       notmuch_message_get_message_id (message),\r
247 -                       message->in_reply_to,\r
248 -                       (*i).c_str () + prefix_len);\r
249 -    }\r
250 -#endif\r
251 -\r
252 +    if (!message->in_reply_to)\r
253 +       _notmuch_message_ensure_metadata (message);\r
254      return message->in_reply_to;\r
255  }\r
256  \r
257  const char *\r
258  notmuch_message_get_thread_id (notmuch_message_t *message)\r
259  {\r
260 -    const char *prefix = _find_prefix ("thread");\r
261 -    Xapian::TermIterator i;\r
262 -    std::string id;\r
263 -\r
264 -    /* This code is written with the assumption that "thread" has a\r
265 -     * single-character prefix. */\r
266 -    assert (strlen (prefix) == 1);\r
267 -\r
268 -    if (message->thread_id)\r
269 -       return message->thread_id;\r
270 -\r
271 -    i = message->doc.termlist_begin ();\r
272 -    i.skip_to (prefix);\r
273 -\r
274 -    if (i != message->doc.termlist_end ())\r
275 -       id = *i;\r
276 -\r
277 -    if (i == message->doc.termlist_end () || id[0] != *prefix)\r
278 -       INTERNAL_ERROR ("Message with document ID of %d has no thread ID.\n",\r
279 +    if (!message->thread_id)\r
280 +       _notmuch_message_ensure_metadata (message);\r
281 +    if (!message->thread_id)\r
282 +       INTERNAL_ERROR ("Message with document ID of %u has no thread ID.\n",\r
283                         message->doc_id);\r
284 -\r
285 -    message->thread_id = talloc_strdup (message, id.c_str () + 1);\r
286 -\r
287 -#if DEBUG_DATABASE_SANITY\r
288 -    i++;\r
289 -    id = *i;\r
290 -\r
291 -    if (i != message->doc.termlist_end () && id[0] == *prefix)\r
292 -    {\r
293 -       INTERNAL_ERROR ("Message %s has duplicate thread IDs: %s and %s\n",\r
294 -                       notmuch_message_get_message_id (message),\r
295 -                       message->thread_id,\r
296 -                       id.c_str () + 1);\r
297 -    }\r
298 -#endif\r
299 -\r
300      return message->thread_id;\r
301  }\r
302  \r
303 @@ -738,6 +733,8 @@ _notmuch_message_add_term (notmuch_message_t *message,\r
304  \r
305      talloc_free (term);\r
306  \r
307 +    _notmuch_message_invalidate_metadata (message, prefix_name);\r
308 +\r
309      return NOTMUCH_PRIVATE_STATUS_SUCCESS;\r
310  }\r
311  \r
312 @@ -801,6 +798,8 @@ _notmuch_message_remove_term (notmuch_message_t *message,\r
313  \r
314      talloc_free (term);\r
315  \r
316 +    _notmuch_message_invalidate_metadata (message, prefix_name);\r
317 +\r
318      return NOTMUCH_PRIVATE_STATUS_SUCCESS;\r
319  }\r
320  \r
321 -- \r
322 1.7.2.3\r
323 \r