]> git.notmuchmail.org Git - notmuch/blobdiff - lib/database.cc
Merge tag '0.31.4'
[notmuch] / lib / database.cc
index defa3062d03d84cd26640ff50a722915f4fc092f..f96ba7c004bd6338d0c0a92bb5ad94464a3d7f50 100644 (file)
  */
 
 #include "database-private.h"
-#include "parse-time-vrp.h"
-#include "query-fp.h"
-#include "thread-fp.h"
-#include "regexp-fields.h"
 #include "string-util.h"
 
 #include <iostream>
@@ -50,12 +46,6 @@ typedef struct {
 #define STRINGIFY(s) _SUB_STRINGIFY (s)
 #define _SUB_STRINGIFY(s) #s
 
-#if HAVE_XAPIAN_DB_RETRY_LOCK
-#define DB_ACTION (Xapian::DB_CREATE_OR_OPEN | Xapian::DB_RETRY_LOCK)
-#else
-#define DB_ACTION Xapian::DB_CREATE_OR_OPEN
-#endif
-
 #define LOG_XAPIAN_EXCEPTION(message, error) _log_xapian_exception (__location__, message, error)
 
 static void
@@ -463,109 +453,6 @@ notmuch_database_find_message (notmuch_database_t *notmuch,
     }
 }
 
-notmuch_status_t
-notmuch_database_create (const char *path, notmuch_database_t **database)
-{
-    char *status_string = NULL;
-    notmuch_status_t status;
-
-    status = notmuch_database_create_verbose (path, database,
-                                             &status_string);
-
-    if (status_string) {
-       fputs (status_string, stderr);
-       free (status_string);
-    }
-
-    return status;
-}
-
-notmuch_status_t
-notmuch_database_create_verbose (const char *path,
-                                notmuch_database_t **database,
-                                char **status_string)
-{
-    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
-    notmuch_database_t *notmuch = NULL;
-    char *notmuch_path = NULL;
-    char *message = NULL;
-    struct stat st;
-    int err;
-
-    if (path == NULL) {
-       message = strdup ("Error: Cannot create a database for a NULL path.\n");
-       status = NOTMUCH_STATUS_NULL_POINTER;
-       goto DONE;
-    }
-
-    if (path[0] != '/') {
-       message = strdup ("Error: Database path must be absolute.\n");
-       status = NOTMUCH_STATUS_PATH_ERROR;
-       goto DONE;
-    }
-
-    err = stat (path, &st);
-    if (err) {
-       IGNORE_RESULT (asprintf (&message, "Error: Cannot create database at %s: %s.\n",
-                                path, strerror (errno)));
-       status = NOTMUCH_STATUS_FILE_ERROR;
-       goto DONE;
-    }
-
-    if (! S_ISDIR (st.st_mode)) {
-       IGNORE_RESULT (asprintf (&message, "Error: Cannot create database at %s: "
-                                "Not a directory.\n",
-                                path));
-       status = NOTMUCH_STATUS_FILE_ERROR;
-       goto DONE;
-    }
-
-    notmuch_path = talloc_asprintf (NULL, "%s/%s", path, ".notmuch");
-
-    err = mkdir (notmuch_path, 0755);
-
-    if (err) {
-       IGNORE_RESULT (asprintf (&message, "Error: Cannot create directory %s: %s.\n",
-                                notmuch_path, strerror (errno)));
-       status = NOTMUCH_STATUS_FILE_ERROR;
-       goto DONE;
-    }
-
-    status = notmuch_database_open_verbose (path,
-                                           NOTMUCH_DATABASE_MODE_READ_WRITE,
-                                           &notmuch, &message);
-    if (status)
-       goto DONE;
-
-    /* Upgrade doesn't add these feature to existing databases, but
-     * new databases have them. */
-    notmuch->features |= NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES;
-    notmuch->features |= NOTMUCH_FEATURE_INDEXED_MIMETYPES;
-    notmuch->features |= NOTMUCH_FEATURE_UNPREFIX_BODY_ONLY;
-
-    status = notmuch_database_upgrade (notmuch, NULL, NULL);
-    if (status) {
-       notmuch_database_close (notmuch);
-       notmuch = NULL;
-    }
-
-  DONE:
-    if (notmuch_path)
-       talloc_free (notmuch_path);
-
-    if (message) {
-       if (status_string)
-           *status_string = message;
-       else
-           free (message);
-    }
-    if (database)
-       *database = notmuch;
-    else
-       talloc_free (notmuch);
-    return status;
-}
-
 notmuch_status_t
 _notmuch_database_ensure_writable (notmuch_database_t *notmuch)
 {
@@ -594,215 +481,6 @@ _notmuch_database_new_revision (notmuch_database_t *notmuch)
     return new_revision;
 }
 
-notmuch_status_t
-notmuch_database_open (const char *path,
-                      notmuch_database_mode_t mode,
-                      notmuch_database_t **database)
-{
-    char *status_string = NULL;
-    notmuch_status_t status;
-
-    status = notmuch_database_open_verbose (path, mode, database,
-                                           &status_string);
-
-    if (status_string) {
-       fputs (status_string, stderr);
-       free (status_string);
-    }
-
-    return status;
-}
-
-notmuch_status_t
-notmuch_database_open_verbose (const char *path,
-                              notmuch_database_mode_t mode,
-                              notmuch_database_t **database,
-                              char **status_string)
-{
-    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
-    void *local = talloc_new (NULL);
-    notmuch_database_t *notmuch = NULL;
-    char *notmuch_path, *xapian_path, *incompat_features;
-    char *message = NULL;
-    struct stat st;
-    int err;
-    unsigned int i, version;
-    static int initialized = 0;
-
-    if (path == NULL) {
-       message = strdup ("Error: Cannot open a database for a NULL path.\n");
-       status = NOTMUCH_STATUS_NULL_POINTER;
-       goto DONE;
-    }
-
-    if (path[0] != '/') {
-       message = strdup ("Error: Database path must be absolute.\n");
-       status = NOTMUCH_STATUS_PATH_ERROR;
-       goto DONE;
-    }
-
-    if (! (notmuch_path = talloc_asprintf (local, "%s/%s", path, ".notmuch"))) {
-       message = strdup ("Out of memory\n");
-       status = NOTMUCH_STATUS_OUT_OF_MEMORY;
-       goto DONE;
-    }
-
-    err = stat (notmuch_path, &st);
-    if (err) {
-       IGNORE_RESULT (asprintf (&message, "Error opening database at %s: %s\n",
-                                notmuch_path, strerror (errno)));
-       status = NOTMUCH_STATUS_FILE_ERROR;
-       goto DONE;
-    }
-
-    if (! (xapian_path = talloc_asprintf (local, "%s/%s", notmuch_path, "xapian"))) {
-       message = strdup ("Out of memory\n");
-       status = NOTMUCH_STATUS_OUT_OF_MEMORY;
-       goto DONE;
-    }
-
-    /* Initialize the GLib type system and threads */
-#if ! GLIB_CHECK_VERSION (2, 35, 1)
-    g_type_init ();
-#endif
-
-    /* Initialize gmime */
-    if (! initialized) {
-       g_mime_init ();
-       initialized = 1;
-    }
-
-    notmuch = talloc_zero (NULL, notmuch_database_t);
-    notmuch->exception_reported = false;
-    notmuch->status_string = NULL;
-    notmuch->path = talloc_strdup (notmuch, path);
-
-    strip_trailing (notmuch->path, '/');
-
-    notmuch->writable_xapian_db = NULL;
-    notmuch->atomic_nesting = 0;
-    notmuch->view = 1;
-    try {
-       string last_thread_id;
-       string last_mod;
-
-       if (mode == NOTMUCH_DATABASE_MODE_READ_WRITE) {
-           notmuch->writable_xapian_db = new Xapian::WritableDatabase (xapian_path,
-                                                                       DB_ACTION);
-           notmuch->xapian_db = notmuch->writable_xapian_db;
-       } else {
-           notmuch->xapian_db = new Xapian::Database (xapian_path);
-       }
-
-       /* Check version.  As of database version 3, we represent
-        * changes in terms of features, so assume a version bump
-        * means a dramatically incompatible change. */
-       version = notmuch_database_get_version (notmuch);
-       if (version > NOTMUCH_DATABASE_VERSION) {
-           IGNORE_RESULT (asprintf (&message,
-                                    "Error: Notmuch database at %s\n"
-                                    "       has a newer database format version (%u) than supported by this\n"
-                                    "       version of notmuch (%u).\n",
-                                    notmuch_path, version, NOTMUCH_DATABASE_VERSION));
-           notmuch_database_destroy (notmuch);
-           notmuch = NULL;
-           status = NOTMUCH_STATUS_FILE_ERROR;
-           goto DONE;
-       }
-
-       /* Check features. */
-       incompat_features = NULL;
-       notmuch->features = _notmuch_database_parse_features (
-           local, notmuch->xapian_db->get_metadata ("features").c_str (),
-           version, mode == NOTMUCH_DATABASE_MODE_READ_WRITE ? 'w' : 'r',
-           &incompat_features);
-       if (incompat_features) {
-           IGNORE_RESULT (asprintf (&message,
-                                    "Error: Notmuch database at %s\n"
-                                    "       requires features (%s)\n"
-                                    "       not supported by this version of notmuch.\n",
-                                    notmuch_path, incompat_features));
-           notmuch_database_destroy (notmuch);
-           notmuch = NULL;
-           status = NOTMUCH_STATUS_FILE_ERROR;
-           goto DONE;
-       }
-
-       notmuch->last_doc_id = notmuch->xapian_db->get_lastdocid ();
-       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);
-       }
-
-       /* Get current highest revision number. */
-       last_mod = notmuch->xapian_db->get_value_upper_bound (
-           NOTMUCH_VALUE_LAST_MOD);
-       if (last_mod.empty ())
-           notmuch->revision = 0;
-       else
-           notmuch->revision = Xapian::sortable_unserialise (last_mod);
-       notmuch->uuid = talloc_strdup (
-           notmuch, notmuch->xapian_db->get_uuid ().c_str ());
-
-       notmuch->query_parser = new Xapian::QueryParser;
-       notmuch->term_gen = new Xapian::TermGenerator;
-       notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
-       notmuch->value_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_TIMESTAMP);
-       notmuch->date_range_processor = new ParseTimeRangeProcessor (NOTMUCH_VALUE_TIMESTAMP, "date:");
-       notmuch->last_mod_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:");
-       notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
-       notmuch->query_parser->set_database (*notmuch->xapian_db);
-       notmuch->query_parser->set_stemmer (Xapian::Stem ("english"));
-       notmuch->query_parser->set_stemming_strategy (Xapian::QueryParser::STEM_SOME);
-       notmuch->query_parser->add_rangeprocessor (notmuch->value_range_processor);
-       notmuch->query_parser->add_rangeprocessor (notmuch->date_range_processor);
-       notmuch->query_parser->add_rangeprocessor (notmuch->last_mod_range_processor);
-
-       status = _notmuch_database_setup_standard_query_fields (notmuch);
-       if (status)
-           goto DONE;
-
-       status = _notmuch_database_setup_user_query_fields (notmuch);
-       if (status)
-           goto DONE;
-
-    } catch (const Xapian::Error &error) {
-       IGNORE_RESULT (asprintf (&message, "A Xapian exception occurred opening database: %s\n",
-                                error.get_msg ().c_str ()));
-       notmuch_database_destroy (notmuch);
-       notmuch = NULL;
-       status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
-    }
-
-  DONE:
-    talloc_free (local);
-
-    if (message) {
-       if (status_string)
-           *status_string = message;
-       else
-           free (message);
-    }
-
-    if (database)
-       *database = notmuch;
-    else
-       talloc_free (notmuch);
-
-    if (notmuch)
-       notmuch->open = true;
-
-    return status;
-}
-
 notmuch_status_t
 notmuch_database_close (notmuch_database_t *notmuch)
 {
@@ -924,27 +602,51 @@ notmuch_database_compact (const char *path,
                          notmuch_compact_status_cb_t status_cb,
                          void *closure)
 {
-    void *local;
-    char *notmuch_path, *xapian_path, *compact_xapian_path;
     notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
     notmuch_database_t *notmuch = NULL;
-    struct stat statbuf;
-    bool keep_backup;
     char *message = NULL;
 
-    local = talloc_new (NULL);
-    if (! local)
-       return NOTMUCH_STATUS_OUT_OF_MEMORY;
-
     ret = notmuch_database_open_verbose (path,
                                         NOTMUCH_DATABASE_MODE_READ_WRITE,
                                         &notmuch,
                                         &message);
     if (ret) {
        if (status_cb) status_cb (message, closure);
-       goto DONE;
+       return ret;
     }
 
+    _notmuch_config_cache (notmuch, NOTMUCH_CONFIG_DATABASE_PATH, path);
+
+    return notmuch_database_compact_db (notmuch,
+                                       backup_path,
+                                       status_cb,
+                                       closure);
+}
+
+notmuch_status_t
+notmuch_database_compact_db (notmuch_database_t *notmuch,
+                            const char *backup_path,
+                            notmuch_compact_status_cb_t status_cb,
+                            void *closure) {
+    void *local;
+    char *notmuch_path, *xapian_path, *compact_xapian_path;
+    const char* path;
+    notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
+    struct stat statbuf;
+    bool keep_backup;
+
+    ret = _notmuch_database_ensure_writable (notmuch);
+    if (ret)
+       return ret;
+
+    path = notmuch_config_get (notmuch, NOTMUCH_CONFIG_DATABASE_PATH);
+    if (! path)
+       return NOTMUCH_STATUS_PATH_ERROR;
+
+    local = talloc_new (NULL);
+    if (! local)
+       return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
     if (! (notmuch_path = talloc_asprintf (local, "%s/%s", path, ".notmuch"))) {
        ret = NOTMUCH_STATUS_OUT_OF_MEMORY;
        goto DONE;