--- /dev/null
+Return-Path: <bremner@pivot.cs.unb.ca>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id 28822431FBC\r
+ for <notmuch@notmuchmail.org>; Sun, 6 Dec 2009 10:30:57 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id ml5u7FT1xzzu for <notmuch@notmuchmail.org>;\r
+ Sun, 6 Dec 2009 10:30:56 -0800 (PST)\r
+Received: from pivot.cs.unb.ca (pivot.cs.unb.ca [131.202.240.57])\r
+ by olra.theworths.org (Postfix) with ESMTP id 5A73C431FAE\r
+ for <notmuch@notmuchmail.org>; Sun, 6 Dec 2009 10:30:56 -0800 (PST)\r
+Received: from\r
+ fctnnbsc30w-142167182194.pppoe-dynamic.high-speed.nb.bellaliant.net\r
+ ([142.167.182.194] helo=localhost)\r
+ by pivot.cs.unb.ca with esmtpsa (TLS1.0:RSA_AES_256_CBC_SHA1:32)\r
+ (Exim 4.69) (envelope-from <bremner@pivot.cs.unb.ca>)\r
+ id 1NHLsk-0000tQ-RB; Sun, 06 Dec 2009 14:30:55 -0400\r
+Received: from bremner by localhost with local (Exim 4.69)\r
+ (envelope-from <bremner@pivot.cs.unb.ca>)\r
+ id 1NHLse-0002pB-HU; Sun, 06 Dec 2009 14:30:48 -0400\r
+From: david@tethera.net\r
+To: notmuch@notmuchmail.org\r
+Date: Sun, 6 Dec 2009 14:30:25 -0400\r
+Message-Id: <1260124225-10830-1-git-send-email-david@tethera.net>\r
+X-Mailer: git-send-email 1.6.5.3\r
+X-Sender-Verified: bremner@pivot.cs.unb.ca\r
+Cc: David Bremner <bremner@unb.ca>\r
+Subject: [notmuch] [PATCH] notmuch-restore.c: only update tags for messages\r
+ that differ from dump file.\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.12\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Sun, 06 Dec 2009 18:30:57 -0000\r
+\r
+From: David Bremner <bremner@unb.ca>\r
+\r
+The main feature of this patch is that it compares the list of current\r
+tags on a message with those read by restore. Only if the two lists\r
+differ is the tag list in the message replaced. In my experiments this leads to\r
+a large performance improvement.\r
+\r
+Since I had to rewrite the parsing of tags from the dump file anyway\r
+to keep a list of tags (in case they should be written to the\r
+database), I decided to make it a bit more robust. It sorts the\r
+incoming tags (it is critical for the comparison of the two tag lists\r
+that they are both sorted), and allows arbitrary whitespace (as\r
+determined by "isspace") between tags.\r
+\r
+The patch allocates a temporary array to keep track of the current\r
+list of tags using calloc and grows it as neccesary using realloc.\r
+---\r
+ notmuch-restore.c | 73 ++++++++++++++++++++++++++++++++++++++++++++--------\r
+ 1 files changed, 61 insertions(+), 12 deletions(-)\r
+\r
+diff --git a/notmuch-restore.c b/notmuch-restore.c\r
+index 1b9598d..31e29f6 100644\r
+--- a/notmuch-restore.c\r
++++ b/notmuch-restore.c\r
+@@ -18,8 +18,17 @@\r
+ * Author: Carl Worth <cworth@cworth.org>\r
+ */\r
+ \r
++#include <stdlib.h>\r
++#include <string.h>\r
++#include <ctype.h>\r
+ #include "notmuch-client.h"\r
+ \r
++#define DEFAULT_TAG_ARRAY_SIZE 2\r
++/* for qsort */\r
++static int scmp( const void *sp1, const void *sp2 )\r
++{\r
++ return( strcmp(*(const char **)sp1, *(const char **)sp2) );\r
++}\r
+ int\r
+ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])\r
+ {\r
+@@ -31,6 +40,9 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])\r
+ ssize_t line_len;\r
+ regex_t regex;\r
+ int rerr;\r
++ char **tag_array=NULL;\r
++ int tag_array_size=DEFAULT_TAG_ARRAY_SIZE;\r
++\r
+ \r
+ config = notmuch_config_open (ctx, NULL, NULL);\r
+ if (config == NULL)\r
+@@ -61,11 +73,18 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])\r
+ "^([^ ]+) \\(([^)]*)\\)$",\r
+ REG_EXTENDED);\r
+ \r
++ /* Make an array of pointers to point to individual tokens */\r
++ tag_array=calloc(tag_array_size,sizeof(char*));\r
++\r
+ while ((line_len = getline (&line, &line_size, input)) != -1) {\r
+ regmatch_t match[3];\r
+- char *message_id, *tags, *tag, *next;\r
++ char *message_id, *tags, *next;\r
+ notmuch_message_t *message;\r
+ notmuch_status_t status;\r
++ int tag_count;\r
++\r
++ notmuch_tags_t *tag_list;\r
++ int i;\r
+ \r
+ chomp_newline (line);\r
+ \r
+@@ -89,26 +108,53 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])\r
+ goto NEXT_LINE;\r
+ }\r
+ \r
+- notmuch_message_freeze (message);\r
++ next=tags;\r
++ tag_count=0;\r
++ while(*next){\r
++ while(*next && isspace(*next))\r
++ next++;\r
++ if (*next) {\r
++ while (tag_count>= tag_array_size){\r
++ tag_array_size*=2;\r
++ tag_array=realloc(tag_array,tag_array_size*sizeof(char *));\r
++ }\r
++ tag_array[tag_count]=next;\r
++ tag_count++;\r
++ }\r
++ while (*next && !isspace(*next))\r
++ next++;\r
++ if (*next){\r
++ *next='\0';\r
++ next++;\r
++ }\r
++ }\r
++\r
++ qsort(tag_array,tag_count,sizeof(char*),scmp);\r
++ \r
++ tag_list = notmuch_message_get_tags (message);\r
++ i=0;\r
++ while (notmuch_tags_has_more (tag_list) && i<tag_count &&\r
++ (strcmp(notmuch_tags_get (tag_list),tag_array[i])==0)){\r
++ notmuch_tags_advance (tag_list);\r
++ i++;\r
++ }\r
+ \r
+- notmuch_message_remove_all_tags (message);\r
++ if (notmuch_tags_has_more (tag_list) && i<tag_count ){\r
++ notmuch_message_freeze (message);\r
++ notmuch_message_remove_all_tags (message);\r
+ \r
+- next = tags;\r
+- while (next) {\r
+- tag = strsep (&next, " ");\r
+- if (*tag == '\0')\r
+- continue;\r
+- status = notmuch_message_add_tag (message, tag);\r
++ for (i=0; i<tag_count; i++) {\r
++ status = notmuch_message_add_tag (message, tag_array[i]);\r
+ if (status) {\r
+ fprintf (stderr,\r
+ "Error applying tag %s to message %s:\n",\r
+- tag, message_id);\r
++ tag_array[i], message_id);\r
+ fprintf (stderr, "%s\n",\r
+ notmuch_status_to_string (status));\r
+ }\r
++ }\r
++ notmuch_message_thaw (message);\r
+ }\r
+-\r
+- notmuch_message_thaw (message);\r
+ notmuch_message_destroy (message);\r
+ NEXT_LINE:\r
+ free (message_id);\r
+@@ -120,6 +166,9 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])\r
+ if (line)\r
+ free (line);\r
+ \r
++ if (tag_array)\r
++ free (tag_array);\r
++\r
+ notmuch_database_close (notmuch);\r
+ if (input != stdin)\r
+ fclose (input);\r
+-- \r
+1.6.5.3\r
+\r