melib/notmuch: use message freeze/thaw for flag changes
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>pull/329/head
parent
ebe1b3da7e
commit
ca7d7bb95d
|
@ -19,16 +19,18 @@
|
||||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::{marker::PhantomData, ptr::NonNull};
|
use std::{cell::Cell, marker::PhantomData, ptr::NonNull};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
notmuch::ffi::{
|
notmuch::ffi::{
|
||||||
notmuch_database_find_message, notmuch_message_add_tag, notmuch_message_destroy,
|
_notmuch_status_NOTMUCH_STATUS_READ_ONLY_DATABASE,
|
||||||
|
_notmuch_status_NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW, notmuch_database_find_message,
|
||||||
|
notmuch_message_add_tag, notmuch_message_destroy, notmuch_message_freeze,
|
||||||
notmuch_message_get_date, notmuch_message_get_filename, notmuch_message_get_header,
|
notmuch_message_get_date, notmuch_message_get_filename, notmuch_message_get_header,
|
||||||
notmuch_message_get_message_id, notmuch_message_get_replies, notmuch_message_remove_tag,
|
notmuch_message_get_message_id, notmuch_message_get_replies, notmuch_message_remove_tag,
|
||||||
notmuch_message_tags_to_maildir_flags, notmuch_messages_get, notmuch_messages_move_to_next,
|
notmuch_message_tags_to_maildir_flags, notmuch_message_thaw, notmuch_messages_get,
|
||||||
notmuch_messages_valid,
|
notmuch_messages_move_to_next, notmuch_messages_valid,
|
||||||
},
|
},
|
||||||
thread::{ThreadHash, ThreadNode, ThreadNodeHash},
|
thread::{ThreadHash, ThreadNode, ThreadNodeHash},
|
||||||
};
|
};
|
||||||
|
@ -38,6 +40,7 @@ pub struct Message<'m> {
|
||||||
pub lib: Arc<NotmuchLibrary>,
|
pub lib: Arc<NotmuchLibrary>,
|
||||||
pub message: NonNull<ffi::notmuch_message_t>,
|
pub message: NonNull<ffi::notmuch_message_t>,
|
||||||
pub is_from_thread: bool,
|
pub is_from_thread: bool,
|
||||||
|
pub freezes: Cell<u8>,
|
||||||
pub _ph: PhantomData<&'m ffi::notmuch_message_t>,
|
pub _ph: PhantomData<&'m ffi::notmuch_message_t>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +64,7 @@ impl<'m> Message<'m> {
|
||||||
))
|
))
|
||||||
})?,
|
})?,
|
||||||
is_from_thread: false,
|
is_from_thread: false,
|
||||||
|
freezes: 0.into(),
|
||||||
_ph: PhantomData,
|
_ph: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -254,10 +258,101 @@ impl<'m> Message<'m> {
|
||||||
let c_str = unsafe { CStr::from_ptr(fs_path) };
|
let c_str = unsafe { CStr::from_ptr(fs_path) };
|
||||||
OsStr::from_bytes(c_str.to_bytes())
|
OsStr::from_bytes(c_str.to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Freeze the current state of 'message' within the database.
|
||||||
|
///
|
||||||
|
/// Quoted from `libnotmuch` C header:
|
||||||
|
///
|
||||||
|
/// > This means that changes 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.
|
||||||
|
/// >
|
||||||
|
/// > 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:
|
||||||
|
///
|
||||||
|
/// ```c
|
||||||
|
/// notmuch_message_freeze (message);
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
/// >
|
||||||
|
/// > 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.
|
||||||
|
/// >
|
||||||
|
/// > Return value:
|
||||||
|
/// >
|
||||||
|
/// > - `NOTMUCH_STATUS_SUCCESS`: Message successfully frozen.
|
||||||
|
/// > - `NOTMUCH_STATUS_READ_ONLY_DATABASE`: Database was opened in
|
||||||
|
/// > read-only
|
||||||
|
/// > mode so message cannot be modified.
|
||||||
|
#[doc(alias = "notmuch_message_freeze")]
|
||||||
|
pub fn freeze(&self) {
|
||||||
|
if _notmuch_status_NOTMUCH_STATUS_READ_ONLY_DATABASE
|
||||||
|
== unsafe { call!(self.lib, notmuch_message_freeze)(self.message.as_ptr()) }
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.freezes.set(self.freezes.get() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Thaw the current 'message', synchronizing any changes that may have
|
||||||
|
/// occurred while 'message' was frozen into the notmuch database.
|
||||||
|
///
|
||||||
|
/// Quoted from `libnotmuch` C header:
|
||||||
|
///
|
||||||
|
/// > See [`notmuch_message_freeze`](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`.
|
||||||
|
#[doc(alias = "notmuch_message_thaw")]
|
||||||
|
pub fn thaw(&self) {
|
||||||
|
if self.freezes.get() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if _notmuch_status_NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW
|
||||||
|
== unsafe { call!(self.lib, notmuch_message_thaw)(self.message.as_ptr()) }
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.freezes.set(self.freezes.get() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Message<'_> {
|
impl Drop for Message<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
while self.freezes.get() > 0 {
|
||||||
|
self.thaw();
|
||||||
|
}
|
||||||
unsafe { call!(self.lib, notmuch_message_destroy)(self.message.as_ptr()) };
|
unsafe { call!(self.lib, notmuch_message_destroy)(self.message.as_ptr()) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,6 +378,7 @@ impl<'q> Iterator for MessageIterator<'q> {
|
||||||
lib: self.lib.clone(),
|
lib: self.lib.clone(),
|
||||||
message: NonNull::new(message)?,
|
message: NonNull::new(message)?,
|
||||||
is_from_thread: self.is_from_thread,
|
is_from_thread: self.is_from_thread,
|
||||||
|
freezes: 0.into(),
|
||||||
_ph: PhantomData,
|
_ph: PhantomData,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -826,6 +826,7 @@ impl MailBackend for NotmuchDb {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
message.freeze();
|
||||||
|
|
||||||
let tags = message.tags().collect::<Vec<&CStr>>();
|
let tags = message.tags().collect::<Vec<&CStr>>();
|
||||||
|
|
||||||
|
@ -888,6 +889,8 @@ impl MailBackend for NotmuchDb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message.thaw();
|
||||||
|
|
||||||
/* Update message filesystem path. */
|
/* Update message filesystem path. */
|
||||||
message.tags_to_maildir_flags()?;
|
message.tags_to_maildir_flags()?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue