mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-22 02:48:08 +01:00
tag-util: optimization of tag application
The idea is not to bother with restore operations if they don't change the set of tags. This is actually a relatively common case. In order to avoid fancy datastructures, this method is quadratic in the number of tags; at least on my mail database this doesn't seem to be a big problem.
This commit is contained in:
parent
60cd3b9a06
commit
5c7990f251
1 changed files with 68 additions and 0 deletions
68
tag-util.c
68
tag-util.c
|
@ -151,6 +151,71 @@ message_error (notmuch_message_t *message,
|
||||||
fprintf (stderr, "Status: %s\n", notmuch_status_to_string (status));
|
fprintf (stderr, "Status: %s\n", notmuch_status_to_string (status));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
makes_changes (notmuch_message_t *message,
|
||||||
|
tag_op_list_t *list,
|
||||||
|
tag_op_flag_t flags)
|
||||||
|
{
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
notmuch_tags_t *tags;
|
||||||
|
notmuch_bool_t changes = FALSE;
|
||||||
|
|
||||||
|
/* First, do we delete an existing tag? */
|
||||||
|
changes = FALSE;
|
||||||
|
for (tags = notmuch_message_get_tags (message);
|
||||||
|
! changes && notmuch_tags_valid (tags);
|
||||||
|
notmuch_tags_move_to_next (tags)) {
|
||||||
|
const char *cur_tag = notmuch_tags_get (tags);
|
||||||
|
int last_op = (flags & TAG_FLAG_REMOVE_ALL) ? -1 : 0;
|
||||||
|
|
||||||
|
/* scan backwards to get last operation */
|
||||||
|
i = list->count;
|
||||||
|
while (i > 0) {
|
||||||
|
i--;
|
||||||
|
if (strcmp (cur_tag, list->ops[i].tag) == 0) {
|
||||||
|
last_op = list->ops[i].remove ? -1 : 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changes = (last_op == -1);
|
||||||
|
}
|
||||||
|
notmuch_tags_destroy (tags);
|
||||||
|
|
||||||
|
if (changes)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* Now check for adding new tags */
|
||||||
|
for (i = 0; i < list->count; i++) {
|
||||||
|
notmuch_bool_t exists = FALSE;
|
||||||
|
|
||||||
|
if (list->ops[i].remove)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (tags = notmuch_message_get_tags (message);
|
||||||
|
notmuch_tags_valid (tags);
|
||||||
|
notmuch_tags_move_to_next (tags)) {
|
||||||
|
const char *cur_tag = notmuch_tags_get (tags);
|
||||||
|
if (strcmp (cur_tag, list->ops[i].tag) == 0) {
|
||||||
|
exists = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notmuch_tags_destroy (tags);
|
||||||
|
|
||||||
|
/* the following test is conservative,
|
||||||
|
* in the sense it ignores cases like +foo ... -foo
|
||||||
|
* but this is OK from a correctness point of view
|
||||||
|
*/
|
||||||
|
if (! exists)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
notmuch_status_t
|
notmuch_status_t
|
||||||
tag_op_list_apply (notmuch_message_t *message,
|
tag_op_list_apply (notmuch_message_t *message,
|
||||||
tag_op_list_t *list,
|
tag_op_list_t *list,
|
||||||
|
@ -160,6 +225,9 @@ tag_op_list_apply (notmuch_message_t *message,
|
||||||
notmuch_status_t status = 0;
|
notmuch_status_t status = 0;
|
||||||
tag_operation_t *tag_ops = list->ops;
|
tag_operation_t *tag_ops = list->ops;
|
||||||
|
|
||||||
|
if (! (flags & TAG_FLAG_PRE_OPTIMIZED) && ! makes_changes (message, list, flags))
|
||||||
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
status = notmuch_message_freeze (message);
|
status = notmuch_message_freeze (message);
|
||||||
if (status) {
|
if (status) {
|
||||||
message_error (message, status, "freezing message");
|
message_error (message, status, "freezing message");
|
||||||
|
|
Loading…
Reference in a new issue