Re: Applying patches directly from emails?
[notmuch-archives.git] / 2d / 5ca56de14210892a6aab7f850bf7217bde83bd
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 18AF0431FB6\r
6         for <notmuch@notmuchmail.org>; Tue, 21 Oct 2014 18:33:09 -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 N+dcz96voSKY for <notmuch@notmuchmail.org>;\r
16         Tue, 21 Oct 2014 18:33:01 -0700 (PDT)\r
17 Received: from outgoing.csail.mit.edu (outgoing.csail.mit.edu [128.30.2.149])\r
18         by olra.theworths.org (Postfix) with ESMTP id 5A730431FAE\r
19         for <notmuch@notmuchmail.org>; Tue, 21 Oct 2014 18:33:01 -0700 (PDT)\r
20 Received: from [104.131.20.129] (helo=awakeningjr)\r
21         by outgoing.csail.mit.edu with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16)\r
22         (Exim 4.72) (envelope-from <aclements@csail.mit.edu>)\r
23         id 1XgknM-0004kE-Kp; Tue, 21 Oct 2014 21:33:00 -0400\r
24 Received: from amthrax by awakeningjr with local (Exim 4.84)\r
25         (envelope-from <aclements@csail.mit.edu>)\r
26         id 1XgknM-0000Ah-Ay; Tue, 21 Oct 2014 21:33:00 -0400\r
27 Date: Tue, 21 Oct 2014 21:33:00 -0400\r
28 From: Austin Clements <aclements@csail.mit.edu>\r
29 To: Mark Walters <markwalters1009@gmail.com>\r
30 Subject: Re: [PATCH v2 07/12] lib: Internal support for querying and creating\r
31         ghost messages\r
32 Message-ID: <20141022013300.GD7970@csail.mit.edu>\r
33 References: <1412637438-4821-1-git-send-email-aclements@csail.mit.edu>\r
34         <1412637438-4821-8-git-send-email-aclements@csail.mit.edu>\r
35         <8738ahja72.fsf@qmul.ac.uk>\r
36 MIME-Version: 1.0\r
37 Content-Type: text/plain; charset=us-ascii\r
38 Content-Disposition: inline\r
39 In-Reply-To: <8738ahja72.fsf@qmul.ac.uk>\r
40 User-Agent: Mutt/1.5.23 (2014-03-12)\r
41 Cc: notmuch@notmuchmail.org\r
42 X-BeenThere: notmuch@notmuchmail.org\r
43 X-Mailman-Version: 2.1.13\r
44 Precedence: list\r
45 List-Id: "Use and development of the notmuch mail system."\r
46         <notmuch.notmuchmail.org>\r
47 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
48         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
49 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
50 List-Post: <mailto:notmuch@notmuchmail.org>\r
51 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
52 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
53         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
54 X-List-Received-Date: Wed, 22 Oct 2014 01:33:09 -0000\r
55 \r
56 Quoth Mark Walters on Oct 22 at 12:05 am:\r
57\r
58 > Hi \r
59\r
60 > I am slowly working my way through this series: only two trivial queries\r
61 > so far.\r
62\r
63 > On Tue, 07 Oct 2014, Austin Clements <aclements@csail.mit.edu> wrote:\r
64 > > From: Austin Clements <amdragon@mit.edu>\r
65 > >\r
66 > > This updates the message abstraction to support ghost messages: it\r
67 > > adds a message flag that distinguishes regular messages from ghost\r
68 > > messages, and an internal function for initializing a newly created\r
69 > > (blank) message as a ghost message.\r
70 > > ---\r
71 > >  lib/message.cc        | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--\r
72 > >  lib/notmuch-private.h |  4 ++++\r
73 > >  lib/notmuch.h         |  9 ++++++++-\r
74 > >  3 files changed, 62 insertions(+), 3 deletions(-)\r
75 > >\r
76 > > diff --git a/lib/message.cc b/lib/message.cc\r
77 > > index 55d2ff6..a7a13cc 100644\r
78 > > --- a/lib/message.cc\r
79 > > +++ b/lib/message.cc\r
80 > > @@ -39,6 +39,9 @@ struct visible _notmuch_message {\r
81 > >      notmuch_message_file_t *message_file;\r
82 > >      notmuch_message_list_t *replies;\r
83 > >      unsigned long flags;\r
84 > > +    /* For flags that are initialized on-demand, lazy_flags indicates\r
85 > > +     * if each flag has been initialized. */\r
86 > > +    unsigned long lazy_flags;\r
87\r
88 > I wonder if valid_flags might be better here as, as far as I can see,\r
89 > the reason for these is so we can invalidate a flag more than an\r
90 > optimisation (which is what I thought the lazy implied).\r
91 \r
92 I do think of this as an optimization.  If we were to compute the\r
93 value of this flag when a message was created (and keep it\r
94 up-to-date), there would be no need for lazy_flags.  But, unlike the\r
95 other flags, computing this is expensive.\r
96 \r
97 > >  \r
98 > >      Xapian::Document doc;\r
99 > >      Xapian::termcount termpos;\r
100 > > @@ -99,6 +102,7 @@ _notmuch_message_create_for_document (const void *talloc_owner,\r
101 > >  \r
102 > >      message->frozen = 0;\r
103 > >      message->flags = 0;\r
104 > > +    message->lazy_flags = 0;\r
105 > >  \r
106 > >      /* Each of these will be lazily created as needed. */\r
107 > >      message->message_id = NULL;\r
108 > > @@ -192,7 +196,7 @@ _notmuch_message_create (const void *talloc_owner,\r
109 > >   *\r
110 > >   *     There is already a document with message ID 'message_id' in the\r
111 > >   *     database. The returned message can be used to query/modify the\r
112 > > - *     document.\r
113 > > + *     document. The message may be a ghost message.\r
114 > >   *\r
115 > >   *   NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND:\r
116 > >   *\r
117 > > @@ -305,6 +309,7 @@ _notmuch_message_ensure_metadata (notmuch_message_t *message)\r
118 > >      const char *thread_prefix = _find_prefix ("thread"),\r
119 > >     *tag_prefix = _find_prefix ("tag"),\r
120 > >     *id_prefix = _find_prefix ("id"),\r
121 > > +   *type_prefix = _find_prefix ("type"),\r
122 > >     *filename_prefix = _find_prefix ("file-direntry"),\r
123 > >     *replyto_prefix = _find_prefix ("replyto");\r
124 > >  \r
125 > > @@ -337,10 +342,25 @@ _notmuch_message_ensure_metadata (notmuch_message_t *message)\r
126 > >     message->message_id =\r
127 > >         _notmuch_message_get_term (message, i, end, id_prefix);\r
128 > >  \r
129 > > +    /* Get document type */\r
130 > > +    assert (strcmp (id_prefix, type_prefix) < 0);\r
131 > > +    if (! NOTMUCH_TEST_BIT (message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST)) {\r
132 > > +   i.skip_to (type_prefix);\r
133 > > +   /* "T" is the prefix "type" fields.  See\r
134 > > +    * BOOLEAN_PREFIX_INTERNAL. */\r
135 > > +   if (*i == "Tmail")\r
136 > > +       NOTMUCH_CLEAR_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST);\r
137 > > +   else if (*i == "Tghost")\r
138 > > +       NOTMUCH_SET_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST);\r
139 > > +   else\r
140 > > +       INTERNAL_ERROR ("Message without type term");\r
141 > > +   NOTMUCH_SET_BIT (&message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST);\r
142 > > +    }\r
143 > > +\r
144 > >      /* Get filename list.  Here we get only the terms.  We lazily\r
145 > >       * expand them to full file names when needed in\r
146 > >       * _notmuch_message_ensure_filename_list. */\r
147 > > -    assert (strcmp (id_prefix, filename_prefix) < 0);\r
148 > > +    assert (strcmp (type_prefix, filename_prefix) < 0);\r
149 > >      if (!message->filename_term_list && !message->filename_list)\r
150 > >     message->filename_term_list =\r
151 > >         _notmuch_database_get_terms_with_prefix (message, i, end,\r
152 > > @@ -371,6 +391,11 @@ _notmuch_message_invalidate_metadata (notmuch_message_t *message,\r
153 > >     message->tag_list = NULL;\r
154 > >      }\r
155 > >  \r
156 > > +    if (strcmp ("type", prefix_name) == 0) {\r
157 > > +   NOTMUCH_CLEAR_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST);\r
158 > > +   NOTMUCH_CLEAR_BIT (&message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST);\r
159 > > +    }\r
160 > > +\r
161 > >      if (strcmp ("file-direntry", prefix_name) == 0) {\r
162 > >     talloc_free (message->filename_term_list);\r
163 > >     talloc_free (message->filename_list);\r
164 > > @@ -869,6 +894,10 @@ notmuch_bool_t\r
165 > >  notmuch_message_get_flag (notmuch_message_t *message,\r
166 > >                       notmuch_message_flag_t flag)\r
167 > >  {\r
168 > > +    if (flag == NOTMUCH_MESSAGE_FLAG_GHOST &&\r
169 > > +   ! NOTMUCH_TEST_BIT (message->lazy_flags, flag))\r
170 > > +   _notmuch_message_ensure_metadata (message);\r
171 > > +\r
172 > >      return NOTMUCH_TEST_BIT (message->flags, flag);\r
173 > >  }\r
174 > >  \r
175 > > @@ -880,6 +909,7 @@ notmuch_message_set_flag (notmuch_message_t *message,\r
176 > >     NOTMUCH_SET_BIT (&message->flags, flag);\r
177 > >      else\r
178 > >     NOTMUCH_CLEAR_BIT (&message->flags, flag);\r
179 > > +    NOTMUCH_SET_BIT (&message->lazy_flags, flag);\r
180 > >  }\r
181 > >  \r
182 > >  time_t\r
183 > > @@ -989,6 +1019,24 @@ _notmuch_message_delete (notmuch_message_t *message)\r
184 > >      return NOTMUCH_STATUS_SUCCESS;\r
185 > >  }\r
186 > >  \r
187 > > +/* Transform a blank message into a ghost message.  The caller must\r
188 > > + * _notmuch_message_sync the message. */\r
189 > > +notmuch_private_status_t\r
190 > > +_notmuch_message_initialize_ghost (notmuch_message_t *message,\r
191 > > +                              const char *thread_id)\r
192 > > +{\r
193 > > +    notmuch_private_status_t status;\r
194 > > +\r
195 > > +    status = _notmuch_message_add_term (message, "type", "ghost");\r
196 > > +    if (status)\r
197 > > +   return status;\r
198 > > +    status = _notmuch_message_add_term (message, "thread", thread_id);\r
199 > > +    if (status)\r
200 > > +   return status;\r
201 > > +\r
202 > > +    return NOTMUCH_PRIVATE_STATUS_SUCCESS;\r
203 > > +}\r
204 > > +\r
205 > >  /* Ensure that 'message' is not holding any file object open. Future\r
206 > >   * calls to various functions will still automatically open the\r
207 > >   * message file as needed.\r
208 > > diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h\r
209 > > index 7250291..2f43c1d 100644\r
210 > > --- a/lib/notmuch-private.h\r
211 > > +++ b/lib/notmuch-private.h\r
212 > > @@ -308,6 +308,10 @@ _notmuch_message_sync (notmuch_message_t *message);\r
213 > >  notmuch_status_t\r
214 > >  _notmuch_message_delete (notmuch_message_t *message);\r
215 > >  \r
216 > > +notmuch_private_status_t\r
217 > > +_notmuch_message_initialize_ghost (notmuch_message_t *message,\r
218 > > +                              const char *thread_id);\r
219 > > +\r
220 > >  void\r
221 > >  _notmuch_message_close (notmuch_message_t *message);\r
222 > >  \r
223 > > diff --git a/lib/notmuch.h b/lib/notmuch.h\r
224 > > index dae0416..92594b9 100644\r
225 > > --- a/lib/notmuch.h\r
226 > > +++ b/lib/notmuch.h\r
227 > > @@ -1221,7 +1221,14 @@ notmuch_message_get_filenames (notmuch_message_t *message);\r
228 > >   */\r
229 > >  typedef enum _notmuch_message_flag {\r
230 > >      NOTMUCH_MESSAGE_FLAG_MATCH,\r
231 > > -    NOTMUCH_MESSAGE_FLAG_EXCLUDED\r
232 > > +    NOTMUCH_MESSAGE_FLAG_EXCLUDED,\r
233 > > +\r
234 > > +    /* This message is a "ghost message", meaning it has no filenames\r
235 > > +     * or content, but we know it exists because it was referenced by\r
236 > > +     * some other message.  A ghost message has only a message ID and\r
237 > > +     * thread ID.\r
238 > > +     */\r
239\r
240 > Can I check here: we are not allowing a ghost message to have any tags?\r
241 \r
242 Correct, at least for now.\r
243 \r
244 However, I think it would make *a lot* of sense to be able to pre-seed\r
245 ghost messages with tags.  nmbug could use this to avoid races with\r
246 receiving messages.  Distributed tag sync could use it similarly.\r
247 Insert could use it to eliminate the nasty races between storing the\r
248 message, indexing it, and tagging it.  Restore could potentially use\r
249 it.  When sending messages, we could pre-seed a sent tag for when the\r
250 sent message is re-received (though insert may obviate that).  I'm\r
251 sure there are other uses I haven't thought of.\r
252 \r
253 This requires some new APIs, since there's currently no way for a\r
254 library user to create a ghost message or get at it to tag it.  It\r
255 also slightly complicates notmuch_database_get_all_tags since that\r
256 probably shouldn't return tags that are only on ghost messages (I\r
257 think if we just collect all the docids in the Tghost posting list and\r
258 use that to filter out tag terms that there should be almost no\r
259 performance impact of this).  But these are both quite doable things.\r
260 \r
261 A more complicated question is what we want to do with deleted\r
262 messages.  Currently we remove them entirely from the database, but we\r
263 *could* keep around their tags so if the message reappears (e.g.,\r
264 there was a transient problem) we can bring back the tags.  After\r
265 thinking about this a great deal, I concluded we should just continue\r
266 deleting them from the database (or, at most, strip the message back\r
267 down to its thread ID).  If anyone's curious, I can write up my\r
268 thoughts on this, but it boils down to complicated the semantics of\r
269 initial tagging and dump/restore.\r
270 \r
271 > Best wishes\r
272\r
273 > Mark\r
274\r
275 > > +    NOTMUCH_MESSAGE_FLAG_GHOST,\r
276 > >  } notmuch_message_flag_t;\r
277 > >  \r
278 > >  /**\r
279 > >\r
280 > > _______________________________________________\r
281 > > notmuch mailing list\r
282 > > notmuch@notmuchmail.org\r
283 > > http://notmuchmail.org/mailman/listinfo/notmuch\r