notmuch->needs_upgrade = FALSE;
notmuch->mode = mode;
try {
+ string last_thread_id;
+
if (mode == NOTMUCH_DATABASE_MODE_READ_WRITE) {
notmuch->xapian_db = new Xapian::WritableDatabase (xapian_path,
Xapian::DB_CREATE_OR_OPEN);
notmuch_path, version, NOTMUCH_DATABASE_VERSION);
}
}
+
+ last_thread_id = notmuch->xapian_db->get_metadata ("last_thread_id");
+ if (last_thread_id.empty ()) {
+ notmuch->last_thread_id = 0;
+ } else {
+ const char *str;
+ char *end;
+
+ str = last_thread_id.c_str ();
+ notmuch->last_thread_id = strtoull (str, &end, 16);
+ if (*end != '\0')
+ INTERNAL_ERROR ("Malformed database last_thread_id: %s", str);
+ }
+
notmuch->query_parser = new Xapian::QueryParser;
notmuch->term_gen = new Xapian::TermGenerator;
notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
notmuch_status_t
notmuch_database_upgrade (notmuch_database_t *notmuch,
void (*progress_notify) (void *closure,
- unsigned int count,
- unsigned int total),
+ double progress),
void *closure)
{
Xapian::WritableDatabase *db;
notmuch_bool_t timer_is_active = FALSE;
unsigned int version;
notmuch_status_t status;
+ unsigned int count = 0, total = 0;
status = _notmuch_database_ensure_writable (notmuch);
if (status)
}
/* Before version 1, each message document had its filename in the
- * data field. Move that into the new format by calling
+ * data field. Copy that into the new format by calling
* notmuch_message_add_filename.
*/
if (version < 1) {
- unsigned int count = 0, total;
notmuch_query_t *query = notmuch_query_create (notmuch, "");
notmuch_messages_t *messages;
notmuch_message_t *message;
+ char *filename;
+ Xapian::TermIterator t, t_end;
total = notmuch_query_count_messages (query);
notmuch_messages_has_more (messages);
notmuch_messages_advance (messages))
{
- if (do_progress_notify)
- progress_notify (closure, count, total);
+ if (do_progress_notify) {
+ progress_notify (closure, (double) count / total);
+ do_progress_notify = 0;
+ }
message = notmuch_messages_get (messages);
- _notmuch_message_upgrade_filename_storage (message);
+ filename = _notmuch_message_talloc_copy_data (message);
+ if (filename && *filename != '\0') {
+ _notmuch_message_add_filename (message, filename);
+ _notmuch_message_sync (message);
+ }
+ talloc_free (filename);
+
+ notmuch_message_destroy (message);
count++;
}
- }
- /* Also, before version 1 we stored directory timestamps in
- * XTIMESTAMP documents instead of the current XDIRECTORY
- * documents. So convert those as well. */
- if (version < 1) {
- Xapian::TermIterator t, t_end;
+ notmuch_query_destroy (query);
+
+ /* Also, before version 1 we stored directory timestamps in
+ * XTIMESTAMP documents instead of the current XDIRECTORY
+ * documents. So copy those as well. */
t_end = notmuch->xapian_db->allterms_end ("XTIMESTAMP");
time_t mtime;
notmuch_directory_t *directory;
+ if (do_progress_notify) {
+ progress_notify (closure, (double) count / total);
+ do_progress_notify = 0;
+ }
+
document = find_document_for_doc_id (notmuch, *p);
mtime = Xapian::sortable_unserialise (
document.get_value (NOTMUCH_VALUE_TIMESTAMP));
db->set_metadata ("version", STRINGIFY (NOTMUCH_DATABASE_VERSION));
db->flush ();
+ /* Now that the upgrade is complete we can remove the old data
+ * and documents that are no longer needed. */
+ if (version < 1) {
+ notmuch_query_t *query = notmuch_query_create (notmuch, "");
+ notmuch_messages_t *messages;
+ notmuch_message_t *message;
+ char *filename;
+
+ for (messages = notmuch_query_search_messages (query);
+ notmuch_messages_has_more (messages);
+ notmuch_messages_advance (messages))
+ {
+ if (do_progress_notify) {
+ progress_notify (closure, (double) count / total);
+ do_progress_notify = 0;
+ }
+
+ message = notmuch_messages_get (messages);
+
+ filename = _notmuch_message_talloc_copy_data (message);
+ if (filename && *filename != '\0') {
+ _notmuch_message_clear_data (message);
+ _notmuch_message_sync (message);
+ }
+ talloc_free (filename);
+
+ notmuch_message_destroy (message);
+ }
+
+ notmuch_query_destroy (query);
+ }
+
+ if (version < 1) {
+ Xapian::TermIterator t, t_end;
+
+ t_end = notmuch->xapian_db->allterms_end ("XTIMESTAMP");
+
+ for (t = notmuch->xapian_db->allterms_begin ("XTIMESTAMP");
+ t != t_end;
+ t++)
+ {
+ Xapian::PostingIterator p, p_end;
+ std::string term = *t;
+
+ p_end = notmuch->xapian_db->postlist_end (term);
+
+ for (p = notmuch->xapian_db->postlist_begin (term);
+ p != p_end;
+ p++)
+ {
+ if (do_progress_notify) {
+ progress_notify (closure, (double) count / total);
+ do_progress_notify = 0;
+ }
+
+ db->delete_document (*p);
+ }
+ }
+ }
+
if (timer_is_active) {
/* Now stop the timer. */
timerval.it_interval.tv_sec = 0;
return ret;
}
+static const char *
+_notmuch_database_generate_thread_id (notmuch_database_t *notmuch)
+{
+ /* 16 bytes (+ terminator) for hexadecimal representation of
+ * a 64-bit integer. */
+ static char thread_id[17];
+ Xapian::WritableDatabase *db;
+
+ db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
+
+ notmuch->last_thread_id++;
+
+ sprintf (thread_id, "%016" PRIx64, notmuch->last_thread_id);
+
+ db->set_metadata ("last_thread_id", thread_id);
+
+ return thread_id;
+}
+
/* Given a (mostly empty) 'message' and its corresponding
* 'message_file' link it to existing threads in the database.
*
* We first look at 'message_file' and its link-relevant headers
* (References and In-Reply-To) for message IDs. We also look in the
- * database for existing message that reference 'message'.
+ * database for existing message that reference 'message'. In either
+ * case, we will assign to the current message the first thread_id
+ * found (through either parent or child). We will also merge any
+ * existing, distinct threads where this message belongs to both,
+ * (which is not uncommon when mesages are processed out of order).
*
- * The end result is to call _notmuch_message_ensure_thread_id which
+ * Finally, if not thread ID has been found through parent or child,
+ * we call _notmuch_message_generate_thread_id to generate a new
* generates a new thread ID if the message doesn't connect to any
* existing threads.
*/
if (status)
return status;
- if (thread_id == NULL)
- _notmuch_message_ensure_thread_id (message);
+ /* If not part of any existing thread, generate a new thread ID. */
+ if (thread_id == NULL) {
+ thread_id = _notmuch_database_generate_thread_id (notmuch);
+
+ _notmuch_message_add_term (message, "thread", thread_id);
+ }
return NOTMUCH_STATUS_SUCCESS;
}