X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=lib%2Fdatabase.cc;h=45c42607802d79db683f7cb77683d68aaa831a4a;hp=d79cc3006d29a204aaa54a762aa30e0a4734ded7;hb=df8885f62c13f77b2b16cbb211e3a727945870b0;hpb=cb6cc296e27fdab85faa4bdd670eda2e0c53b8c2 diff --git a/lib/database.cc b/lib/database.cc index d79cc300..45c42607 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -42,7 +42,7 @@ typedef struct { const char *prefix; } prefix_t; -#define NOTMUCH_DATABASE_VERSION 1 +#define NOTMUCH_DATABASE_VERSION 2 #define STRINGIFY(s) _SUB_STRINGIFY(s) #define _SUB_STRINGIFY(s) #s @@ -100,8 +100,8 @@ typedef struct { * In addition, terms from the content of the message are added with * "from", "to", "attachment", and "subject" prefixes for use by the * user in searching. Similarly, terms from the path of the mail - * message are added with a "folder" prefix. But the database doesn't - * really care itself about any of these. + * message are added with "folder" and "path" prefixes. But the + * database doesn't really care itself about any of these. * * The data portion of a mail document is empty. * @@ -208,7 +208,15 @@ static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = { { "thread", "G" }, { "tag", "K" }, { "is", "K" }, - { "id", "Q" } + { "id", "Q" }, + { "path", "P" }, + /* + * Without the ":", since this is a multi-letter prefix, Xapian + * will add a colon itself if the first letter of the path is + * upper-case ASCII. Including the ":" forces there to always be a + * colon, which keeps our own logic simpler. + */ + { "folder", "XFOLDER:" }, }; static prefix_t PROBABILISTIC_PREFIX[]= { @@ -216,7 +224,6 @@ static prefix_t PROBABILISTIC_PREFIX[]= { { "to", "XTO" }, { "attachment", "XATTACHMENT" }, { "subject", "XSUBJECT"}, - { "folder", "XFOLDER"} }; const char * @@ -349,7 +356,7 @@ _message_id_compressed (void *ctx, const char *message_id) { char *sha1, *compressed; - sha1 = notmuch_sha1_of_string (message_id); + sha1 = _notmuch_sha1_of_string (message_id); compressed = talloc_asprintf (ctx, "notmuch-sha1-%s", sha1); free (sha1); @@ -767,14 +774,17 @@ notmuch_database_open (const char *path, return status; } -void +notmuch_status_t notmuch_database_close (notmuch_database_t *notmuch) { + notmuch_status_t status = NOTMUCH_STATUS_SUCCESS; + try { if (notmuch->xapian_db != NULL && notmuch->mode == NOTMUCH_DATABASE_MODE_READ_WRITE) (static_cast (notmuch->xapian_db))->flush (); } catch (const Xapian::Error &error) { + status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; if (! notmuch->exception_reported) { fprintf (stderr, "Error: A Xapian exception occurred flushing database: %s\n", error.get_msg().c_str()); @@ -788,7 +798,9 @@ notmuch_database_close (notmuch_database_t *notmuch) try { notmuch->xapian_db->close(); } catch (const Xapian::Error &error) { - /* do nothing */ + /* don't clobber previous error status */ + if (status == NOTMUCH_STATUS_SUCCESS) + status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; } } @@ -802,6 +814,8 @@ notmuch_database_close (notmuch_database_t *notmuch) notmuch->value_range_processor = NULL; delete notmuch->date_range_processor; notmuch->date_range_processor = NULL; + + return status; } #if HAVE_XAPIAN_COMPACT @@ -922,6 +936,12 @@ notmuch_database_compact (const char *path, goto DONE; } + /* Unconditionally attempt to remove old work-in-progress database (if + * any). This is "protected" by database lock. If this fails due to write + * errors (etc), the following code will fail and provide error message. + */ + (void) rmtree (compact_xapian_path); + try { NotmuchCompactor compactor (status_cb, closure); @@ -936,23 +956,38 @@ notmuch_database_compact (const char *path, } if (rename (xapian_path, backup_path)) { - fprintf (stderr, "Error moving old database out of the way\n"); + fprintf (stderr, "Error moving %s to %s: %s\n", + xapian_path, backup_path, strerror (errno)); ret = NOTMUCH_STATUS_FILE_ERROR; goto DONE; } if (rename (compact_xapian_path, xapian_path)) { - fprintf (stderr, "Error moving compacted database\n"); + fprintf (stderr, "Error moving %s to %s: %s\n", + compact_xapian_path, xapian_path, strerror (errno)); ret = NOTMUCH_STATUS_FILE_ERROR; goto DONE; } - if (! keep_backup) - rmtree (backup_path); + if (! keep_backup) { + if (rmtree (backup_path)) { + fprintf (stderr, "Error removing old database %s: %s\n", + backup_path, strerror (errno)); + ret = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + } DONE: - if (notmuch) - notmuch_database_destroy (notmuch); + if (notmuch) { + notmuch_status_t ret2; + + ret2 = notmuch_database_destroy (notmuch); + + /* don't clobber previous error status */ + if (ret == NOTMUCH_STATUS_SUCCESS && ret2 != NOTMUCH_STATUS_SUCCESS) + ret = ret2; + } talloc_free (local); @@ -970,11 +1005,15 @@ notmuch_database_compact (unused (const char *path), } #endif -void +notmuch_status_t notmuch_database_destroy (notmuch_database_t *notmuch) { - notmuch_database_close (notmuch); + notmuch_status_t status; + + status = notmuch_database_close (notmuch); talloc_free (notmuch); + + return status; } const char * @@ -1153,6 +1192,40 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, } } + /* + * Prior to version 2, the "folder:" prefix was probabilistic and + * stemmed. Change it to the current boolean prefix. Add "path:" + * prefixes while at it. + */ + if (version < 2) { + notmuch_query_t *query = notmuch_query_create (notmuch, ""); + notmuch_messages_t *messages; + notmuch_message_t *message; + + count = 0; + total = notmuch_query_count_messages (query); + + for (messages = notmuch_query_search_messages (query); + notmuch_messages_valid (messages); + notmuch_messages_move_to_next (messages)) { + if (do_progress_notify) { + progress_notify (closure, (double) count / total); + do_progress_notify = 0; + } + + message = notmuch_messages_get (messages); + + _notmuch_message_upgrade_folder (message); + _notmuch_message_sync (message); + + notmuch_message_destroy (message); + + count++; + } + + notmuch_query_destroy (query); + } + db->set_metadata ("version", STRINGIFY (NOTMUCH_DATABASE_VERSION)); db->flush (); @@ -1301,7 +1374,7 @@ _notmuch_database_get_directory_db_path (const char *path) int term_len = strlen (_find_prefix ("directory")) + strlen (path); if (term_len > NOTMUCH_TERM_MAX) - return notmuch_sha1_of_string (path); + return _notmuch_sha1_of_string (path); else return path; } @@ -1703,12 +1776,12 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch, _my_talloc_free_for_g_hash, NULL); this_message_id = notmuch_message_get_message_id (message); - refs = notmuch_message_file_get_header (message_file, "references"); + refs = _notmuch_message_file_get_header (message_file, "references"); last_ref_message_id = parse_references (message, this_message_id, parents, refs); - in_reply_to = notmuch_message_file_get_header (message_file, "in-reply-to"); + in_reply_to = _notmuch_message_file_get_header (message_file, "in-reply-to"); in_reply_to_message_id = parse_references (message, this_message_id, parents, in_reply_to); @@ -1906,7 +1979,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch, if (ret) return ret; - message_file = notmuch_message_file_open (filename); + message_file = _notmuch_message_file_open (filename); if (message_file == NULL) return NOTMUCH_STATUS_FILE_ERROR; @@ -1916,15 +1989,10 @@ notmuch_database_add_message (notmuch_database_t *notmuch, if (ret) goto DONE; - notmuch_message_file_restrict_headers (message_file, - "date", - "from", - "in-reply-to", - "message-id", - "references", - "subject", - "to", - (char *) NULL); + /* Parse message up front to get better error status. */ + ret = _notmuch_message_file_parse (message_file); + if (ret) + goto DONE; try { /* Before we do any real work, (especially before doing a @@ -1932,9 +2000,9 @@ notmuch_database_add_message (notmuch_database_t *notmuch, * let's make sure that what we're looking at looks like an * actual email message. */ - from = notmuch_message_file_get_header (message_file, "from"); - subject = notmuch_message_file_get_header (message_file, "subject"); - to = notmuch_message_file_get_header (message_file, "to"); + from = _notmuch_message_file_get_header (message_file, "from"); + subject = _notmuch_message_file_get_header (message_file, "subject"); + to = _notmuch_message_file_get_header (message_file, "to"); if ((from == NULL || *from == '\0') && (subject == NULL || *subject == '\0') && @@ -1947,7 +2015,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch, /* Now that we're sure it's mail, the first order of business * is to find a message ID (or else create one ourselves). */ - header = notmuch_message_file_get_header (message_file, "message-id"); + header = _notmuch_message_file_get_header (message_file, "message-id"); if (header && *header != '\0') { message_id = _parse_message_id (message_file, header, NULL); @@ -1968,7 +2036,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch, if (message_id == NULL ) { /* No message-id at all, let's generate one by taking a * hash over the file's contents. */ - char *sha1 = notmuch_sha1_of_file (filename); + char *sha1 = _notmuch_sha1_of_file (filename); /* If that failed too, something is really wrong. Give up. */ if (sha1 == NULL) { @@ -2008,10 +2076,10 @@ notmuch_database_add_message (notmuch_database_t *notmuch, if (ret) goto DONE; - date = notmuch_message_file_get_header (message_file, "date"); + date = _notmuch_message_file_get_header (message_file, "date"); _notmuch_message_set_header_values (message, date, from, subject); - ret = _notmuch_message_index_file (message, filename); + ret = _notmuch_message_index_file (message, message_file); if (ret) goto DONE; } else { @@ -2037,7 +2105,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch, } if (message_file) - notmuch_message_file_close (message_file); + _notmuch_message_file_close (message_file); ret2 = notmuch_database_end_atomic (notmuch); if ((ret == NOTMUCH_STATUS_SUCCESS ||