[PATCH 3/4] lib: handle DatabaseModifiedError in _n_message_ensure_metadata
Jani Nikula
jani at nikula.org
Sat Feb 25 10:42:24 PST 2017
On Fri, 24 Feb 2017, David Bremner <david at tethera.net> wrote:
> The retries are hardcoded to a small number, and error handling aborts
> than propagating errors from notmuch_database_reopen. These are both
> somewhat justified by the assumption that most things that can go
> wrong in Xapian::Database::reopen are rare and fatal (like running out
> of memory or disk corruption).
I think the sanity of the implementation hinges on that assumption. It
makes sense if you're right, but I really have no idea either way...
> ---
> lib/message.cc | 152 ++++++++++++++++++++++++-----------------
> test/T640-database-modified.sh | 1 -
> 2 files changed, 88 insertions(+), 65 deletions(-)
>
> diff --git a/lib/message.cc b/lib/message.cc
> index 2fb67d85..15e2f528 100644
> --- a/lib/message.cc
> +++ b/lib/message.cc
> @@ -49,6 +49,9 @@ struct visible _notmuch_message {
> /* Message document modified since last sync */
> notmuch_bool_t modified;
>
> + /* last view of database the struct is synced with */
> + unsigned long last_view;
> +
> Xapian::Document doc;
> Xapian::termcount termpos;
> };
> @@ -110,6 +113,9 @@ _notmuch_message_create_for_document (const void *talloc_owner,
> message->flags = 0;
> message->lazy_flags = 0;
>
> + /* the message is initially not synchronized with Xapian */
> + message->last_view = 0;
> +
> /* Each of these will be lazily created as needed. */
> message->message_id = NULL;
> message->thread_id = NULL;
> @@ -314,6 +320,8 @@ static void
> _notmuch_message_ensure_metadata (notmuch_message_t *message)
> {
> Xapian::TermIterator i, end;
> + notmuch_bool_t success = FALSE;
> +
> const char *thread_prefix = _find_prefix ("thread"),
> *tag_prefix = _find_prefix ("tag"),
> *id_prefix = _find_prefix ("id"),
> @@ -327,73 +335,89 @@ _notmuch_message_ensure_metadata (notmuch_message_t *message)
> * slightly more costly than looking up individual fields if only
> * one field of the message object is actually used, it's a huge
> * win as more fields are used. */
> + for (int count=0; count < 3 && !success; count++) {
> + try {
> + i = message->doc.termlist_begin ();
> + end = message->doc.termlist_end ();
> +
> + /* Get thread */
> + if (!message->thread_id)
> + message->thread_id =
> + _notmuch_message_get_term (message, i, end, thread_prefix);
> +
> + /* Get tags */
> + assert (strcmp (thread_prefix, tag_prefix) < 0);
> + if (!message->tag_list) {
> + message->tag_list =
> + _notmuch_database_get_terms_with_prefix (message, i, end,
> + tag_prefix);
> + _notmuch_string_list_sort (message->tag_list);
> + }
>
> - i = message->doc.termlist_begin ();
> - end = message->doc.termlist_end ();
> -
> - /* Get thread */
> - if (!message->thread_id)
> - message->thread_id =
> - _notmuch_message_get_term (message, i, end, thread_prefix);
> -
> - /* Get tags */
> - assert (strcmp (thread_prefix, tag_prefix) < 0);
> - if (!message->tag_list) {
> - message->tag_list =
> - _notmuch_database_get_terms_with_prefix (message, i, end,
> - tag_prefix);
> - _notmuch_string_list_sort (message->tag_list);
> - }
> + /* Get id */
> + assert (strcmp (tag_prefix, id_prefix) < 0);
> + if (!message->message_id)
> + message->message_id =
> + _notmuch_message_get_term (message, i, end, id_prefix);
> +
> + /* Get document type */
> + assert (strcmp (id_prefix, type_prefix) < 0);
> + if (! NOTMUCH_TEST_BIT (message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST)) {
> + i.skip_to (type_prefix);
> + /* "T" is the prefix "type" fields. See
> + * BOOLEAN_PREFIX_INTERNAL. */
> + if (*i == "Tmail")
> + NOTMUCH_CLEAR_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST);
> + else if (*i == "Tghost")
> + NOTMUCH_SET_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST);
> + else
> + INTERNAL_ERROR ("Message without type term");
> + NOTMUCH_SET_BIT (&message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST);
> + }
>
> - /* Get id */
> - assert (strcmp (tag_prefix, id_prefix) < 0);
> - if (!message->message_id)
> - message->message_id =
> - _notmuch_message_get_term (message, i, end, id_prefix);
> -
> - /* Get document type */
> - assert (strcmp (id_prefix, type_prefix) < 0);
> - if (! NOTMUCH_TEST_BIT (message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST)) {
> - i.skip_to (type_prefix);
> - /* "T" is the prefix "type" fields. See
> - * BOOLEAN_PREFIX_INTERNAL. */
> - if (*i == "Tmail")
> - NOTMUCH_CLEAR_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST);
> - else if (*i == "Tghost")
> - NOTMUCH_SET_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST);
> - else
> - INTERNAL_ERROR ("Message without type term");
> - NOTMUCH_SET_BIT (&message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST);
> + /* Get filename list. Here we get only the terms. We lazily
> + * expand them to full file names when needed in
> + * _notmuch_message_ensure_filename_list. */
> + assert (strcmp (type_prefix, filename_prefix) < 0);
> + if (!message->filename_term_list && !message->filename_list)
> + message->filename_term_list =
> + _notmuch_database_get_terms_with_prefix (message, i, end,
> + filename_prefix);
> +
> +
> + /* Get property terms. Mimic the setup with filenames above */
> + assert (strcmp (filename_prefix, property_prefix) < 0);
> + if (!message->property_map && !message->property_term_list)
> + message->property_term_list =
> + _notmuch_database_get_terms_with_prefix (message, i, end,
> + property_prefix);
> +
> + /* Get reply to */
> + assert (strcmp (property_prefix, replyto_prefix) < 0);
> + if (!message->in_reply_to)
> + message->in_reply_to =
> + _notmuch_message_get_term (message, i, end, replyto_prefix);
> +
> +
> + /* It's perfectly valid for a message to have no In-Reply-To
> + * header. For these cases, we return an empty string. */
> + if (!message->in_reply_to)
> + message->in_reply_to = talloc_strdup (message, "");
> +
> + /* all the way without an exception */
> + success = TRUE;
Nitpick, if you don't intend to use that variable to return status from
the function, you can just break here, and get rid of the variable. But
no big deal.
> + } catch (const Xapian::DatabaseModifiedError &error) {
> + notmuch_status_t status = notmuch_database_reopen (message->notmuch);
> + if (status != NOTMUCH_STATUS_SUCCESS)
> + INTERNAL_ERROR ("unhandled error from notmuch_database_reopen: %s\n",
> + notmuch_status_to_string (status));
> + success = FALSE;
> + } catch (const Xapian::Error &error) {
> + INTERNAL_ERROR ("A Xapian exception occurred fetching message metadata: %s\n",
> + error.get_msg().c_str());
> + }
If the assumption is that these really are rare cases (read: shouldn't
happen), INTERNAL_ERROR is an improvement over leaking the
exception. Otherwise, I think we'd need to propagate the status all the
way to the API, which would really be annoying.
I guess I think this is a worthwhile improvement no matter what.
> }
> -
> - /* Get filename list. Here we get only the terms. We lazily
> - * expand them to full file names when needed in
> - * _notmuch_message_ensure_filename_list. */
> - assert (strcmp (type_prefix, filename_prefix) < 0);
> - if (!message->filename_term_list && !message->filename_list)
> - message->filename_term_list =
> - _notmuch_database_get_terms_with_prefix (message, i, end,
> - filename_prefix);
> -
> -
> - /* Get property terms. Mimic the setup with filenames above */
> - assert (strcmp (filename_prefix, property_prefix) < 0);
> - if (!message->property_map && !message->property_term_list)
> - message->property_term_list =
> - _notmuch_database_get_terms_with_prefix (message, i, end,
> - property_prefix);
> -
> - /* Get reply to */
> - assert (strcmp (property_prefix, replyto_prefix) < 0);
> - if (!message->in_reply_to)
> - message->in_reply_to =
> - _notmuch_message_get_term (message, i, end, replyto_prefix);
> -
> -
> - /* It's perfectly valid for a message to have no In-Reply-To
> - * header. For these cases, we return an empty string. */
> - if (!message->in_reply_to)
> - message->in_reply_to = talloc_strdup (message, "");
> + message->last_view = message->notmuch->view;
> }
>
> void
> diff --git a/test/T640-database-modified.sh b/test/T640-database-modified.sh
> index 41869eaa..9599417c 100755
> --- a/test/T640-database-modified.sh
> +++ b/test/T640-database-modified.sh
> @@ -5,7 +5,6 @@ test_description="DatabaseModifiedError handling"
> add_email_corpus
>
> test_begin_subtest "catching DatabaseModifiedError in _notmuch_message_ensure_metadata"
> -test_subtest_known_broken
> test_C ${MAIL_DIR} <<'EOF'
> #include <unistd.h>
> #include <stdlib.h>
> --
> 2.11.0
>
> _______________________________________________
> notmuch mailing list
> notmuch at notmuchmail.org
> https://notmuchmail.org/mailman/listinfo/notmuch
More information about the notmuch
mailing list