Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id 8D945431E62 for ; Mon, 10 Dec 2012 22:55:42 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: -0.7 X-Spam-Level: X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5 tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id xpN7W7eipY4g for ; Mon, 10 Dec 2012 22:55:33 -0800 (PST) Received: from mail-pb0-f53.google.com (mail-pb0-f53.google.com [209.85.160.53]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (No client certificate requested) by olra.theworths.org (Postfix) with ESMTPS id 5F21D431FAE for ; Mon, 10 Dec 2012 22:55:33 -0800 (PST) Received: by mail-pb0-f53.google.com with SMTP id jt11so2279356pbb.26 for ; Mon, 10 Dec 2012 22:55:32 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=3N0dY6fCEF5/AFsfE/ySqxnuib2mCKQgpSCauMWO8LU=; b=G5Yqi3J1FnFlrlBecrJb32LhMBD1XSnVQQ47+P9/8XUFaB773wsP4zp0eUUYPnBxDG rZFfsbBXbU5Yvb5tftLfUC3vEKP0PaCwVgl0avCBr9bJus9qM5qaunELuIDPN2f5mQoF PUGZ8fJveTbOYqa5u3zjItz8fzypb97zxAFodTm9TRNPJKxEq2cv/X0oQyMOsLpIWiOL jVVbVVM/kMITBPbiplGrWA8PUiNmV7AeY6DcpQphBd2cHCxs1mHAl3l+znvE9CbSraAz 9NVMBwyLGSKSDd6CclAr2iRvwsOjfZRvizwOvN6wYPMZUumzx7Cn/ggGI+1pDrtDHL4v X/vA== Received: by 10.68.232.2 with SMTP id tk2mr46481367pbc.92.1355208932676; Mon, 10 Dec 2012 22:55:32 -0800 (PST) Received: from localhost ([2601:9:580:4c:21f:16ff:fe34:119e]) by mx.google.com with ESMTPS id qt3sm13240882pbb.32.2012.12.10.22.55.31 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 10 Dec 2012 22:55:31 -0800 (PST) From: Michael Forney To: notmuch@notmuchmail.org Subject: [PATCH 1/2] lib: Replace freeze/thaw functionality with single sync function Date: Mon, 10 Dec 2012 22:54:52 -0800 Message-Id: <1355208893-16122-2-git-send-email-mforney@mforney.org> X-Mailer: git-send-email 1.8.0 In-Reply-To: <1355208893-16122-1-git-send-email-mforney@mforney.org> References: <1355208893-16122-1-git-send-email-mforney@mforney.org> X-Gm-Message-State: ALoCoQlWzDRk31/WdUDpXOQOP+1paqEyVfxtwJKqS1PJoOsnuYgKhXvLW+U9y3G9BlwrxXkZy2rK X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 11 Dec 2012 06:55:42 -0000 In all cases I could find, message tags were being modified with freeze/thaw. This commit changes the default operation of notmuch_message_{add_tag,remove_tag,remove_all_tags} to *not* commit changes until notmuch_message_sync is called. --- bindings/go/src/notmuch/notmuch.go | 69 ++++------------ bindings/python/docs/source/message.rst | 4 +- bindings/python/notmuch/__init__.py | 1 - bindings/python/notmuch/errors.py | 7 -- bindings/python/notmuch/message.py | 139 ++++++++------------------------ bindings/ruby/defs.h | 6 +- bindings/ruby/init.c | 12 +-- bindings/ruby/message.c | 27 +------ bindings/ruby/status.c | 2 - contrib/notmuch-deliver/src/main.c | 10 +++ lib/database.cc | 14 ++-- lib/message.cc | 92 +++++---------------- lib/notmuch-private.h | 7 +- lib/notmuch.h | 87 ++++++-------------- notmuch-new.c | 4 +- notmuch-tag.c | 4 +- tag-util.c | 10 +-- 17 files changed, 123 insertions(+), 372 deletions(-) diff --git a/bindings/go/src/notmuch/notmuch.go b/bindings/go/src/notmuch/notmuch.go index 00bd53a..56eb710 100644 --- a/bindings/go/src/notmuch/notmuch.go +++ b/bindings/go/src/notmuch/notmuch.go @@ -26,7 +26,6 @@ const ( STATUS_DUPLICATE_MESSAGE_ID STATUS_NULL_POINTER STATUS_TAG_TOO_LONG - STATUS_UNBALANCED_FREEZE_THAW STATUS_UNBALANCED_ATOMIC STATUS_LAST_STATUS @@ -926,7 +925,7 @@ func (self *Message) RemoveTag(tag string) Status { /* Remove all tags from the given message. * - * See notmuch_message_freeze for an example showing how to safely + * See notmuch_message_sync for an example showing how to safely * replace tag values. * * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only @@ -939,79 +938,39 @@ func (self *Message) RemoveAllTags() Status { return Status(C.notmuch_message_remove_all_tags(self.message)) } -/* Freeze the current state of 'message' within the database. +/* Synchronize the current state of 'message' into the database. * - * This means that changes to the message state, (via + * This will commit any changes made to the message state, (via * notmuch_message_add_tag, notmuch_message_remove_tag, and - * notmuch_message_remove_all_tags), will not be committed to the - * database until the message is thawed with notmuch_message_thaw. + * notmuch_message_remove_all_tags), to the database. * - * Multiple calls to freeze/thaw are valid and these calls will - * "stack". That is there must be as many calls to thaw as to freeze - * before a message is actually thawed. - * - * The ability to do freeze/thaw allows for safe transactions to - * change tag values. For example, explicitly setting a message to - * have a given set of tags might look like this: - * - * notmuch_message_freeze (message); + * If this method succeeds, the message in the database is guaranteed to + * have the full set of changes made to the message committed to the + * database. For example, explicitly setting a message to have a given + * set of tags might look like this: * * notmuch_message_remove_all_tags (message); * * for (i = 0; i < NUM_TAGS; i++) * notmuch_message_add_tag (message, tags[i]); * - * notmuch_message_thaw (message); + * notmuch_message_sync (message); * - * With freeze/thaw used like this, the message in the database is - * guaranteed to have either the full set of original tag values, or - * the full set of new tag values, but nothing in between. - * - * Imagine the example above without freeze/thaw and the operation - * somehow getting interrupted. This could result in the message being - * left with no tags if the interruption happened after - * notmuch_message_remove_all_tags but before notmuch_message_add_tag. + * This method only works if the database associated with 'message' was + * opened in read-write mode. * * Return value: * - * NOTMUCH_STATUS_SUCCESS: Message successfully frozen. + * NOTMUCH_STATUS_SUCCESS: Message successfully synchronized. * * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only * mode so message cannot be modified. */ -func (self *Message) Freeze() Status { - if self.message == nil { - return STATUS_NULL_POINTER - } - return Status(C.notmuch_message_freeze(self.message)) -} - -/* Thaw the current 'message', synchronizing any changes that may have - * occurred while 'message' was frozen into the notmuch database. - * - * See notmuch_message_freeze for an example of how to use this - * function to safely provide tag changes. - * - * Multiple calls to freeze/thaw are valid and these calls with - * "stack". That is there must be as many calls to thaw as to freeze - * before a message is actually thawed. - * - * Return value: - * - * NOTMUCH_STATUS_SUCCESS: Message successfully thawed, (or at least - * its frozen count has successfully been reduced by 1). - * - * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: An attempt was made to thaw - * an unfrozen message. That is, there have been an unbalanced - * number of calls to notmuch_message_freeze and - * notmuch_message_thaw. - */ -func (self *Message) Thaw() Status { +func (self *Message) Sync() Status { if self.message == nil { return STATUS_NULL_POINTER } - - return Status(C.notmuch_message_thaw(self.message)) + return Status(C.notmuch_message_sync(self.message)) } /* Destroy a notmuch_message_t object. diff --git a/bindings/python/docs/source/message.rst b/bindings/python/docs/source/message.rst index 1a6cc3d..d3ada71 100644 --- a/bindings/python/docs/source/message.rst +++ b/bindings/python/docs/source/message.rst @@ -43,8 +43,6 @@ .. automethod:: remove_all_tags - .. automethod:: freeze - - .. automethod:: thaw + .. automethod:: sync .. automethod:: __str__ diff --git a/bindings/python/notmuch/__init__.py b/bindings/python/notmuch/__init__.py index 5561624..edd7cbd 100644 --- a/bindings/python/notmuch/__init__.py +++ b/bindings/python/notmuch/__init__.py @@ -72,7 +72,6 @@ from .errors import ( DuplicateMessageIdError, NullPointerError, TagTooLongError, - UnbalancedFreezeThawError, UnbalancedAtomicError, NotInitializedError, ) diff --git a/bindings/python/notmuch/errors.py b/bindings/python/notmuch/errors.py index f153a9c..cb748d6 100644 --- a/bindings/python/notmuch/errors.py +++ b/bindings/python/notmuch/errors.py @@ -54,7 +54,6 @@ STATUS = Status(['SUCCESS', 'DUPLICATE_MESSAGE_ID', 'NULL_POINTER', 'TAG_TOO_LONG', - 'UNBALANCED_FREEZE_THAW', 'UNBALANCED_ATOMIC', 'NOT_INITIALIZED']) """STATUS is a class, whose attributes provide constants that serve as return @@ -71,7 +70,6 @@ description. * DUPLICATE_MESSAGE_ID * NULL_POINTER * TAG_TOO_LONG - * UNBALANCED_FREEZE_THAW * UNBALANCED_ATOMIC * NOT_INITIALIZED @@ -99,7 +97,6 @@ class NotmuchError(Exception, Python3StringMixIn): STATUS.DUPLICATE_MESSAGE_ID: DuplicateMessageIdError, STATUS.NULL_POINTER: NullPointerError, STATUS.TAG_TOO_LONG: TagTooLongError, - STATUS.UNBALANCED_FREEZE_THAW: UnbalancedFreezeThawError, STATUS.UNBALANCED_ATOMIC: UnbalancedAtomicError, STATUS.NOT_INITIALIZED: NotInitializedError, } @@ -167,10 +164,6 @@ class TagTooLongError(NotmuchError): status = STATUS.TAG_TOO_LONG -class UnbalancedFreezeThawError(NotmuchError): - status = STATUS.UNBALANCED_FREEZE_THAW - - class UnbalancedAtomicError(NotmuchError): status = STATUS.UNBALANCED_ATOMIC diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index d1c1b58..600c01e 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -308,7 +308,7 @@ class Message(Python3StringMixIn): _add_tag.argtypes = [NotmuchMessageP, c_char_p] _add_tag.restype = c_uint - def add_tag(self, tag, sync_maildir_flags=False): + def add_tag(self, tag): """Adds a tag to the given message Adds a tag to the current message. The maximal tag length is defined in @@ -316,14 +316,6 @@ class Message(Python3StringMixIn): :param tag: String with a 'tag' to be added. - :param sync_maildir_flags: If notmuch configuration is set to do - this, add maildir flags corresponding to notmuch tags. See - underlying method :meth:`tags_to_maildir_flags`. Use False - if you want to add/remove many tags on a message without - having to physically rename the file every time. Do note, - that this will do nothing when a message is frozen, as tag - changes will not be committed to the database yet. - :returns: STATUS.SUCCESS if the tag was successfully added. Raises an exception otherwise. :raises: :exc:`NullPointerError` if the `tag` argument is NULL @@ -342,29 +334,19 @@ class Message(Python3StringMixIn): # bail out on failure if status != STATUS.SUCCESS: raise NotmuchError(status) - - if sync_maildir_flags: - self.tags_to_maildir_flags() return STATUS.SUCCESS _remove_tag = nmlib.notmuch_message_remove_tag _remove_tag.argtypes = [NotmuchMessageP, c_char_p] _remove_tag.restype = c_uint - def remove_tag(self, tag, sync_maildir_flags=False): + def remove_tag(self, tag): """Removes a tag from the given message If the message has no such tag, this is a non-operation and will report success anyway. :param tag: String with a 'tag' to be removed. - :param sync_maildir_flags: If notmuch configuration is set to do - this, add maildir flags corresponding to notmuch tags. See - underlying method :meth:`tags_to_maildir_flags`. Use False - if you want to add/remove many tags on a message without - having to physically rename the file every time. Do note, - that this will do nothing when a message is frozen, as tag - changes will not be committed to the database yet. :returns: STATUS.SUCCESS if the tag was successfully removed or if the message had no such tag. @@ -385,29 +367,18 @@ class Message(Python3StringMixIn): if status != STATUS.SUCCESS: raise NotmuchError(status) - if sync_maildir_flags: - self.tags_to_maildir_flags() return STATUS.SUCCESS _remove_all_tags = nmlib.notmuch_message_remove_all_tags _remove_all_tags.argtypes = [NotmuchMessageP] _remove_all_tags.restype = c_uint - def remove_all_tags(self, sync_maildir_flags=False): + def remove_all_tags(self): """Removes all tags from the given message. - See :meth:`freeze` for an example showing how to safely + See :meth:`sync` for an example showing how to safely replace tag values. - - :param sync_maildir_flags: If notmuch configuration is set to do - this, add maildir flags corresponding to notmuch tags. See - :meth:`tags_to_maildir_flags`. Use False if you want to - add/remove many tags on a message without having to - physically rename the file every time. Do note, that this - will do nothing when a message is frozen, as tag changes - will not be committed to the database yet. - :returns: STATUS.SUCCESS if the tags were successfully removed. Raises an exception otherwise. :raises: :exc:`ReadOnlyDatabaseError` if the database was opened @@ -424,46 +395,40 @@ class Message(Python3StringMixIn): if status != STATUS.SUCCESS: raise NotmuchError(status) - if sync_maildir_flags: - self.tags_to_maildir_flags() return STATUS.SUCCESS - _freeze = nmlib.notmuch_message_freeze - _freeze.argtypes = [NotmuchMessageP] - _freeze.restype = c_uint - - def freeze(self): - """Freezes the current state of 'message' within the database + _sync = nmlib.notmuch_message_sync + _sync.argtypes = [NotmuchMessageP] + _sync.restype = c_uint - This means that changes to the message state, (via :meth:`add_tag`, - :meth:`remove_tag`, and :meth:`remove_all_tags`), will not be - committed to the database until the message is :meth:`thaw` ed. + def sync(self, sync_maildir_flags=False): + """Synchronize the current state of 'message' into the database. - Multiple calls to freeze/thaw are valid and these calls will - "stack". That is there must be as many calls to thaw as to freeze - before a message is actually thawed. + This will commit any changes made to the message state, (via + :meth:`add_tag`, :meth:`remove_tag`, and :meth:`remove_all_tags`), to + the database. - The ability to do freeze/thaw allows for safe transactions to - change tag values. For example, explicitly setting a message to - have a given set of tags might look like this:: + If this method succeeds, the message in the database is guaranteed to + have the full set of changes made to the message committed to the + database. For example, explicitly setting a message to have a given set + of tags might look like this: - msg.freeze() msg.remove_all_tags(False) for tag in new_tags: msg.add_tag(tag, False) - msg.thaw() + msg.sync() msg.tags_to_maildir_flags() - With freeze/thaw used like this, the message in the database is - guaranteed to have either the full set of original tag values, or - the full set of new tag values, but nothing in between. + This method only works if the database associated with 'message' was + opened with NOTMUCH_DATABASE_MODE_READ_WRITE. - Imagine the example above without freeze/thaw and the operation - somehow getting interrupted. This could result in the message being - left with no tags if the interruption happened after - :meth:`remove_all_tags` but before :meth:`add_tag`. + :param sync_maildir_flags: If notmuch configuration is set to do + this, add maildir flags corresponding to notmuch tags. See + :meth:`tags_to_maildir_flags`. Use False if you want to + add/remove many tags on a message without having to + physically rename the file every time. - :returns: STATUS.SUCCESS if the message was successfully frozen. + :returns: STATUS.SUCCESS if the message was successfully synchronized. Raises an exception otherwise. :raises: :exc:`ReadOnlyDatabaseError` if the database was opened in read-only mode so message cannot be modified @@ -473,50 +438,14 @@ class Message(Python3StringMixIn): if not self._msg: raise NotInitializedError() - status = self._freeze(self._msg) - - if STATUS.SUCCESS == status: - # return on success - return status - - raise NotmuchError(status) - - _thaw = nmlib.notmuch_message_thaw - _thaw.argtypes = [NotmuchMessageP] - _thaw.restype = c_uint - - def thaw(self): - """Thaws the current 'message' + status = self._sync(self._msg) - Thaw the current 'message', synchronizing any changes that may have - occurred while 'message' was frozen into the notmuch database. - - See :meth:`freeze` for an example of how to use this - function to safely provide tag changes. - - Multiple calls to freeze/thaw are valid and these calls with - "stack". That is there must be as many calls to thaw as to freeze - before a message is actually thawed. - - :returns: STATUS.SUCCESS if the message was successfully frozen. - Raises an exception otherwise. - :raises: :exc:`UnbalancedFreezeThawError` if an attempt was made - to thaw an unfrozen message. That is, there have been - an unbalanced number of calls to :meth:`freeze` and - :meth:`thaw`. - :raises: :exc:`NotInitializedError` if message has not been - initialized - """ - if not self._msg: - raise NotInitializedError() - - status = self._thaw(self._msg) - - if STATUS.SUCCESS == status: - # return on success - return status + if status != STATUS.SUCCESS: + raise NotmuchError(status) - raise NotmuchError(status) + if sync_maildir_flags: + self.tags_to_maildir_flags() + raise STATUS.SUCCESS def is_match(self): """(Not implemented)""" @@ -537,9 +466,9 @@ class Message(Python3StringMixIn): Also, if this filename is in a directory named "new", rename it to be within the neighboring directory named "cur". - Do note that calling this method while a message is frozen might - not work yet, as the modified tags have not been committed yet - to the database. + Do note that calling this method before :meth:`sync` is called + might not work yet, as the modified tags have not been committed + yet to the database. :returns: a :class:`STATUS` value. In short, you want to see notmuch.STATUS.SUCCESS here. See there for details.""" diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index fe81b3f..de36936 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -43,7 +43,6 @@ extern VALUE notmuch_rb_eFileError; extern VALUE notmuch_rb_eFileNotEmailError; extern VALUE notmuch_rb_eNullPointerError; extern VALUE notmuch_rb_eTagTooLongError; -extern VALUE notmuch_rb_eUnbalancedFreezeThawError; extern VALUE notmuch_rb_eUnbalancedAtomicError; extern ID ID_call; @@ -329,10 +328,7 @@ VALUE notmuch_rb_message_tags_to_maildir_flags (VALUE self); VALUE -notmuch_rb_message_freeze (VALUE self); - -VALUE -notmuch_rb_message_thaw (VALUE self); +notmuch_rb_message_sync (VALUE self); /* tags.c */ VALUE diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c index f4931d3..b7a7456 100644 --- a/bindings/ruby/init.c +++ b/bindings/ruby/init.c @@ -39,7 +39,6 @@ VALUE notmuch_rb_eFileError; VALUE notmuch_rb_eFileNotEmailError; VALUE notmuch_rb_eNullPointerError; VALUE notmuch_rb_eTagTooLongError; -VALUE notmuch_rb_eUnbalancedFreezeThawError; VALUE notmuch_rb_eUnbalancedAtomicError; ID ID_call; @@ -191,14 +190,6 @@ Init_notmuch (void) */ notmuch_rb_eTagTooLongError = rb_define_class_under (mod, "TagTooLongError", notmuch_rb_eBaseError); /* - * Document-class: Notmuch::UnbalancedFreezeThawError - * - * Raised when the notmuch_message_thaw function has been called more times - * than notmuch_message_freeze. - */ - notmuch_rb_eUnbalancedFreezeThawError = rb_define_class_under (mod, "UnbalancedFreezeThawError", - notmuch_rb_eBaseError); - /* * Document-class: Notmuch::UnbalancedAtomicError * * Raised when notmuch_database_end_atomic has been called more times than @@ -338,8 +329,7 @@ Init_notmuch (void) rb_define_method (notmuch_rb_cMessage, "remove_all_tags", notmuch_rb_message_remove_all_tags, 0); /* in message.c */ rb_define_method (notmuch_rb_cMessage, "maildir_flags_to_tags", notmuch_rb_message_maildir_flags_to_tags, 0); /* in message.c */ rb_define_method (notmuch_rb_cMessage, "tags_to_maildir_flags", notmuch_rb_message_tags_to_maildir_flags, 0); /* in message.c */ - rb_define_method (notmuch_rb_cMessage, "freeze", notmuch_rb_message_freeze, 0); /* in message.c */ - rb_define_method (notmuch_rb_cMessage, "thaw", notmuch_rb_message_thaw, 0); /* in message.c */ + rb_define_method (notmuch_rb_cMessage, "sync", notmuch_rb_message_sync, 0); /* in message.c */ /* * Document-class: Notmuch::Tags diff --git a/bindings/ruby/message.c b/bindings/ruby/message.c index eed4b31..719ca16 100644 --- a/bindings/ruby/message.c +++ b/bindings/ruby/message.c @@ -328,38 +328,19 @@ notmuch_rb_message_tags_to_maildir_flags (VALUE self) } /* - * call-seq: MESSAGE.freeze => true + * call-seq: MESSAGE.sync => true * - * Freeze the 'message' + * Sync the 'message' to the database */ VALUE -notmuch_rb_message_freeze (VALUE self) +notmuch_rb_message_sync (VALUE self) { notmuch_status_t ret; notmuch_message_t *message; Data_Get_Notmuch_Message (self, message); - ret = notmuch_message_freeze (message); - notmuch_rb_status_raise (ret); - - return Qtrue; -} - -/* - * call-seq: MESSAGE.thaw => true - * - * Thaw a 'message' - */ -VALUE -notmuch_rb_message_thaw (VALUE self) -{ - notmuch_status_t ret; - notmuch_message_t *message; - - Data_Get_Notmuch_Message (self, message); - - ret = notmuch_message_thaw (message); + ret = notmuch_message_sync (message); notmuch_rb_status_raise (ret); return Qtrue; diff --git a/bindings/ruby/status.c b/bindings/ruby/status.c index b11fb9f..8d1390a 100644 --- a/bindings/ruby/status.c +++ b/bindings/ruby/status.c @@ -41,8 +41,6 @@ notmuch_rb_status_raise (notmuch_status_t status) rb_raise (notmuch_rb_eNullPointerError, "null pointer"); case NOTMUCH_STATUS_TAG_TOO_LONG: rb_raise (notmuch_rb_eTagTooLongError, "tag too long"); - case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: - rb_raise (notmuch_rb_eUnbalancedFreezeThawError, "unbalanced freeze/thaw"); case NOTMUCH_STATUS_UNBALANCED_ATOMIC: rb_raise (notmuch_rb_eUnbalancedAtomicError, "unbalanced atomic"); default: diff --git a/contrib/notmuch-deliver/src/main.c b/contrib/notmuch-deliver/src/main.c index 032b9d6..afe84ff 100644 --- a/contrib/notmuch-deliver/src/main.c +++ b/contrib/notmuch-deliver/src/main.c @@ -300,6 +300,11 @@ add_tags(notmuch_message_t *message, char **tags) tags[i], notmuch_status_to_string(ret)); } + ret = notmuch_message_sync(message); + if (ret != NOTMUCH_STATUS_SUCCESS) + g_warning("Failed to sync changes to database: %s", + notmuch_status_to_string(ret)); + return i; } @@ -319,6 +324,11 @@ rm_tags(notmuch_message_t *message, char **tags) tags[i], notmuch_status_to_string(ret)); } + ret = notmuch_message_sync(message); + if (ret != NOTMUCH_STATUS_SUCCESS) + g_warning("Failed to sync changes to database: %s", + notmuch_status_to_string(ret)); + return i; } diff --git a/lib/database.cc b/lib/database.cc index 91d4329..98ea789 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -264,8 +264,6 @@ notmuch_status_to_string (notmuch_status_t status) return "Erroneous NULL pointer"; case NOTMUCH_STATUS_TAG_TOO_LONG: return "Tag value is too long (exceeds NOTMUCH_TAG_MAX)"; - case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: - return "Unbalanced number of calls to notmuch_message_freeze/thaw"; case NOTMUCH_STATUS_UNBALANCED_ATOMIC: return "Unbalanced number of calls to notmuch_database_begin_atomic/end_atomic"; default: @@ -917,7 +915,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, filename = _notmuch_message_talloc_copy_data (message); if (filename && *filename != '\0') { _notmuch_message_add_filename (message, filename); - _notmuch_message_sync (message); + notmuch_message_sync (message); } talloc_free (filename); @@ -993,7 +991,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, filename = _notmuch_message_talloc_copy_data (message); if (filename && *filename != '\0') { _notmuch_message_clear_data (message); - _notmuch_message_sync (message); + notmuch_message_sync (message); } talloc_free (filename); @@ -1483,7 +1481,7 @@ _merge_threads (notmuch_database_t *notmuch, _notmuch_message_remove_term (message, "thread", loser_thread_id); _notmuch_message_add_term (message, "thread", winner_thread_id); - _notmuch_message_sync (message); + notmuch_message_sync (message); notmuch_message_destroy (message); message = NULL; @@ -1601,7 +1599,7 @@ _notmuch_database_link_message_to_children (notmuch_database_t *notmuch, } else if (strcmp (*thread_id, child_thread_id)) { _notmuch_message_remove_term (child_message, "reference", message_id); - _notmuch_message_sync (child_message); + notmuch_message_sync (child_message); ret = _merge_threads (notmuch, *thread_id, child_thread_id); if (ret) goto DONE; @@ -1828,7 +1826,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch, ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; } - _notmuch_message_sync (message); + notmuch_message_sync (message); } catch (const Xapian::Error &error) { fprintf (stderr, "A Xapian exception occurred adding message: %s.\n", error.get_msg().c_str()); @@ -1873,7 +1871,7 @@ notmuch_database_remove_message (notmuch_database_t *notmuch, if (status == NOTMUCH_STATUS_SUCCESS) _notmuch_message_delete (message); else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) - _notmuch_message_sync (message); + notmuch_message_sync (message); notmuch_message_destroy (message); } diff --git a/lib/message.cc b/lib/message.cc index 320901f..b7e4bbe 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -28,7 +28,6 @@ struct visible _notmuch_message { notmuch_database_t *notmuch; Xapian::docid doc_id; - int frozen; char *message_id; char *thread_id; char *in_reply_to; @@ -97,7 +96,6 @@ _notmuch_message_create_for_document (const void *talloc_owner, message->notmuch = notmuch; message->doc_id = doc_id; - message->frozen = 0; message->flags = 0; /* Each of these will be lazily created as needed. */ @@ -199,7 +197,7 @@ _notmuch_message_create (const void *talloc_owner, * returned message contains a newly created document (not yet * added to the database) and a document ID that is known not to * exist in the database. The caller can modify the message, and a - * call to _notmuch_message_sync will add * the document to the + * call to notmuch_message_sync will add the document to the * database. * * If an error occurs, this function will return NULL and *status @@ -476,7 +474,7 @@ notmuch_message_get_replies (notmuch_message_t *message) /* Add an additional 'filename' for 'message'. * * This change will not be reflected in the database until the next - * call to _notmuch_message_sync. */ + * call to notmuch_message_sync. */ notmuch_status_t _notmuch_message_add_filename (notmuch_message_t *message, const char *filename) @@ -515,7 +513,7 @@ _notmuch_message_add_filename (notmuch_message_t *message, /* Remove a particular 'filename' from 'message'. * * This change will not be reflected in the database until the next - * call to _notmuch_message_sync. + * call to notmuch_message_sync. * * If this message still has other filenames, returns * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID. @@ -831,17 +829,22 @@ _notmuch_message_set_header_values (notmuch_message_t *message, message->doc.add_value (NOTMUCH_VALUE_SUBJECT, subject); } -/* Synchronize changes made to message->doc out into the database. */ -void -_notmuch_message_sync (notmuch_message_t *message) +/* Synchronize changes made to message->doc into the given database. */ +notmuch_status_t +_notmuch_message_sync_to_database (notmuch_message_t *message, + notmuch_database_t *notmuch) { + notmuch_status_t status; Xapian::WritableDatabase *db; - if (message->notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) - return; + status = _notmuch_database_ensure_writable(notmuch); + if (status) + return status; - db = static_cast (message->notmuch->xapian_db); + db = static_cast (notmuch->xapian_db); db->replace_document (message->doc_id, message->doc); + + return NOTMUCH_STATUS_SUCCESS; } /* Delete a message document from the database. */ @@ -879,7 +882,7 @@ _notmuch_message_close (notmuch_message_t *message) * names to prefix values. * * This change will not be reflected in the database until the next - * call to _notmuch_message_sync. */ + * call to notmuch_message_sync. */ notmuch_private_status_t _notmuch_message_add_term (notmuch_message_t *message, const char *prefix_name, @@ -940,7 +943,7 @@ _notmuch_message_gen_terms (notmuch_message_t *message, * names to prefix values. * * This change will not be reflected in the database until the next - * call to _notmuch_message_sync. */ + * call to notmuch_message_sync. */ notmuch_private_status_t _notmuch_message_remove_term (notmuch_message_t *message, const char *prefix_name, @@ -977,11 +980,6 @@ notmuch_status_t notmuch_message_add_tag (notmuch_message_t *message, const char *tag) { notmuch_private_status_t private_status; - notmuch_status_t status; - - status = _notmuch_database_ensure_writable (message->notmuch); - if (status) - return status; if (tag == NULL) return NOTMUCH_STATUS_NULL_POINTER; @@ -995,9 +993,6 @@ notmuch_message_add_tag (notmuch_message_t *message, const char *tag) private_status); } - if (! message->frozen) - _notmuch_message_sync (message); - return NOTMUCH_STATUS_SUCCESS; } @@ -1005,11 +1000,6 @@ notmuch_status_t notmuch_message_remove_tag (notmuch_message_t *message, const char *tag) { notmuch_private_status_t private_status; - notmuch_status_t status; - - status = _notmuch_database_ensure_writable (message->notmuch); - if (status) - return status; if (tag == NULL) return NOTMUCH_STATUS_NULL_POINTER; @@ -1023,9 +1013,6 @@ notmuch_message_remove_tag (notmuch_message_t *message, const char *tag) private_status); } - if (! message->frozen) - _notmuch_message_sync (message); - return NOTMUCH_STATUS_SUCCESS; } @@ -1113,10 +1100,6 @@ notmuch_message_maildir_flags_to_tags (notmuch_message_t *message) if (! seen_maildir_info) return NOTMUCH_STATUS_SUCCESS; - status = notmuch_message_freeze (message); - if (status) - return status; - for (i = 0; i < ARRAY_SIZE(flag2tag); i++) { if ((strchr (combined_flags, flag2tag[i].flag) != NULL) ^ @@ -1129,7 +1112,7 @@ notmuch_message_maildir_flags_to_tags (notmuch_message_t *message) if (status) return status; } - status = notmuch_message_thaw (message); + status = notmuch_message_sync (message); talloc_free (combined_flags); @@ -1348,7 +1331,7 @@ notmuch_message_tags_to_maildir_flags (notmuch_message_t *message) continue; } - _notmuch_message_sync (message); + notmuch_message_sync (message); } talloc_free (filename_new); @@ -1364,14 +1347,9 @@ notmuch_status_t notmuch_message_remove_all_tags (notmuch_message_t *message) { notmuch_private_status_t private_status; - notmuch_status_t status; notmuch_tags_t *tags; const char *tag; - status = _notmuch_database_ensure_writable (message->notmuch); - if (status) - return status; - for (tags = notmuch_message_get_tags (message); notmuch_tags_valid (tags); notmuch_tags_move_to_next (tags)) @@ -1385,44 +1363,14 @@ notmuch_message_remove_all_tags (notmuch_message_t *message) } } - if (! message->frozen) - _notmuch_message_sync (message); - talloc_free (tags); return NOTMUCH_STATUS_SUCCESS; } notmuch_status_t -notmuch_message_freeze (notmuch_message_t *message) +notmuch_message_sync (notmuch_message_t *message) { - notmuch_status_t status; - - status = _notmuch_database_ensure_writable (message->notmuch); - if (status) - return status; - - message->frozen++; - - return NOTMUCH_STATUS_SUCCESS; -} - -notmuch_status_t -notmuch_message_thaw (notmuch_message_t *message) -{ - notmuch_status_t status; - - status = _notmuch_database_ensure_writable (message->notmuch); - if (status) - return status; - - if (message->frozen > 0) { - message->frozen--; - if (message->frozen == 0) - _notmuch_message_sync (message); - return NOTMUCH_STATUS_SUCCESS; - } else { - return NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW; - } + return _notmuch_message_sync_to_database (message, message->notmuch); } void diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 7a409f5..9a43129 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -122,7 +122,6 @@ typedef enum _notmuch_private_status { NOTMUCH_PRIVATE_STATUS_FILE_NOT_EMAIL = NOTMUCH_STATUS_FILE_NOT_EMAIL, NOTMUCH_PRIVATE_STATUS_NULL_POINTER = NOTMUCH_STATUS_NULL_POINTER, NOTMUCH_PRIVATE_STATUS_TAG_TOO_LONG = NOTMUCH_STATUS_TAG_TOO_LONG, - NOTMUCH_PRIVATE_STATUS_UNBALANCED_FREEZE_THAW = NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW, /* Then add our own private values. */ NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG = NOTMUCH_STATUS_LAST_STATUS, @@ -295,8 +294,10 @@ _notmuch_message_set_header_values (notmuch_message_t *message, const char *date, const char *from, const char *subject); -void -_notmuch_message_sync (notmuch_message_t *message); + +notmuch_status_t +_notmuch_message_sync_to_database (notmuch_message_t *message, + notmuch_database_t *notmuch); notmuch_status_t _notmuch_message_delete (notmuch_message_t *message); diff --git a/lib/notmuch.h b/lib/notmuch.h index 3633bed..f6962ee 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -78,9 +78,6 @@ typedef int notmuch_bool_t; * NOTMUCH_STATUS_TAG_TOO_LONG: A tag value is too long (exceeds * NOTMUCH_TAG_MAX) * - * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: The notmuch_message_thaw - * function has been called more times than notmuch_message_freeze. - * * NOTMUCH_STATUS_UNBALANCED_ATOMIC: notmuch_database_end_atomic has * been called more times than notmuch_database_begin_atomic. * @@ -99,7 +96,6 @@ typedef enum _notmuch_status { NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID, NOTMUCH_STATUS_NULL_POINTER, NOTMUCH_STATUS_TAG_TOO_LONG, - NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW, NOTMUCH_STATUS_UNBALANCED_ATOMIC, NOTMUCH_STATUS_LAST_STATUS @@ -1043,6 +1039,9 @@ notmuch_message_get_tags (notmuch_message_t *message); /* Add a tag to the given message. * + * The changes to the message will not be committed into the database + * until notmuch_message_sync is called. + * * Return value: * * NOTMUCH_STATUS_SUCCESS: Tag successfully added to message @@ -1051,15 +1050,15 @@ notmuch_message_get_tags (notmuch_message_t *message); * * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long * (exceeds NOTMUCH_TAG_MAX) - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so message cannot be modified. */ notmuch_status_t notmuch_message_add_tag (notmuch_message_t *message, const char *tag); /* Remove a tag from the given message. * + * The changes to the message will not be committed into the database + * until notmuch_message_sync is called. + * * Return value: * * NOTMUCH_STATUS_SUCCESS: Tag successfully removed from message @@ -1068,17 +1067,14 @@ notmuch_message_add_tag (notmuch_message_t *message, const char *tag); * * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long * (exceeds NOTMUCH_TAG_MAX) - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so message cannot be modified. */ notmuch_status_t notmuch_message_remove_tag (notmuch_message_t *message, const char *tag); /* Remove all tags from the given message. * - * See notmuch_message_freeze for an example showing how to safely - * replace tag values. + * See notmuch_message_sync for an example showing how to safely replace + * tag values. * * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only * mode so message cannot be modified. @@ -1148,79 +1144,44 @@ notmuch_message_maildir_flags_to_tags (notmuch_message_t *message); * * A client can ensure that maildir filename flags remain synchronized * with notmuch database tags by calling this function after changing - * tags, (after calls to notmuch_message_add_tag, - * notmuch_message_remove_tag, or notmuch_message_freeze/ - * notmuch_message_thaw). See also notmuch_message_maildir_flags_to_tags - * for synchronizing maildir flag changes back to tags. + * tags, (after calls to notmuch_message_sync). + * + * See also notmuch_message_maildir_flags_to_tags for synchronizing + * maildir flag changes back to tags. */ notmuch_status_t notmuch_message_tags_to_maildir_flags (notmuch_message_t *message); -/* Freeze the current state of 'message' within the database. +/* Synchronize the current state of 'message' into the database. * - * This means that changes to the message state, (via + * This will commit any changes made to the message state, (via * notmuch_message_add_tag, notmuch_message_remove_tag, and - * notmuch_message_remove_all_tags), will not be committed to the - * database until the message is thawed with notmuch_message_thaw. - * - * Multiple calls to freeze/thaw are valid and these calls will - * "stack". That is there must be as many calls to thaw as to freeze - * before a message is actually thawed. + * notmuch_message_remove_all_tags), to the database. * - * The ability to do freeze/thaw allows for safe transactions to - * change tag values. For example, explicitly setting a message to - * have a given set of tags might look like this: - * - * notmuch_message_freeze (message); + * If this method succeeds, the message in the database is guaranteed to + * have the full set of changes made to the message committed to the + * database. For example, explicitly setting a message to have a given + * set of tags might look like this: * * notmuch_message_remove_all_tags (message); * * for (i = 0; i < NUM_TAGS; i++) * notmuch_message_add_tag (message, tags[i]); * - * notmuch_message_thaw (message); - * - * With freeze/thaw used like this, the message in the database is - * guaranteed to have either the full set of original tag values, or - * the full set of new tag values, but nothing in between. + * notmuch_message_sync (message); * - * Imagine the example above without freeze/thaw and the operation - * somehow getting interrupted. This could result in the message being - * left with no tags if the interruption happened after - * notmuch_message_remove_all_tags but before notmuch_message_add_tag. + * This method only works if the database associated with 'message' was + * opened in read-write mode. * * Return value: * - * NOTMUCH_STATUS_SUCCESS: Message successfully frozen. + * NOTMUCH_STATUS_SUCCESS: Message successfully synchronized. * * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only * mode so message cannot be modified. */ notmuch_status_t -notmuch_message_freeze (notmuch_message_t *message); - -/* Thaw the current 'message', synchronizing any changes that may have - * occurred while 'message' was frozen into the notmuch database. - * - * See notmuch_message_freeze for an example of how to use this - * function to safely provide tag changes. - * - * Multiple calls to freeze/thaw are valid and these calls with - * "stack". That is there must be as many calls to thaw as to freeze - * before a message is actually thawed. - * - * Return value: - * - * NOTMUCH_STATUS_SUCCESS: Message successfully thawed, (or at least - * its frozen count has successfully been reduced by 1). - * - * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: An attempt was made to thaw - * an unfrozen message. That is, there have been an unbalanced - * number of calls to notmuch_message_freeze and - * notmuch_message_thaw. - */ -notmuch_status_t -notmuch_message_thaw (notmuch_message_t *message); +notmuch_message_sync (notmuch_message_t *message); /* Destroy a notmuch_message_t object. * diff --git a/notmuch-new.c b/notmuch-new.c index feb9c32..644a809 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -509,12 +509,11 @@ add_files (notmuch_database_t *notmuch, /* success */ case NOTMUCH_STATUS_SUCCESS: state->added_messages++; - notmuch_message_freeze (message); for (tag=state->new_tags; *tag != NULL; tag++) notmuch_message_add_tag (message, *tag); if (state->synchronize_flags == TRUE) notmuch_message_maildir_flags_to_tags (message); - notmuch_message_thaw (message); + notmuch_message_sync (message); break; /* Non-fatal issues (go on to next file) */ case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: @@ -537,7 +536,6 @@ add_files (notmuch_database_t *notmuch, case NOTMUCH_STATUS_FILE_ERROR: case NOTMUCH_STATUS_NULL_POINTER: case NOTMUCH_STATUS_TAG_TOO_LONG: - case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: case NOTMUCH_STATUS_UNBALANCED_ATOMIC: case NOTMUCH_STATUS_LAST_STATUS: INTERNAL_ERROR ("add_message returned unexpected value: %d", status); diff --git a/notmuch-tag.c b/notmuch-tag.c index 88d559b..23714c9 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -145,8 +145,6 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, notmuch_messages_move_to_next (messages)) { message = notmuch_messages_get (messages); - notmuch_message_freeze (message); - for (i = 0; tag_ops[i].tag; i++) { if (tag_ops[i].remove) notmuch_message_remove_tag (message, tag_ops[i].tag); @@ -154,7 +152,7 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, notmuch_message_add_tag (message, tag_ops[i].tag); } - notmuch_message_thaw (message); + notmuch_message_sync (message); if (synchronize_flags) notmuch_message_tags_to_maildir_flags (message); diff --git a/tag-util.c b/tag-util.c index eab482f..65db504 100644 --- a/tag-util.c +++ b/tag-util.c @@ -228,12 +228,6 @@ tag_op_list_apply (notmuch_message_t *message, if (! (flags & TAG_FLAG_PRE_OPTIMIZED) && ! makes_changes (message, list, flags)) return NOTMUCH_STATUS_SUCCESS; - status = notmuch_message_freeze (message); - if (status) { - message_error (message, status, "freezing message"); - return status; - } - if (flags & TAG_FLAG_REMOVE_ALL) { status = notmuch_message_remove_all_tags (message); if (status) { @@ -259,9 +253,9 @@ tag_op_list_apply (notmuch_message_t *message, } } - status = notmuch_message_thaw (message); + status = notmuch_message_sync (message); if (status) { - message_error (message, status, "thawing message"); + message_error (message, status, "syncing message"); return status; } -- 1.8.0