RE: [Spam-verdenking][english 100%] Re: another bug fix release: 0.15.2, in progress.
[notmuch-archives.git] / c7 / e6abfd94ecadac21b15976d3cf79ddc92dc8f8
1 Return-Path: <james@jameswestby.net>\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 487374048E1\r
6         for <notmuch@notmuchmail.org>; Sat, 13 Mar 2010 13:28:15 -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.001\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=0.001 tagged_above=-999 required=5\r
12         tests=[BAYES_50=0.001] autolearn=ham\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 yP39C8A1YYl2 for <notmuch@notmuchmail.org>;\r
16         Sat, 13 Mar 2010 13:28:14 -0800 (PST)\r
17 Received: from jameswestby.net (jameswestby.net [89.145.97.141])\r
18         by olra.theworths.org (Postfix) with ESMTP id D5AA04048E0\r
19         for <notmuch@notmuchmail.org>; Sat, 13 Mar 2010 13:28:13 -0800 (PST)\r
20 Received: from [74.220.175.184] (helo=flash)\r
21         by jameswestby.net with esmtpa (Exim 4.69)\r
22         (envelope-from <james@jameswestby.net>)\r
23         id 1NqYsV-0002Ng-Jm; Sat, 13 Mar 2010 21:28:12 +0000\r
24 Received: by flash (Postfix, from userid 1000)\r
25         id 84190605C14; Sat, 13 Mar 2010 16:28:09 -0500 (EST)\r
26 From: James Westby <jw+debian@jameswestby.net>\r
27 To: notmuch@notmuchmail.org\r
28 Date: Sat, 13 Mar 2010 16:27:57 -0500\r
29 Message-Id: <1268515677-12692-1-git-send-email-jw+debian@jameswestby.net>\r
30 X-Mailer: git-send-email 1.7.0\r
31 In-Reply-To: <87fx72o8pq.fsf@yoom.home.cworth.org>\r
32 References: <87fx72o8pq.fsf@yoom.home.cworth.org>\r
33 Subject: [notmuch] [PATCH] Store thread ids for messages that we haven't\r
34         seen yet\r
35 X-BeenThere: notmuch@notmuchmail.org\r
36 X-Mailman-Version: 2.1.13\r
37 Precedence: list\r
38 List-Id: "Use and development of the notmuch mail system."\r
39         <notmuch.notmuchmail.org>\r
40 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
41         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
42 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
43 List-Post: <mailto:notmuch@notmuchmail.org>\r
44 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
45 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
46         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
47 X-List-Received-Date: Sat, 13 Mar 2010 21:28:15 -0000\r
48 \r
49 This allows us to thread messages even when we receive them out of\r
50 order, or never receive the root.\r
51 \r
52 The thread ids for messages that aren't present but are referred to are\r
53 stored as metadata in the database and then retrieved if we ever get\r
54 that message.\r
55 \r
56 When determining the thread id for a message we also check for this\r
57 metadata so that we can thread descendants of a message together before\r
58 we receive it.\r
59 ---\r
60  lib/database.cc   |   78 ++++++++++++++++++++++++++++++++++++++--------------\r
61  test/notmuch-test |   32 +++++++++++++++++++--\r
62  2 files changed, 86 insertions(+), 24 deletions(-)\r
63 \r
64 diff --git a/lib/database.cc b/lib/database.cc\r
65 index c91e97c..92234ff 100644\r
66 --- a/lib/database.cc\r
67 +++ b/lib/database.cc\r
68 @@ -1111,6 +1111,31 @@ notmuch_database_get_directory (notmuch_database_t *notmuch,\r
69      return _notmuch_directory_create (notmuch, path, &status);\r
70  }\r
71  \r
72 +static const char *\r
73 +_notmuch_database_generate_thread_id (notmuch_database_t *notmuch)\r
74 +{\r
75 +    /* 16 bytes (+ terminator) for hexadecimal representation of\r
76 +     * a 64-bit integer. */\r
77 +    static char thread_id[17];\r
78 +    Xapian::WritableDatabase *db;\r
79 +\r
80 +    db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);\r
81 +\r
82 +    notmuch->last_thread_id++;\r
83 +\r
84 +    sprintf (thread_id, "%016" PRIx64, notmuch->last_thread_id);\r
85 +\r
86 +    db->set_metadata ("last_thread_id", thread_id);\r
87 +\r
88 +    return thread_id;\r
89 +}\r
90 +\r
91 +static char *\r
92 +_get_metadata_thread_id_key (void *ctx, const char *message_id)\r
93 +{\r
94 +    return talloc_asprintf (ctx, "thread_id_%s", message_id);\r
95 +}\r
96 +\r
97  /* Find the thread ID to which the message with 'message_id' belongs.\r
98   *\r
99   * Returns NULL if no message with message ID 'message_id' is in the\r
100 @@ -1127,8 +1152,25 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,\r
101      const char *ret = NULL;\r
102  \r
103      message = notmuch_database_find_message (notmuch, message_id);\r
104 -    if (message == NULL)\r
105 -       goto DONE;\r
106 +    /* If we haven't seen that message yet then check if we have already\r
107 +     * generated a dummy id for it and stored it in the metadata.\r
108 +     * If not then we generate a new thread id.\r
109 +     * This ensures that we can thread messages even when we haven't received\r
110 +     * the root (yet?)\r
111 +     */\r
112 +    if (message == NULL) {\r
113 +        Xapian::WritableDatabase *db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);\r
114 +        char * metadata_key = _get_metadata_thread_id_key (ctx, message_id);\r
115 +        string thread_id = notmuch->xapian_db->get_metadata(metadata_key);\r
116 +        if (thread_id.empty()) {\r
117 +            ret = _notmuch_database_generate_thread_id(notmuch);\r
118 +            db->set_metadata(metadata_key, ret);\r
119 +        } else {\r
120 +            ret = thread_id.c_str();\r
121 +        }\r
122 +        talloc_free (metadata_key);\r
123 +        goto DONE;\r
124 +    }\r
125  \r
126      ret = talloc_steal (ctx, notmuch_message_get_thread_id (message));\r
127  \r
128 @@ -1295,25 +1337,6 @@ _notmuch_database_link_message_to_children (notmuch_database_t *notmuch,\r
129      return ret;\r
130  }\r
131  \r
132 -static const char *\r
133 -_notmuch_database_generate_thread_id (notmuch_database_t *notmuch)\r
134 -{\r
135 -    /* 16 bytes (+ terminator) for hexadecimal representation of\r
136 -     * a 64-bit integer. */\r
137 -    static char thread_id[17];\r
138 -    Xapian::WritableDatabase *db;\r
139 -\r
140 -    db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);\r
141 -\r
142 -    notmuch->last_thread_id++;\r
143 -\r
144 -    sprintf (thread_id, "%016" PRIx64, notmuch->last_thread_id);\r
145 -\r
146 -    db->set_metadata ("last_thread_id", thread_id);\r
147 -\r
148 -    return thread_id;\r
149 -}\r
150 -\r
151  /* Given a (mostly empty) 'message' and its corresponding\r
152   * 'message_file' link it to existing threads in the database.\r
153   *\r
154 @@ -1337,6 +1360,19 @@ _notmuch_database_link_message (notmuch_database_t *notmuch,\r
155  {\r
156      notmuch_status_t status;\r
157      const char *thread_id = NULL;\r
158 +    char *metadata_key = _get_metadata_thread_id_key (message,\r
159 +            notmuch_message_get_message_id (message));\r
160 +    /* Check if we have already seen related messages to this one.\r
161 +     * If we have then use the thread_id that we stored at that time.\r
162 +     */\r
163 +    string stored_id = notmuch->xapian_db->get_metadata (metadata_key);\r
164 +    if (!stored_id.empty()) {\r
165 +        Xapian::WritableDatabase *db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);\r
166 +        db->set_metadata (metadata_key, "");\r
167 +        thread_id = stored_id.c_str();\r
168 +        _notmuch_message_add_term (message, "thread", thread_id);\r
169 +    }\r
170 +    talloc_free (metadata_key);\r
171  \r
172      status = _notmuch_database_link_message_to_parents (notmuch, message,\r
173                                                         message_file,\r
174 diff --git a/test/notmuch-test b/test/notmuch-test\r
175 index 7bc53ec..9264fb0 100755\r
176 --- a/test/notmuch-test\r
177 +++ b/test/notmuch-test\r
178 @@ -64,6 +64,10 @@ increment_mtime ()\r
179  #      Additional values for email headers. If these are not provided\r
180  #      then the relevant headers will simply not appear in the\r
181  #      message.\r
182 +#\r
183 +#  '[id]=<message-id>'\r
184 +#\r
185 +#      Controls the message-id of the created message.\r
186  gen_msg_cnt=0\r
187  gen_msg_filename=""\r
188  gen_msg_id=""\r
189 @@ -73,9 +77,14 @@ generate_message ()\r
190      local -A template="($@)"\r
191      local additional_headers\r
192  \r
193 -    gen_msg_cnt=$((gen_msg_cnt + 1))\r
194 -    gen_msg_name=msg-$(printf "%03d" $gen_msg_cnt)\r
195 -    gen_msg_id="${gen_msg_name}@notmuch-test-suite"\r
196 +    if [ -z "${template[id]}" ]; then\r
197 +       gen_msg_cnt=$((gen_msg_cnt + 1))\r
198 +       gen_msg_name=msg-$(printf "%03d" $gen_msg_cnt)\r
199 +       gen_msg_id="${gen_msg_name}@notmuch-test-suite"\r
200 +    else\r
201 +       gen_msg_name="msg-${template[id]}"\r
202 +       gen_msg_id="${template[id]}"\r
203 +    fi\r
204  \r
205      if [ -z "${template[dir]}" ]; then\r
206         gen_msg_filename="${MAIL_DIR}/$gen_msg_name"\r
207 @@ -534,6 +543,23 @@ printf " Restore with nothing to do...\t"\r
208  $NOTMUCH restore dump.expected\r
209  echo " PASS"\r
210  \r
211 +printf "\nTesting threading when messages received out of order:\n"\r
212 +printf " Adding initial child message...\t\t"\r
213 +generate_message [body]=foo '[in-reply-to]=\<parent-id\>' [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'\r
214 +execute_expecting new "Added 1 new message to the database."\r
215 +printf " Searching returns the message...\t\t"\r
216 +execute_expecting "search foo" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; brokenthreadtest (inbox unread)"\r
217 +printf " Adding second child message...\t\t"\r
218 +generate_message [body]=foo '[in-reply-to]=\<parent-id\>' [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'\r
219 +execute_expecting new "Added 1 new message to the database."\r
220 +printf " Searching returns both messages in one thread...\t\t"\r
221 +execute_expecting "search foo" "thread:XXX   2000-01-01 [2/2] Notmuch Test Suite; brokenthreadtest (inbox unread)"\r
222 +printf " Adding parent message...\t\t"\r
223 +generate_message [body]=foo [id]=parent-id [subject]=brokenthreadtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'\r
224 +execute_expecting new "Added 1 new message to the database."\r
225 +printf " Searching returns all three messages in one thread...\t\t"\r
226 +execute_expecting "search foo" "thread:XXX   2000-01-01 [3/3] Notmuch Test Suite; brokenthreadtest (inbox unread)"\r
227 +\r
228  cat <<EOF\r
229  Notmuch test suite complete.\r
230  \r
231 -- \r
232 1.7.0\r
233 \r