Send MailboxUpdate events when threads are updated

Depending on the insertion order of folders which is non-deterministic
because it relies on the kernel's scheduling of parsing threads, the
listing the user sees might not be up-to-date because later thread
updates are never broadcast. This results in inconsistencies between
threads and mail listings when a thread's root envelope was part of a
not broadcast update leading to `key not found` panics in a listing's
hashmaps.
embed
Manos Pitsidianakis 2019-08-02 15:17:23 +03:00
parent 3aec1f6dec
commit bc7da4610e
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 23 additions and 4 deletions

View File

@ -120,13 +120,15 @@ impl Collection {
} }
} }
/// Merge new Mailbox to collection and update threads.
/// Returns a list of already existing folders whose threads were updated
pub fn merge( pub fn merge(
&mut self, &mut self,
mut envelopes: FnvHashMap<EnvelopeHash, Envelope>, mut envelopes: FnvHashMap<EnvelopeHash, Envelope>,
folder_hash: FolderHash, folder_hash: FolderHash,
mailbox: &mut Mailbox, mailbox: &mut Mailbox,
sent_folder: Option<FolderHash>, sent_folder: Option<FolderHash>,
) { ) -> Option<StackVec<FolderHash>> {
self.sent_folder = sent_folder; self.sent_folder = sent_folder;
envelopes.retain(|&h, e| { envelopes.retain(|&h, e| {
if self.message_ids.contains_key(e.message_id().raw()) { if self.message_ids.contains_key(e.message_id().raw()) {
@ -150,6 +152,8 @@ impl Collection {
ref sent_folder, ref sent_folder,
.. ..
} = self; } = self;
let mut ret = StackVec::new();
for (t_fh, t) in threads.iter_mut() { for (t_fh, t) in threads.iter_mut() {
if sent_folder.map(|f| f == folder_hash).unwrap_or(false) { if sent_folder.map(|f| f == folder_hash).unwrap_or(false) {
let mut ordered_hash_set = new_threads let mut ordered_hash_set = new_threads
@ -163,8 +167,12 @@ impl Collection {
.partial_cmp(&envelopes[b].date()) .partial_cmp(&envelopes[b].date())
.unwrap() .unwrap()
}); });
let mut updated = false;
for h in ordered_hash_set { for h in ordered_hash_set {
t.insert_reply(envelopes, h); updated |= t.insert_reply(envelopes, h);
}
if updated {
ret.push(*t_fh);
} }
continue; continue;
} }
@ -183,6 +191,11 @@ impl Collection {
} }
} }
threads.insert(folder_hash, new_threads); threads.insert(folder_hash, new_threads);
if ret.is_empty() {
None
} else {
Some(ret)
}
} }
pub fn update(&mut self, old_hash: EnvelopeHash, envelope: Envelope, folder_hash: FolderHash) { pub fn update(&mut self, old_hash: EnvelopeHash, envelope: Envelope, folder_hash: FolderHash) {

View File

@ -468,8 +468,14 @@ impl Account {
return; return;
} }
let (envelopes, mut mailbox) = payload.unwrap(); let (envelopes, mut mailbox) = payload.unwrap();
self.collection if let Some(updated_folders) =
.merge(envelopes, folder_hash, &mut mailbox, self.sent_folder); self.collection
.merge(envelopes, folder_hash, &mut mailbox, self.sent_folder)
{
for f in updated_folders {
self.notify_fn.notify(f);
}
}
self.folders self.folders
.insert(folder_hash, MailboxEntry::Available(mailbox)); .insert(folder_hash, MailboxEntry::Available(mailbox));
} }