Add notmuch_database_set_timestamp and notmuch_database_get_timestamp

These will be very helpful to implement an efficient "notmuch new"
command which imports new mail messages that have appeared.
This commit is contained in:
Carl Worth 2009-10-23 14:31:01 -07:00
parent 668f20bdfb
commit 68a10091d6
5 changed files with 158 additions and 9 deletions

View file

@ -484,6 +484,101 @@ notmuch_database_get_path (notmuch_database_t *notmuch)
return notmuch->path;
}
notmuch_private_status_t
find_timestamp_document (notmuch_database_t *notmuch, const char *db_key,
Xapian::Document *doc, unsigned int *doc_id)
{
return find_unique_document (notmuch, "timestamp", db_key, doc, doc_id);
}
/* We allow the user to use arbitrarily long keys for timestamps,
* (they're for filesystem paths after all, which have no limit we
* know about). But we have a term-length limit. So if we exceed that,
* we'll use the SHA-1 of the user's key as the actual key for
* constructing a database term.
*
* Caution: This function returns a newly allocated string which the
* caller should free() when finished.
*/
static char *
timestamp_db_key (const char *key)
{
if (strlen (key) + 1 > NOTMUCH_TERM_MAX) {
return notmuch_sha1_of_string (key);
} else {
return strdup (key);
}
}
notmuch_status_t
notmuch_database_set_timestamp (notmuch_database_t *notmuch,
const char *key, time_t timestamp)
{
Xapian::Document doc;
unsigned int doc_id;
notmuch_private_status_t status;
notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
char *db_key = NULL;
db_key = timestamp_db_key (key);
try {
status = find_timestamp_document (notmuch, db_key, &doc, &doc_id);
doc.add_value (0, Xapian::sortable_serialise (timestamp));
if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) {
char *term = talloc_asprintf (NULL, "%s%s",
_find_prefix ("timestamp"), db_key);
doc.add_term (term);
talloc_free (term);
notmuch->xapian_db->add_document (doc);
} else {
notmuch->xapian_db->replace_document (doc_id, doc);
}
} catch (Xapian::Error &error) {
fprintf (stderr, "A Xapian exception occurred: %s.\n",
error.get_msg().c_str());
ret = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
if (db_key)
free (db_key);
return ret;
}
time_t
notmuch_database_get_timestamp (notmuch_database_t *notmuch, const char *key)
{
Xapian::Document doc;
unsigned int doc_id;
notmuch_private_status_t status;
char *db_key = NULL;
time_t ret = 0;
db_key = timestamp_db_key (key);
try {
status = find_timestamp_document (notmuch, db_key, &doc, &doc_id);
if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
goto DONE;
ret = Xapian::sortable_unserialise (doc.get_value (0));
} catch (Xapian::Error &error) {
goto DONE;
}
DONE:
if (db_key)
free (db_key);
return ret;
}
notmuch_status_t
notmuch_database_add_message (notmuch_database_t *notmuch,
const char *filename)

View file

@ -82,7 +82,8 @@ prefix_t BOOLEAN_PREFIX[] = {
{ "attachment_extension", "O" },
{ "msgid", "Q" },
{ "thread", "H" },
{ "ref", "R" }
{ "ref", "R" },
{ "timestamp", "KTS" },
};
const char *

View file

@ -21,15 +21,15 @@
#ifndef NOTMUCH_PRIVATE_H
#define NOTMUCH_PRIVATE_H
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* For getline */
#endif
#include <stdio.h>
#include "notmuch.h"
NOTMUCH_BEGIN_DECLS
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* For getline */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>

View file

@ -18,11 +18,12 @@
* Author: Carl Worth <cworth@cworth.org>
*/
#include "notmuch.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* for getline */
#endif
#include <stdio.h>
#include "notmuch.h"
/* This is separate from notmuch-private.h because we're trying to
* keep notmuch.c from looking into any internals, (which helps us
@ -30,7 +31,6 @@
*/
#include "xutil.h"
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <sys/stat.h>

View file

@ -31,6 +31,8 @@
NOTMUCH_BEGIN_DECLS
#include <time.h>
#ifndef FALSE
#define FALSE 0
#endif
@ -172,6 +174,57 @@ notmuch_database_default_path (void);
const char *
notmuch_database_get_path (notmuch_database_t *database);
/* Store a timestamp within the database.
*
* The Notmuch database will not interpret this key nor the timestamp
* values at all. It will merely store them together and return the
* timestamp when notmuch_database_get_timestamp is called with the
* same value for 'key'.
*
* The intention is for the caller to use the timestamp to allow
* efficient identification of new messages to be added to the
* database. The recommended usage is as follows:
*
* o Read the mtime of a directory from the filesystem
*
* o Call add_message for all mail files in the directory
*
* o Call notmuch_database_set_timestamp with the path of the
* directory as 'key' and the originally read mtime as 'value'.
*
* Then, when wanting to check for updates to the directory in the
* future, the client can call notmuch_database_get_timestamp and know
* that it only needs to add files if the mtime of the directory and
* files are newer than the stored timestamp.
*
* Note: The notmuch_database_get_timestamp function does not allow
* the caller to distinguish a timestamp of 0 from a non-existent
* timestamp. So don't store a timestamp of 0 unless you are
* comfortable with that.
*
* Return value:
*
* NOTMUCH_STATUS_SUCCESS: Timestamp successfully stored in database.
*
* NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception
* occurred. Timestamp not stored.
*/
notmuch_status_t
notmuch_database_set_timestamp (notmuch_database_t *database,
const char *key, time_t timestamp);
/* Retrieve a timestamp from the database.
*
* Returns the timestamp value previously stored by calling
* notmuch_database_set_timestamp with the same value for 'key'.
*
* Returns 0 if no timestamp is stored for 'key' or if any error
* occurred querying the database.
*/
time_t
notmuch_database_get_timestamp (notmuch_database_t *database,
const char *key);
/* Add a new message to the given notmuch database.
*
* Here,'filename' should be a path relative to the the path of