Re: [PATCH] create .mailmap file (for git shortlog/blame)
[notmuch-archives.git] / e3 / 5ab120c17944ee0e2f58e44024726c73608f2e
1 Return-Path: <aclements@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 1F458429E40\r
6         for <notmuch@notmuchmail.org>; Fri,  3 Oct 2014 07:19:59 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -2.3\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-2.3 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_MED=-2.3] 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 McwXxeHu-v1x for <notmuch@notmuchmail.org>;\r
16         Fri,  3 Oct 2014 07:19:51 -0700 (PDT)\r
17 Received: from dmz-mailsec-scanner-4.mit.edu (dmz-mailsec-scanner-4.mit.edu\r
18         [18.9.25.15])\r
19         (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\r
20         (No client certificate requested)\r
21         by olra.theworths.org (Postfix) with ESMTPS id BA631431FD5\r
22         for <notmuch@notmuchmail.org>; Fri,  3 Oct 2014 07:19:29 -0700 (PDT)\r
23 X-AuditID: 1209190f-f79aa6d000005b45-b9-542eb07123d2\r
24 Received: from mailhub-auth-1.mit.edu ( [18.9.21.35])\r
25         (using TLS with cipher AES256-SHA (256/256 bits))\r
26         (Client did not present a certificate)\r
27         by dmz-mailsec-scanner-4.mit.edu (Symantec Messaging Gateway) with SMTP\r
28         id 8D.24.23365.170BE245; Fri,  3 Oct 2014 10:19:29 -0400 (EDT)\r
29 Received: from outgoing.mit.edu (outgoing-auth-1.mit.edu [18.9.28.11])\r
30         by mailhub-auth-1.mit.edu (8.13.8/8.9.2) with ESMTP id s93EJOTE006610; \r
31         Fri, 3 Oct 2014 10:19:25 -0400\r
32 Received: from drake.dyndns.org\r
33         (216-15-114-40.c3-0.arl-ubr1.sbo-arl.ma.cable.rcn.com\r
34         [216.15.114.40]) (authenticated bits=0)\r
35         (User authenticated as amdragon@ATHENA.MIT.EDU)\r
36         by outgoing.mit.edu (8.13.8/8.12.4) with ESMTP id s93EJL8t023318\r
37         (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NOT);\r
38         Fri, 3 Oct 2014 10:19:24 -0400\r
39 Received: from amthrax by drake.dyndns.org with local (Exim 4.84)\r
40         (envelope-from <aclements@csail.mit.edu>)\r
41         id 1Xa3hZ-0002K2-7z; Fri, 03 Oct 2014 10:19:21 -0400\r
42 From: Austin Clements <aclements@csail.mit.edu>\r
43 To: notmuch@notmuchmail.org\r
44 Subject: [PATCH 07/11] lib: Implement ghost-based thread linking\r
45 Date: Fri,  3 Oct 2014 10:19:14 -0400\r
46 Message-Id: <1412345958-8278-8-git-send-email-aclements@csail.mit.edu>\r
47 X-Mailer: git-send-email 2.1.0\r
48 In-Reply-To: <1412345958-8278-1-git-send-email-aclements@csail.mit.edu>\r
49 References: <1412345958-8278-1-git-send-email-aclements@csail.mit.edu>\r
50 X-Brightmail-Tracker:\r
51  H4sIAAAAAAAAA+NgFtrEIsWRmVeSWpSXmKPExsUixCmqrFu4QS/EYPM7eYvrN2cyOzB6PFt1\r
52         izmAMYrLJiU1J7MstUjfLoErY/HWBcwFU80rWufkNDC263QxcnJICJhITOxYwQJhi0lcuLee\r
53         rYuRi0NIYDaTxLL5t5khnA2MEhsPbGaFcG4zSTy+eQLKWcIo8al3Blg/m4C+xIq1k1hBbBEB\r
54         aYmdd2cD2RwczAJqEn+6VEDCwgIOEuferwcrYRFQlTj4YydYK6+Am0T3xZWMEGfISWzY/R/M\r
55         5hRwl7hw9ykbiC0EVLPqWDfbBEb+BYwMqxhlU3KrdHMTM3OKU5N1i5MT8/JSi3RN9HIzS/RS\r
56         U0o3MYKDRpJ/B+O3g0qHGAU4GJV4eD/c0A0RYk0sK67MPcQoycGkJMpbuVgvRIgvKT+lMiOx\r
57         OCO+qDQntfgQowQHs5II74KVQDnelMTKqtSifJiUNAeLkjjvph98IUIC6YklqdmpqQWpRTBZ\r
58         GQ4OJQne9vVAjYJFqempFWmZOSUIaSYOTpDhPEDDwWp4iwsSc4sz0yHypxgVpcR5H64DSgiA\r
59         JDJK8+B6YVH9ilEc6BVhXiZgjAvxABMCXPcroMFMQIPf2euCDC5JREhJNTDyesh++tL69OIq\r
60         v/IbzxjEovfHxijM35qs5qm7xumz/IcbM61KV4j/arZV/lN8NPv0djsuAb9tUeckzUv/pfD/\r
61         yduwec29Vr3XLy4Itl87od1ua8Wz/0z3yV/WB5c8vnvr3gSDqduf7C10tZV/s4h5d22gq/Su\r
62         ba/2crCeyZ7Rcs1+6ofJLztmKbEUZyQaajEXFScCACZ0yFfFAgAA\r
63 X-BeenThere: notmuch@notmuchmail.org\r
64 X-Mailman-Version: 2.1.13\r
65 Precedence: list\r
66 List-Id: "Use and development of the notmuch mail system."\r
67         <notmuch.notmuchmail.org>\r
68 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
69         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
70 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
71 List-Post: <mailto:notmuch@notmuchmail.org>\r
72 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
73 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
74         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
75 X-List-Received-Date: Fri, 03 Oct 2014 14:19:59 -0000\r
76 \r
77 From: Austin Clements <amdragon@mit.edu>\r
78 \r
79 This updates the thread linking code to use ghost messages instead of\r
80 user metadata to link messages into threads.\r
81 \r
82 In contrast with the old approach, this is actually correct.\r
83 Previously, thread merging updated only the thread IDs of message\r
84 documents, not thread IDs stored in user metadata.  As originally\r
85 diagnosed by Mark Walters [1] and as demonstrated by the broken\r
86 T260-thread-order test, this can cause notmuch to fail to link\r
87 messages even though they're in the same thread.  In principle the old\r
88 approach could have been fixed by updating the user metadata thread\r
89 IDs as well, but these are not indexed and hence this would have\r
90 required a full scan of all stored thread IDs.  Ghost messages solve\r
91 this problem naturally by reusing the exact same thread ID and message\r
92 ID representation and indexing as regular messages.\r
93 \r
94 Furthermore, thanks to this greater symmetry, ghost messages are also\r
95 algorithmically simpler.  We continue to support the old user metadata\r
96 format, so this patch can't delete any code, but when we do remove\r
97 support for the old format, several functions can simply be deleted.\r
98 \r
99 [1] id:8738h7kv2q.fsf@qmul.ac.uk\r
100 ---\r
101  lib/database.cc | 86 +++++++++++++++++++++++++++++++++++++++++++++++++--------\r
102  1 file changed, 75 insertions(+), 11 deletions(-)\r
103 \r
104 diff --git a/lib/database.cc b/lib/database.cc\r
105 index c641bcd..fdcc526 100644\r
106 --- a/lib/database.cc\r
107 +++ b/lib/database.cc\r
108 @@ -1752,6 +1752,12 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)\r
109                             message_id);\r
110  }\r
111  \r
112 +static notmuch_status_t\r
113 +_resolve_message_id_to_thread_id_old (notmuch_database_t *notmuch,\r
114 +                                     void *ctx,\r
115 +                                     const char *message_id,\r
116 +                                     const char **thread_id_ret);\r
117 +\r
118  /* Find the thread ID to which the message with 'message_id' belongs.\r
119   *\r
120   * Note: 'thread_id_ret' must not be NULL!\r
121 @@ -1760,9 +1766,9 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)\r
122   *\r
123   * Note: If there is no message in the database with the given\r
124   * 'message_id' then a new thread_id will be allocated for this\r
125 - * message and stored in the database metadata, (where this same\r
126 + * message ID and stored in the database metadata so that the\r
127   * thread ID can be looked up if the message is added to the database\r
128 - * later).\r
129 + * later.\r
130   */\r
131  static notmuch_status_t\r
132  _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,\r
133 @@ -1770,6 +1776,49 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,\r
134                                   const char *message_id,\r
135                                   const char **thread_id_ret)\r
136  {\r
137 +    notmuch_private_status_t status;\r
138 +    notmuch_message_t *message;\r
139 +\r
140 +    if (! (notmuch->features & NOTMUCH_FEATURE_GHOSTS))\r
141 +       return _resolve_message_id_to_thread_id_old (notmuch, ctx, message_id,\r
142 +                                                    thread_id_ret);\r
143 +\r
144 +    /* Look for this message (regular or ghost) */\r
145 +    message = _notmuch_message_create_for_message_id (\r
146 +       notmuch, message_id, &status);\r
147 +    if (status == NOTMUCH_PRIVATE_STATUS_SUCCESS) {\r
148 +       /* Message exists */\r
149 +       *thread_id_ret = talloc_steal (\r
150 +           ctx, notmuch_message_get_thread_id (message));\r
151 +    } else if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) {\r
152 +       /* Message did not exist.  Give it a fresh thread ID and\r
153 +        * populate this message as a ghost message. */\r
154 +       *thread_id_ret = talloc_strdup (\r
155 +           ctx, _notmuch_database_generate_thread_id (notmuch));\r
156 +       if (! *thread_id_ret) {\r
157 +           status = NOTMUCH_PRIVATE_STATUS_OUT_OF_MEMORY;\r
158 +       } else {\r
159 +           status = _notmuch_message_initialize_ghost (message, *thread_id_ret);\r
160 +           if (status == 0)\r
161 +               /* Commit the new ghost message */\r
162 +               _notmuch_message_sync (message);\r
163 +       }\r
164 +    } else {\r
165 +       /* Create failed. Fall through. */\r
166 +    }\r
167 +\r
168 +    notmuch_message_destroy (message);\r
169 +\r
170 +    return COERCE_STATUS (status, "Error creating ghost message");\r
171 +}\r
172 +\r
173 +/* Pre-ghost messages _resolve_message_id_to_thread_id */\r
174 +static notmuch_status_t\r
175 +_resolve_message_id_to_thread_id_old (notmuch_database_t *notmuch,\r
176 +                                     void *ctx,\r
177 +                                     const char *message_id,\r
178 +                                     const char **thread_id_ret)\r
179 +{\r
180      notmuch_status_t status;\r
181      notmuch_message_t *message;\r
182      string thread_id_string;\r
183 @@ -2007,7 +2056,7 @@ _consume_metadata_thread_id (void *ctx, notmuch_database_t *notmuch,\r
184      }\r
185  }\r
186  \r
187 -/* Given a (mostly empty) 'message' and its corresponding\r
188 +/* Given a blank or ghost 'message' and its corresponding\r
189   * 'message_file' link it to existing threads in the database.\r
190   *\r
191   * The first check is in the metadata of the database to see if we\r
192 @@ -2035,16 +2084,22 @@ _consume_metadata_thread_id (void *ctx, notmuch_database_t *notmuch,\r
193  static notmuch_status_t\r
194  _notmuch_database_link_message (notmuch_database_t *notmuch,\r
195                                 notmuch_message_t *message,\r
196 -                               notmuch_message_file_t *message_file)\r
197 +                               notmuch_message_file_t *message_file,\r
198 +                               notmuch_bool_t is_ghost)\r
199  {\r
200      void *local = talloc_new (NULL);\r
201      notmuch_status_t status;\r
202 -    const char *thread_id;\r
203 +    const char *thread_id = NULL;\r
204  \r
205      /* Check if the message already had a thread ID */\r
206 -    thread_id = _consume_metadata_thread_id (local, notmuch, message);\r
207 -    if (thread_id)\r
208 -       _notmuch_message_add_term (message, "thread", thread_id);\r
209 +    if (notmuch->features & NOTMUCH_FEATURE_GHOSTS) {\r
210 +       if (is_ghost)\r
211 +           thread_id = notmuch_message_get_thread_id (message);\r
212 +    } else {\r
213 +       thread_id = _consume_metadata_thread_id (local, notmuch, message);\r
214 +       if (thread_id)\r
215 +           _notmuch_message_add_term (message, "thread", thread_id);\r
216 +    }\r
217  \r
218      status = _notmuch_database_link_message_to_parents (notmuch, message,\r
219                                                         message_file,\r
220 @@ -2079,6 +2134,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch,\r
221      notmuch_message_t *message = NULL;\r
222      notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS, ret2;\r
223      notmuch_private_status_t private_status;\r
224 +    notmuch_bool_t is_ghost = false;\r
225  \r
226      const char *date, *header;\r
227      const char *from, *to, *subject;\r
228 @@ -2171,12 +2227,20 @@ notmuch_database_add_message (notmuch_database_t *notmuch,\r
229  \r
230         _notmuch_message_add_filename (message, filename);\r
231  \r
232 -       /* Is this a newly created message object? */\r
233 -       if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) {\r
234 +       /* Is this a newly created message object or a ghost\r
235 +        * message?  We have to be slightly careful: if this is a\r
236 +        * blank message, it's not safe to call\r
237 +        * notmuch_message_get_flag yet. */\r
238 +       if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND ||\r
239 +           (is_ghost = notmuch_message_get_flag (\r
240 +               message, NOTMUCH_MESSAGE_FLAG_GHOST))) {\r
241             _notmuch_message_add_term (message, "type", "mail");\r
242 +           if (is_ghost)\r
243 +               /* Convert ghost message to a regular message */\r
244 +               _notmuch_message_remove_term (message, "type", "ghost");\r
245  \r
246             ret = _notmuch_database_link_message (notmuch, message,\r
247 -                                                 message_file);\r
248 +                                                 message_file, is_ghost);\r
249             if (ret)\r
250                 goto DONE;\r
251  \r
252 -- \r
253 2.1.0\r
254 \r