aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib/database.cc
Commit message (Collapse)AuthorAge
* lib: Refactor _notmuch_database_link_messageGravatar Austin Clements2014-10-11
| | | | | | This moves the code to retrieve and clear the metadata thread ID out of _notmuch_database_link_message into its own function. This will simplify future changes.
* lib: Move message ID compression to _notmuch_message_create_for_message_idGravatar Austin Clements2014-10-11
| | | | | | | | Previously, this was performed by notmuch_database_add_message. This happens to be the only caller currently (which is why this was safe), but we're about to introduce more callers, and it makes more sense to put responsibility for ID compression in the lower-level function rather than requiring each caller to handle it.
* lib: Simplify close and codify aborting atomic sectionGravatar Austin Clements2014-10-03
| | | | | | | | | | | | | | | | | | | | | In Xapian, closing a database implicitly aborts any outstanding transaction and commits changes. For historical reasons, notmuch_database_close had grown to almost, but not quite duplicate this behavior. Before closing the database, it would explicitly (and unnecessarily) commit it. However, if there was an outstanding transaction (ie atomic section), commit would throw a Xapian exception, which notmuch_database_close would unnecessarily print to stderr, even though notmuch_database_close would ultimately abort the transaction anyway when it called close. This patch simplifies notmuch_database_close to explicitly abort any outstanding transaction and then just call Database::close. This works for both read-only and read/write databases, takes care of committing changes, unifies the exception handling path, and codifies aborting outstanding transactions. This is currently the only way to abort an atomic section (and may remain so, since it would be difficult to roll back things we may have cached from rolled-back modifications).
* lib: Fix endless upgrade problemGravatar Austin Clements2014-09-01
| | | | | | | | | | | | | | 48db8c8 introduced a disagreement between when notmuch_database_needs_upgrade returned TRUE and when notmuch_database_upgrade actually performed an upgrade. As a result, if a database had a version less than 3, but no new features were required, notmuch new would call notmuch_database_upgrade to perform an upgrade, but notmuch_database_upgrade would return immediately without updating the database version. Hence, the next notmuch new would do the same, and so on. Fix this by ensuring that the upgrade-required logic is identical between the two.
* lib: Return an error from operations that require an upgradeGravatar Austin Clements2014-08-30
| | | | | | | | | | | | | | | | | Previously, there was no protection against a caller invoking an operation on an old database version that would effectively corrupt the database by treating it like a newer version. According to notmuch.h, any caller that opens the database in read/write mode is supposed to check if the database needs upgrading and perform an upgrade if it does. This would protect against this, but nobody (even the CLI) actually does this. However, with features, it's easy to protect against incompatible operations on a fine-grained basis. This lightweight change allows callers to safely operate on old database versions, while preventing specific operations that would corrupt the database with an informative error message.
* lib: Report progress for combined upgrade operationGravatar Austin Clements2014-08-30
| | | | | | | | | Previously, some parts of upgrade didn't report progress and for others it was possible for the progress meter to restart at 0 part way through the upgrade because each stage was reported separately. Fix this by computing the total amount of work that needs to be done up-front and updating completed work monotonically.
* lib: Reorganize upgrade around document typesGravatar Austin Clements2014-08-30
| | | | | | | | Rather than potentially making multiple passes over the same type of data in the database, reorganize upgrade around each type of data that may be upgraded. This eliminates code duplication, will make multi-version upgrades faster, and will let us improve progress reporting.
* lib: Use database features to drive upgradeGravatar Austin Clements2014-08-30
| | | | | | Previously, we had database version information hard-coded in the upgrade code. Slightly re-organize the upgrade process around the set of new database features to be enabled by the upgrade.
* lib: Simplify upgrade code using a transactionGravatar Austin Clements2014-08-30
| | | | | | | | | | | | Previously, the upgrade was organized as two passes -- an upgrade pass, and a separate cleanup pass -- so the database was always in a valid state. This change substantially simplifies this code by performing the upgrade in a transaction and combining both passes in to one. This 1) eliminates a lot of duplicate code between the passes, 2) speeds up the upgrade process, 3) makes progress reporting more accurate, 4) eliminates the potential for stale data if the upgrade is interrupted during the cleanup pass, and 5) makes it easier to reason about the safety of the upgrade code.
* lib: Database version 3: Introduce fine-grained "features"Gravatar Austin Clements2014-08-30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Previously, our database schema was versioned by a single number. Each database schema change had to occur "atomically" in Notmuch's development history: before some commit, Notmuch used version N, after that commit, it used version N+1. Hence, each new schema version could introduce only one change, the task of developing a schema change fell on a single person, and it all had to happen and be perfect in a single commit series. This made introducing a new schema version hard. We've seen only two schema changes in the history of Notmuch. This commit introduces database schema version 3; hopefully the last schema version we'll need for a while. With this version, we switch from a single version number to "features": a set of named, independent aspects of the database schema. Features should make backwards compatibility easier. For many things, it should be easy to support databases both with and without a feature, which will allow us to make upgrades optional and will enable "unstable" features that can be developed and tested over time. Features also make forwards compatibility easier. The features recorded in a database include "compatibility flags," which can indicate to an older version of Notmuch when it must support a given feature to open the database for read or for write. This lets us replace the old vague "I don't recognize this version, so something might go wrong, but I promise to try my best" warnings upon opening a database with an unknown version with precise errors. If a database is safe to open for read/write despite unknown features, an older version will know that and issue no message at all. If the database is not safe to open for read/write because of unknown features, an older version will know that, too, and can tell the user exactly which required features it lacks support for.
* Make parsing of References and In-Reply-To header less error proneGravatar Michal Sojka2014-08-16
| | | | | | | | | | | | | | | | According to RFC2822 References and In-Reply-To headers are supposed to contain one or more Message-IDs, however older RFC822 allowed almost any content. When both References and In-Reply-To headers ends with something else that a Message-ID (see e.g. [1]), the thread structure presented by notmuch is incorrect. The reason is that notmuch treats this case as if the email contained no "replyto" information (see _notmuch_database_link_message_to_parents). This patch changes the parse_references() function to return the last valid Message-ID encountered rather than NULL resulting from the last hunk of text not being the Message-ID. [1] https://lkml.org/lkml/headers/2014/5/19/864
* lib: Fix slight misinformation in the database schema docGravatar Austin Clements2014-08-04
| | | | | | The database schema documentation made it sound like each mail document had exactly one on-disk message file, which hasn't been true for a long time.
* lib: Start all function names in notmuch-private.h withGravatar Charles Celerier2014-07-13
| | | | | | | | | | | | | | | | | As noted in devel/STYLE, every private library function should start with _notmuch. This patch corrects function naming that did not adhere to this style in lib/notmuch-private.h. In particular, the old function names that now begin with _notmuch are notmuch_sha1_of_file notmuch_sha1_of_string notmuch_message_file_close notmuch_message_file_get_header notmuch_message_file_open notmuch_message_get_author notmuch_message_set_author Signed-off-by: Charles Celerier <cceleri@cs.stanford.edu>
* lib: add return status to database close and destroyGravatar Jani Nikula2014-07-09
| | | | | | | | | notmuch_database_close may fail in Xapian ->flush() or ->close(), so report the status. Similarly for notmuch_database_destroy which calls close. This is required for notmuch insert to report error status if message indexing failed.
* lib: replace the header parser with gmimeGravatar Jani Nikula2014-04-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The notmuch library includes a full blown message header parser. Yet the same message headers are parsed by gmime during indexing. Switch to gmime parsing completely. These are the main changes: * Gmime stops header parsing at the first invalid header, and presumes the message body starts from there. The current parser is quite liberal in accepting broken headers. The change means we will be much pickier about accepting invalid messages. * The current parser converts tabs used in header folding to spaces. Gmime preserve the tabs. Due to a broken python library used in mailman, there are plenty of mailing lists that produce headers with tabs in header folding, and we'll see plenty of tabs. (This change has been mitigated in preparatory patches.) * For pure header parsing, the current parser is likely faster than gmime, which parses the whole message rather than just the headers. Since we parse the message and its headers using gmime for indexing anyway, this avoids and extra header parsing round when adding new messages. In case of duplicate messages, we'll end up parsing the full message although just headers would be sufficient. All in all this should still speed up 'notmuch new'. * Calls to notmuch_message_get_header() may be slightly slower than previously for headers that are not indexed in the database, due to parsing of the whole message. Within the notmuch code base, notmuch reply is the only such user.
* lib: make folder: prefix literalGravatar Jani Nikula2014-03-11
| | | | | | | | | | | | | | | | | | | | | In xapian terms, convert folder: prefix from probabilistic to boolean prefix, matching the paths, relative from the maildir root, of the message files, ignoring the maildir new and cur leaf directories. folder:foo matches all message files in foo, foo/new, and foo/cur. folder:foo/new does *not* match message files in foo/new. folder:"" matches all message files in the top level maildir and its new and cur subdirectories. This change constitutes a database change: bump the database version and add database upgrade support for folder: terms. The upgrade also adds path: terms. Finally, fix the folder search test for literal folder: search, as some of the folder: matching capabilities are lost in the probabilistic to boolean prefix change.
* lib: add support for path: prefix searchesGravatar Jani Nikula2014-03-11
| | | | | | | | | | | | | | | | | The path: prefix is a literal boolean prefix matching the paths, relative from the maildir root, of the message files. path:foo matches all message files in foo (but not in foo/new or foo/cur). path:foo/new matches all message files in foo/new. path:"" matches all message files in the top level maildir. path:foo/** matches all message files in foo and recursively in all subdirectories of foo. path:** matches all message files recursively, i.e. all messages.
* compact: improve error messages on failures after compactionGravatar Tomi Ollila2013-11-19
| | | | | The error messages written during the steps replacing old database with new now includes relevant paths and strerror.
* compact: unconditionally remove old wip database compact directoryGravatar Tomi Ollila2013-11-19
| | | | | | In case previous notmuch compact has been interrupted there is old work-in-progress database compact directory partially filled. Remove it just before starting to fill the directory with new files.
* compact: preserve backup database until compacted database is in placeGravatar Tomi Ollila2013-11-19
| | | | | | | It is less error prone and window of failure opportunity is smaller if the old (backup) database is always renamed (instead of sometimes rmtree'd) before new (compacted) database is put into its place. Finally rmtree() old database in case old database backup is not kept.
* compact: catch Xapian::Error consistentlyGravatar Tomi Ollila2013-11-17
| | | | | | catch Xapian::Error in compact code in lib/database.cc to be consistent with other code in addition to not making software crash on uncaught other Xapian error.
* compact: tidy formattingGravatar Tomi Ollila2013-11-17
| | | | Notmuch compact code whitespace changes to match devel/STYLE.
* lib: use the compaction backup path provided by the callerGravatar Jani Nikula2013-11-07
| | | | | | | | The extra path component added by the lib is a magic value that the caller just has to know. This is demonstrated by the current code, which indeed has "xapian.old" both sides of the interface. Use the backup path provided by the lib caller verbatim, without adding anything to it.
* lib: add closure parameter to compact status update callbackGravatar Jani Nikula2013-11-07
| | | | This provides much more flexibility for the caller.
* lib: do not leak the database in compactionGravatar Jani Nikula2013-11-07
| | | | | Destroy instead of close the database after compaction, and also on error path, to not leak the database.
* lib: check talloc success in compactGravatar Jani Nikula2013-11-06
| | | | In line with the allocation checks all around.
* lib: construct compactor within try block to catch any exceptionsGravatar Jani Nikula2013-11-06
| | | | Constructors may also throw exceptions. Catch them.
* lib: fix build on !HAVE_XAPIAN_COMPACTGravatar Jani Nikula2013-10-30
| | | | | Minimal change to build notmuch against xapian that doesn't have compaction support.
* database: Add notmuch_database_compact_closeGravatar Ben Gamari2013-10-09
| | | | | | | | | This function uses Xapian's Compactor machinery to compact the notmuch database. The compacted database is built in a temporary directory and later moved into place while the original uncompacted database is preserved. Signed-off-by: Ben Gamari <bgamari.foss@gmail.com>
* lib/cli: pass GMIME_ENABLE_RFC2047_WORKAROUNDS to g_mime_init()Gravatar Jani Nikula2013-09-14
| | | | | | | | | | | | | | As explained by Jeffrey Stedfast, the author of GMime, quoted in [1]: > Passing the GMIME_ENABLE_RFC2047_WORKAROUNDS flag to g_mime_init() > *should* solve the decoding problem mentioned in the thread. This > flag should be safe to pass into g_mime_init() without any bad side > effects and my unit tests do test that code-path. The thread being referred to is [2]. [1] id:87bo56viyo.fsf@nikula.org [2] id:08cb1dcd-c5db-4e33-8b09-7730cb3d59a2@gmail.com
* cli: Guard deprecated g_type_init callsGravatar Tomi Ollila2013-06-08
| | | | | | | g_type_init was deprecated in GLib 2.35.1. In order to compile cleanly, guard these with a suitable #if. (commit msg from https://bugs.freedesktop.org/attachment.cgi?id=73774 )
* lib/database.cc: change how the parent of a message is calculatedGravatar Aaron Ecay2013-05-13
| | | | | | | | | | | | | | | | | | | | Presently, the code which finds the parent of a message as it is being added to the database assumes that the first Message-ID-like substring of the In-Reply-To header is the parent Message ID. Some mail clients, however, put stuff other than the Message-ID of the parent in the In-Reply-To header, such as the email address of the sender of the parent. This can fool notmuch. The updated algorithm prefers the last Message ID in the References header. The References header lists messages oldest-first, so the last Message ID is the parent (RFC2822, p. 24). The References header is also less likely to be in a non-standard syntax (http://cr.yp.to/immhf/thread.html, http://www.jwz.org/doc/threading.html). In case the References header is not to be found, fall back to the old behavior. V2 of this patch, incorporating feedback from Jani and (indirectly) Austin.
* lib: Reject multi-message mboxes and deprecate single-message mboxGravatar Austin Clements2012-11-26
| | | | | | | | Previously, we would treat multi-message mboxes as one giant email, which, besides the obvious incorrect indexing, often led to out-of-memory errors for archival mboxes. Now we explicitly reject multi-message mboxes. For historical reasons, we retain support for single-message mboxes, but official deprecate this behavior.
* lib: add date range query supportGravatar Jani Nikula2012-10-31
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Add a custom value range processor to enable date and time searches of the form date:since..until, where "since" and "until" are expressions understood by the previously added date/time parser, to restrict the results to messages within a particular time range (based on the Date: header). If "since" or "until" describes date/time at an accuracy of days or less, the values are rounded according to the accuracy, towards past for "since" and towards future for "until". For example, date:november..yesterday would match from the beginning of November until the end of yesterday. Expressions such as date:today..today means since the beginning of today until the end of today. Open-ended ranges are supported (since Xapian 1.2.1), i.e. you can specify date:..until or date:since.. to not limit the start or end date, respectively. CAVEATS: Xapian does not support spaces in range expressions. You can replace the spaces with '_', or (in most cases) '-', or (in some cases) leave the spaces out altogether. Entering date:expr without ".." (for example date:yesterday) will not work as you might expect. You can achieve the expected result by duplicating the expr both sides of ".." (for example date:yesterday..yesterday). Open-ended ranges won't work with pre-1.2.1 Xapian, but they don't produce an error either. Signed-off-by: Jani Nikula <jani@nikula.org>
* lib: Make notmuch_database_find_message_by_filename not crash on read-only ↵Gravatar Austin Clements2012-05-23
| | | | | | | | | | | databases Previously, _notmuch_database_filename_to_direntry would abort with an internal error when called on a read-only database. Now that creating the directory document is optional, notmuch_database_find_message_by_filename can disable directory document creation (as it should) and, as a result, not abort on read-only databases.
* lib: Make notmuch_database_get_directory return NULL if the directory is not ↵Gravatar Austin Clements2012-05-23
| | | | | | | | | | | | | | | found Using the new support from _notmuch_directory_create, this makes notmuch_database_get_directory a read-only operation that simply returns the directory object if it exists or NULL otherwise. This also means that notmuch_database_get_directory can work on read-only databases. This change breaks the directory mtime workaround in notmuch-new.c by fixing the exact issue it was working around. This permits mtime update races to prevent scans of changed directories, which non-deterministically breaks a few tests. The next patch fixes this.
* lib: Perform the same transformation to _notmuch_database_filename_to_direntryGravatar Austin Clements2012-05-23
| | | | | | Now _notmuch_database_filename_to_direntry takes a flags argument and can indicate if the necessary directory documents do not exist. Again, callers have been updated, but retain their original behavior.
* lib: Perform the same transformation to _notmuch_database_find_directory_idGravatar Austin Clements2012-05-23
| | | | | | | Now _notmuch_database_find_directory_id takes a flags argument, which it passes through to _notmuch_directory_create and can indicate if the directory does not exist. Again, callers have been updated, but retain their original behavior.
* lib: Make directory document creation optional for _notmuch_directory_createGravatar Austin Clements2012-05-23
| | | | | | | | | | | Previously this function would create directory documents if they didn't exist. As a result, it could only be used on writable databases. This adds an argument to make creation optional and to make this function work on read-only databases. We use a flag argument to avoid a bare boolean and to permit future expansion. Both callers have been updated, but currently retain the old behavior. We'll take advantage of the new argument in the following patches.
* lib/cli: Make notmuch_database_get_directory return a status codeGravatar Austin Clements2012-05-15
| | | | | | | | | | | | | | Previously, notmuch_database_get_directory had no way to indicate how it had failed. This changes its prototype to return a status code and set an out-argument to the retrieved directory, like similar functions in the library API. This does *not* change its currently broken behavior of creating directory objects when they don't exist, but it does document it and paves the way for fixing this. Also, it can now check for a read-only database and return NOTMUCH_STATUS_READ_ONLY_DATABASE instead of crashing. In the interest of atomicity, this also updates calls from the CLI so that notmuch still compiles.
* lib/cli: Make notmuch_database_create return a status codeGravatar Austin Clements2012-05-05
| | | | | | | | This is the notmuch_database_create equivalent of the previous change. In this case, there were places where errors were not being propagated correctly in notmuch_database_create or in calls to it. These have been fixed, using the new status value.
* lib/cli: Make notmuch_database_open return a status codeGravatar Austin Clements2012-05-05
| | | | | | | | | | | | It has been a long-standing issue that notmuch_database_open doesn't return any indication of why it failed. This patch changes its prototype to return a notmuch_status_t and set an out-argument to the database itself, like other functions that return both a status and an object. In the interest of atomicity, this also updates every use in the CLI so that notmuch still compiles. Since this patch does not update the bindings, the Python bindings test fails.
* Split notmuch_database_close into two functionsGravatar Justus Winter2012-04-28
| | | | | | | | | | | | | | | | | | Formerly notmuch_database_close closed the xapian database and destroyed the talloc structure associated with the notmuch database object. Split notmuch_database_close into notmuch_database_close and notmuch_database_destroy. This makes it possible for long running programs to close the xapian database and thus release the lock associated with it without destroying the data structures obtained from it. This also makes the api more consistent since every other data structure has a destructor function. The comments in notmuch.h are a courtesy of Austin Clements. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
* Fix error reporting in notmuch_database_find_message_by_filenameGravatar Justus Winter2012-03-18
| | | | | | | | | Formerly it was possible for *message_ret to be left uninitialized. The documentation however clearly states that "[o]n any failure or when the message is not found, this function initializes '*message' to NULL". Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
* Actually close the xapian database in notmuch_database_closeGravatar Justus Winter2012-03-03
| | | | | | | | | | | Formerly the xapian database object was deleted and closed in its destructor once the object was garbage collected. Explicitly call close() so that the database and the associated lock is released immediately. The comment is a courtesy of Austin Clements. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
* Prevent segmentation fault in notmuch_database_closeGravatar Justus Winter2012-02-20
| | | | | | | | | | | | Previously opening a notmuch database in read write mode that has been locked resulted in the notmuch_database_open function executing notmuch_database_close as a cleanup function. notmuch_database_close failed to check whether the xapian database has in fact been created. Add a check whether the xapian database object has actually been created before trying to call its flush method. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
* lib: Use talloc to simplify cleanup in notmuch_database_openGravatar Austin Clements2012-02-03
| | | | | | | Previously, we manually "free"d various pointers in notmuch_database_open. Use a local talloc context instead to simplify cleanup and eliminate various NULL pointer initializations and conditionals.
* lib: Release resources if notmuch_database_open failsGravatar Austin Clements2012-02-03
| | | | | Previously, if a Xapian exception occurred in notmuch_database_open, we failed to clean up the allocated notmuch_database_t object.
* lib: Don't delete uninitialized pointersGravatar Austin Clements2012-02-03
| | | | | | | | | In the error-handling paths of notmuch_database_open, we call notmuch_database_close, which "delete"s several objects referenced by the notmuch_database_t object. However, some of these pointers may be uninitialized, resulting in undefined behavior. Hence, allocate the notmuch_database_t with talloc_zero to make sure these pointers are NULL so that "delete"ing them is harmless.
* lib: call g_mime_init() from notmuch_database_open()Gravatar Kazuo Teramoto2011-12-31
| | | | | | | | | | | | | | As reported in id:"CAEbOPGyuHnz4BPtDutnTPUHcP3eYcRCRkXhYoJR43RUMw671+g@mail.gmail.com" sometimes gmime tries to access a NULL pointer, e.g. g_mime_iconv_open() tries to access iconv_cache that is NULL if g_mime_init() is not called. This causes notmuch to segfault when calling gmime functions. Calling g_mime_init() initializes iconv_cache and others variables needed by gmime, making sure they are initialized when notmuch calls gmime functions. Test marked fix by db.