database: Store the parent ID for each directory document.

Storing the document ID of the parent of each directory document will
allow us to find all child-directory documents for a given directory
document. We will need this in order to detect directories that have
been removed from the mail store, (though we aren't yet doing this).
This commit is contained in:
Carl Worth 2009-12-19 13:20:26 -08:00
parent 851c97aed7
commit e890b0cf40

View file

@ -84,9 +84,11 @@ typedef struct {
* maintain data necessary to allow for efficient polling of mail * maintain data necessary to allow for efficient polling of mail
* directories. * directories.
* *
* The directory document is indexed with a single prefixed term: * The directory document contains the following terms:
* *
* directory: The directory path (relative to the database path) * directory: The directory path (relative to the database path)
* parent: The document ID of the parent directory document.
* Top-level directories will have a parent value of 0.
* *
* and has a single value: * and has a single value:
* *
@ -113,6 +115,7 @@ prefix_t BOOLEAN_PREFIX_INTERNAL[] = {
{ "reference", "XREFERENCE" }, { "reference", "XREFERENCE" },
{ "replyto", "XREPLYTO" }, { "replyto", "XREPLYTO" },
{ "directory", "XDIRECTORY" }, { "directory", "XDIRECTORY" },
{ "parent", "XPARENT" },
}; };
prefix_t BOOLEAN_PREFIX_EXTERNAL[] = { prefix_t BOOLEAN_PREFIX_EXTERNAL[] = {
@ -587,6 +590,76 @@ directory_db_path (const char *path)
return path; return path;
} }
notmuch_status_t
_find_parent_id (notmuch_database_t *notmuch,
const char *path,
Xapian::docid *parent_id)
{
const char *slash, *parent_db_path;
char *parent_path;
notmuch_private_status_t private_status;
notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
if (path == NULL || *path == '\0') {
*parent_id = 0;
return NOTMUCH_STATUS_SUCCESS;
}
/* Find the last slash (not counting a trailing slash), if any. */
slash = path + strlen (path) - 1;
/* First, skip trailing slashes. */
while (slash != path) {
if (*slash != '/')
break;
--slash;
}
/* Then, find a slash. */
while (slash != path) {
if (*slash == '/')
break;
--slash;
}
/* Finally, skip multiple slashes. */
while (slash != path) {
if (*slash != '/')
break;
--slash;
}
if (slash == path)
parent_path = talloc_strdup (notmuch, "");
else
parent_path = talloc_strndup (notmuch, path, slash - path + 1);
parent_db_path = directory_db_path (parent_path);
private_status = find_unique_doc_id (notmuch, "directory",
parent_db_path, parent_id);
if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) {
status = notmuch_database_set_directory_mtime (notmuch,
parent_path, 0);
if (status)
return status;
private_status = find_unique_doc_id (notmuch, "directory",
parent_db_path, parent_id);
status = COERCE_STATUS (private_status, "_find_parent_id");
}
if (parent_db_path != parent_path)
free ((char *) parent_db_path);
talloc_free (parent_path);
return status;
}
/* Given a legal 'path' for the database, return the relative path. /* Given a legal 'path' for the database, return the relative path.
* *
* The return value will be a pointer to the originl path contents, * The return value will be a pointer to the originl path contents,
@ -632,6 +705,7 @@ notmuch_database_set_directory_mtime (notmuch_database_t *notmuch,
notmuch_private_status_t status; notmuch_private_status_t status;
notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS; notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
const char *db_path = NULL; const char *db_path = NULL;
Xapian::docid parent_id;
if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) { if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) {
fprintf (stderr, "Attempted to update a read-only database.\n"); fprintf (stderr, "Attempted to update a read-only database.\n");
@ -655,6 +729,16 @@ notmuch_database_set_directory_mtime (notmuch_database_t *notmuch,
doc.add_term (term); doc.add_term (term);
talloc_free (term); talloc_free (term);
status = _find_parent_id (notmuch, path, &parent_id);
if (status)
return status;
term = talloc_asprintf (NULL, "%s%u",
_find_prefix ("parent"),
parent_id);
doc.add_term (term);
talloc_free (term);
db->add_document (doc); db->add_document (doc);
} else { } else {
db->replace_document (doc_id, doc); db->replace_document (doc_id, doc);