melib/Collection: put all fields behind a mutex

master
Manos Pitsidianakis 2020-07-21 07:53:38 +03:00
parent 1112ef4717
commit 0882dbbad0
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
8 changed files with 255 additions and 119 deletions

View File

@ -60,12 +60,19 @@ impl DerefMut for EnvelopeRefMut<'_> {
} }
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone)]
pub struct Collection { pub struct Collection {
pub envelopes: Arc<RwLock<HashMap<EnvelopeHash, Envelope>>>, pub envelopes: Arc<RwLock<HashMap<EnvelopeHash, Envelope>>>,
pub threads: HashMap<MailboxHash, Threads>, pub message_id_index: Arc<RwLock<HashMap<Vec<u8>, EnvelopeHash>>>,
sent_mailbox: Option<MailboxHash>, pub threads: Arc<RwLock<HashMap<MailboxHash, Threads>>>,
pub mailboxes: HashMap<MailboxHash, HashSet<EnvelopeHash>>, sent_mailbox: Arc<RwLock<Option<MailboxHash>>>,
pub mailboxes: Arc<RwLock<HashMap<MailboxHash, HashSet<EnvelopeHash>>>>,
}
impl Default for Collection {
fn default() -> Self {
Self::new()
}
} }
/* /*
@ -89,15 +96,26 @@ impl Drop for Collection {
*/ */
impl Collection { impl Collection {
pub fn new(envelopes: HashMap<EnvelopeHash, Envelope>) -> Collection { pub fn new() -> Collection {
let threads = HashMap::with_capacity_and_hasher(16, Default::default()); let message_id_index = Arc::new(RwLock::new(HashMap::with_capacity_and_hasher(
let mailboxes = HashMap::with_capacity_and_hasher(16, Default::default()); 16,
Default::default(),
)));
let threads = Arc::new(RwLock::new(HashMap::with_capacity_and_hasher(
16,
Default::default(),
)));
let mailboxes = Arc::new(RwLock::new(HashMap::with_capacity_and_hasher(
16,
Default::default(),
)));
Collection { Collection {
envelopes: Arc::new(RwLock::new(envelopes)), envelopes: Arc::new(RwLock::new(Default::default())),
message_id_index,
threads, threads,
mailboxes, mailboxes,
sent_mailbox: None, sent_mailbox: Arc::new(RwLock::new(None)),
} }
} }
@ -112,14 +130,19 @@ impl Collection {
pub fn remove(&mut self, envelope_hash: EnvelopeHash, mailbox_hash: MailboxHash) { pub fn remove(&mut self, envelope_hash: EnvelopeHash, mailbox_hash: MailboxHash) {
debug!("DEBUG: Removing {}", envelope_hash); debug!("DEBUG: Removing {}", envelope_hash);
self.envelopes.write().unwrap().remove(&envelope_hash); self.envelopes.write().unwrap().remove(&envelope_hash);
self.mailboxes.entry(mailbox_hash).and_modify(|m| { self.mailboxes
m.remove(&envelope_hash); .write()
}); .unwrap()
self.threads .entry(mailbox_hash)
.and_modify(|m| {
m.remove(&envelope_hash);
});
let mut threads_lck = self.threads.write().unwrap();
threads_lck
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.remove(envelope_hash); .remove(envelope_hash);
for (h, t) in self.threads.iter_mut() { for (h, t) in threads_lck.iter_mut() {
if *h == mailbox_hash { if *h == mailbox_hash {
continue; continue;
} }
@ -137,15 +160,19 @@ impl Collection {
return false; return false;
} }
let mut envelope = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); let mut envelope = self.envelopes.write().unwrap().remove(&old_hash).unwrap();
self.mailboxes.entry(mailbox_hash).and_modify(|m| { self.mailboxes
m.remove(&old_hash); .write()
m.insert(new_hash); .unwrap()
}); .entry(mailbox_hash)
.and_modify(|m| {
m.remove(&old_hash);
m.insert(new_hash);
});
envelope.set_hash(new_hash); envelope.set_hash(new_hash);
self.envelopes.write().unwrap().insert(new_hash, envelope); self.envelopes.write().unwrap().insert(new_hash, envelope);
let mut threads_lck = self.threads.write().unwrap();
{ {
if self if threads_lck
.threads
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.update_envelope(&self.envelopes, old_hash, new_hash) .update_envelope(&self.envelopes, old_hash, new_hash)
@ -155,11 +182,11 @@ impl Collection {
} }
} }
/* envelope is not in threads, so insert it */ /* envelope is not in threads, so insert it */
self.threads threads_lck
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert(&mut self.envelopes, new_hash); .insert(&mut self.envelopes, new_hash);
for (h, t) in self.threads.iter_mut() { for (h, t) in threads_lck.iter_mut() {
if *h == mailbox_hash { if *h == mailbox_hash {
continue; continue;
} }
@ -178,7 +205,7 @@ impl Collection {
mailbox_hash: MailboxHash, mailbox_hash: MailboxHash,
sent_mailbox: Option<MailboxHash>, sent_mailbox: Option<MailboxHash>,
) -> Option<SmallVec<[MailboxHash; 8]>> { ) -> Option<SmallVec<[MailboxHash; 8]>> {
self.sent_mailbox = sent_mailbox; *self.sent_mailbox.write().unwrap() = sent_mailbox;
let &mut Collection { let &mut Collection {
ref mut threads, ref mut threads,
@ -188,17 +215,19 @@ impl Collection {
.. ..
} = self; } = self;
if !threads.contains_key(&mailbox_hash) { let mut threads_lck = threads.write().unwrap();
threads.insert(mailbox_hash, Threads::new(new_envelopes.len())); let mut mailboxes_lck = mailboxes.write().unwrap();
mailboxes.insert(mailbox_hash, new_envelopes.keys().cloned().collect()); if !threads_lck.contains_key(&mailbox_hash) {
threads_lck.insert(mailbox_hash, Threads::new(new_envelopes.len()));
mailboxes_lck.insert(mailbox_hash, new_envelopes.keys().cloned().collect());
for (h, e) in new_envelopes { for (h, e) in new_envelopes {
envelopes.write().unwrap().insert(h, e); envelopes.write().unwrap().insert(h, e);
} }
} else { } else {
mailboxes.entry(mailbox_hash).and_modify(|m| { mailboxes_lck.entry(mailbox_hash).and_modify(|m| {
m.extend(new_envelopes.keys().cloned()); m.extend(new_envelopes.keys().cloned());
}); });
threads.entry(mailbox_hash).and_modify(|t| { threads_lck.entry(mailbox_hash).and_modify(|t| {
let mut ordered_hash_set = let mut ordered_hash_set =
new_envelopes.keys().cloned().collect::<Vec<EnvelopeHash>>(); new_envelopes.keys().cloned().collect::<Vec<EnvelopeHash>>();
ordered_hash_set.sort_by(|a, b| { ordered_hash_set.sort_by(|a, b| {
@ -218,14 +247,19 @@ impl Collection {
} }
let mut ret = SmallVec::new(); let mut ret = SmallVec::new();
let keys = threads.keys().cloned().collect::<Vec<MailboxHash>>(); let keys = threads_lck.keys().cloned().collect::<Vec<MailboxHash>>();
for t_fh in keys { for t_fh in keys {
if t_fh == mailbox_hash { if t_fh == mailbox_hash {
continue; continue;
} }
if sent_mailbox.map(|f| f == mailbox_hash).unwrap_or(false) { if sent_mailbox
.read()
.unwrap()
.map(|f| f == mailbox_hash)
.unwrap_or(false)
{
let envelopes_lck = envelopes.read().unwrap(); let envelopes_lck = envelopes.read().unwrap();
let mut ordered_hash_set = threads[&mailbox_hash] let mut ordered_hash_set = threads_lck[&mailbox_hash]
.hash_set .hash_set
.iter() .iter()
.cloned() .cloned()
@ -239,16 +273,24 @@ impl Collection {
drop(envelopes_lck); drop(envelopes_lck);
let mut updated = false; let mut updated = false;
for h in ordered_hash_set { for h in ordered_hash_set {
updated |= threads.entry(t_fh).or_default().insert_reply(envelopes, h); updated |= threads_lck
.entry(t_fh)
.or_default()
.insert_reply(envelopes, h);
} }
if updated { if updated {
ret.push(t_fh); ret.push(t_fh);
} }
continue; continue;
} }
if sent_mailbox.map(|f| f == t_fh).unwrap_or(false) { if sent_mailbox
.read()
.unwrap()
.map(|f| f == t_fh)
.unwrap_or(false)
{
let envelopes_lck = envelopes.read().unwrap(); let envelopes_lck = envelopes.read().unwrap();
let mut ordered_hash_set = threads[&t_fh] let mut ordered_hash_set = threads_lck[&t_fh]
.hash_set .hash_set
.iter() .iter()
.cloned() .cloned()
@ -262,7 +304,7 @@ impl Collection {
drop(envelopes_lck); drop(envelopes_lck);
let mut updated = false; let mut updated = false;
for h in ordered_hash_set { for h in ordered_hash_set {
updated |= threads updated |= threads_lck
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert_reply(envelopes, h); .insert_reply(envelopes, h);
@ -288,24 +330,30 @@ impl Collection {
let old_env = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); let old_env = self.envelopes.write().unwrap().remove(&old_hash).unwrap();
envelope.set_thread(old_env.thread()); envelope.set_thread(old_env.thread());
let new_hash = envelope.hash(); let new_hash = envelope.hash();
self.mailboxes.entry(mailbox_hash).and_modify(|m| { self.mailboxes
m.remove(&old_hash); .write()
m.insert(new_hash); .unwrap()
}); .entry(mailbox_hash)
.and_modify(|m| {
m.remove(&old_hash);
m.insert(new_hash);
});
self.envelopes.write().unwrap().insert(new_hash, envelope); self.envelopes.write().unwrap().insert(new_hash, envelope);
let mut threads_lck = self.threads.write().unwrap();
if self if self
.sent_mailbox .sent_mailbox
.read()
.unwrap()
.map(|f| f == mailbox_hash) .map(|f| f == mailbox_hash)
.unwrap_or(false) .unwrap_or(false)
{ {
for (_, t) in self.threads.iter_mut() { for (_, t) in threads_lck.iter_mut() {
t.update_envelope(&self.envelopes, old_hash, new_hash) t.update_envelope(&self.envelopes, old_hash, new_hash)
.unwrap_or(()); .unwrap_or(());
} }
} }
{ {
if self if threads_lck
.threads
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.update_envelope(&self.envelopes, old_hash, new_hash) .update_envelope(&self.envelopes, old_hash, new_hash)
@ -315,11 +363,11 @@ impl Collection {
} }
} }
/* envelope is not in threads, so insert it */ /* envelope is not in threads, so insert it */
self.threads threads_lck
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert(&mut self.envelopes, new_hash); .insert(&mut self.envelopes, new_hash);
for (h, t) in self.threads.iter_mut() { for (h, t) in threads_lck.iter_mut() {
if *h == mailbox_hash { if *h == mailbox_hash {
continue; continue;
} }
@ -330,19 +378,21 @@ impl Collection {
} }
pub fn update_flags(&mut self, env_hash: EnvelopeHash, mailbox_hash: MailboxHash) { pub fn update_flags(&mut self, env_hash: EnvelopeHash, mailbox_hash: MailboxHash) {
let mut threads_lck = self.threads.write().unwrap();
if self if self
.sent_mailbox .sent_mailbox
.read()
.unwrap()
.map(|f| f == mailbox_hash) .map(|f| f == mailbox_hash)
.unwrap_or(false) .unwrap_or(false)
{ {
for (_, t) in self.threads.iter_mut() { for (_, t) in threads_lck.iter_mut() {
t.update_envelope(&self.envelopes, env_hash, env_hash) t.update_envelope(&self.envelopes, env_hash, env_hash)
.unwrap_or(()); .unwrap_or(());
} }
} }
{ {
if self if threads_lck
.threads
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.update_envelope(&self.envelopes, env_hash, env_hash) .update_envelope(&self.envelopes, env_hash, env_hash)
@ -352,11 +402,11 @@ impl Collection {
} }
} }
/* envelope is not in threads, so insert it */ /* envelope is not in threads, so insert it */
self.threads threads_lck
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert(&mut self.envelopes, env_hash); .insert(&mut self.envelopes, env_hash);
for (h, t) in self.threads.iter_mut() { for (h, t) in threads_lck.iter_mut() {
if *h == mailbox_hash { if *h == mailbox_hash {
continue; continue;
} }
@ -368,16 +418,24 @@ impl Collection {
pub fn insert(&mut self, envelope: Envelope, mailbox_hash: MailboxHash) -> bool { pub fn insert(&mut self, envelope: Envelope, mailbox_hash: MailboxHash) -> bool {
let hash = envelope.hash(); let hash = envelope.hash();
self.mailboxes.entry(mailbox_hash).and_modify(|m| { self.mailboxes
m.insert(hash); .write()
}); .unwrap()
.entry(mailbox_hash)
.and_modify(|m| {
m.insert(hash);
});
self.envelopes.write().unwrap().insert(hash, envelope); self.envelopes.write().unwrap().insert(hash, envelope);
self.threads self.threads
.write()
.unwrap()
.entry(mailbox_hash) .entry(mailbox_hash)
.or_default() .or_default()
.insert(&mut self.envelopes, hash); .insert(&mut self.envelopes, hash);
if self if self
.sent_mailbox .sent_mailbox
.read()
.unwrap()
.map(|f| f == mailbox_hash) .map(|f| f == mailbox_hash)
.unwrap_or(false) .unwrap_or(false)
{ {
@ -388,7 +446,7 @@ impl Collection {
pub fn insert_reply(&mut self, env_hash: EnvelopeHash) { pub fn insert_reply(&mut self, env_hash: EnvelopeHash) {
debug_assert!(self.envelopes.read().unwrap().contains_key(&env_hash)); debug_assert!(self.envelopes.read().unwrap().contains_key(&env_hash));
for (_, t) in self.threads.iter_mut() { for (_, t) in self.threads.write().unwrap().iter_mut() {
t.insert_reply(&mut self.envelopes, env_hash); t.insert_reply(&mut self.envelopes, env_hash);
} }
} }
@ -403,27 +461,45 @@ impl Collection {
EnvelopeRefMut { guard, env_hash } EnvelopeRefMut { guard, env_hash }
} }
pub fn get_threads(&'_ self, hash: MailboxHash) -> RwRef<'_, MailboxHash, Threads> {
let guard = self.threads.read().unwrap();
RwRef { guard, hash }
}
pub fn get_mailbox(
&'_ self,
hash: MailboxHash,
) -> RwRef<'_, MailboxHash, HashSet<EnvelopeHash>> {
let guard = self.mailboxes.read().unwrap();
RwRef { guard, hash }
}
pub fn contains_key(&self, env_hash: &EnvelopeHash) -> bool { pub fn contains_key(&self, env_hash: &EnvelopeHash) -> bool {
self.envelopes.read().unwrap().contains_key(env_hash) self.envelopes.read().unwrap().contains_key(env_hash)
} }
pub fn new_mailbox(&mut self, mailbox_hash: MailboxHash) { pub fn new_mailbox(&mut self, mailbox_hash: MailboxHash) {
if !self.mailboxes.contains_key(&mailbox_hash) { let mut mailboxes_lck = self.mailboxes.write().unwrap();
self.mailboxes.insert(mailbox_hash, Default::default()); if !mailboxes_lck.contains_key(&mailbox_hash) {
self.threads.insert(mailbox_hash, Threads::default()); mailboxes_lck.insert(mailbox_hash, Default::default());
self.threads
.write()
.unwrap()
.insert(mailbox_hash, Threads::default());
} }
} }
} }
impl Index<&MailboxHash> for Collection {
type Output = HashSet<EnvelopeHash>; pub struct RwRef<'g, K: std::cmp::Eq + std::hash::Hash, V> {
fn index(&self, index: &MailboxHash) -> &HashSet<EnvelopeHash> { guard: RwLockReadGuard<'g, HashMap<K, V>>,
&self.mailboxes[index] hash: K,
}
} }
impl IndexMut<&MailboxHash> for Collection { impl<K: std::cmp::Eq + std::hash::Hash, V> Deref for RwRef<'_, K, V> {
fn index_mut(&mut self, index: &MailboxHash) -> &mut HashSet<EnvelopeHash> { type Target = V;
self.mailboxes.get_mut(index).unwrap()
fn deref(&self) -> &V {
self.guard.get(&self.hash).unwrap()
} }
} }

View File

@ -148,9 +148,13 @@ pub trait MailListingTrait: ListingTrait {
let account = &mut context.accounts[account_pos]; let account = &mut context.accounts[account_pos];
let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new(); let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new();
let mailbox_hash = self.coordinates().1; let mailbox_hash = self.coordinates().1;
for (_, h) in account.collection.threads[&mailbox_hash].thread_group_iter(thread_hash) { for (_, h) in account
.collection
.get_threads(mailbox_hash)
.thread_group_iter(thread_hash)
{
envs_to_set.push( envs_to_set.push(
account.collection.threads[&mailbox_hash].thread_nodes()[&h] account.collection.get_threads(mailbox_hash).thread_nodes()[&h]
.message() .message()
.unwrap(), .unwrap(),
); );
@ -1209,7 +1213,7 @@ impl Component for Listing {
MailboxStatus::Available | MailboxStatus::Parsing(_, _) => format!( MailboxStatus::Available | MailboxStatus::Parsing(_, _) => format!(
"Mailbox: {}, Messages: {}, New: {}", "Mailbox: {}, Messages: {}, New: {}",
account[&mailbox_hash].ref_mailbox.name(), account[&mailbox_hash].ref_mailbox.name(),
account.collection[&mailbox_hash].len(), account.collection.get_mailbox(mailbox_hash).len(),
account[&mailbox_hash] account[&mailbox_hash]
.ref_mailbox .ref_mailbox
.count() .count()

View File

@ -247,7 +247,9 @@ impl MailListingTrait for CompactListing {
} }
} }
let threads = &context.accounts[self.cursor_pos.0].collection.threads[&self.cursor_pos.1]; let threads = context.accounts[self.cursor_pos.0]
.collection
.get_threads(self.cursor_pos.1);
let mut roots = threads.roots(); let mut roots = threads.roots();
threads.group_inner_sort_by( threads.group_inner_sort_by(
&mut roots, &mut roots,
@ -276,7 +278,7 @@ impl MailListingTrait for CompactListing {
) { ) {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
self.order.clear(); self.order.clear();
self.length = 0; self.length = 0;
let mut rows = Vec::with_capacity(1024); let mut rows = Vec::with_capacity(1024);
@ -341,7 +343,7 @@ impl MailListingTrait for CompactListing {
} }
} }
let entry_strings = self.make_entry_string(&root_envelope, context, threads, thread); let entry_strings = self.make_entry_string(&root_envelope, context, &threads, thread);
row_widths.1.push( row_widths.1.push(
entry_strings entry_strings
.date .date
@ -462,7 +464,7 @@ impl ListingTrait for CompactListing {
let thread_hash = self.get_thread_under_cursor(idx); let thread_hash = self.get_thread_under_cursor(idx);
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash); let thread = threads.thread_ref(thread_hash);
let row_attr = row_attr!( let row_attr = row_attr!(
@ -685,7 +687,7 @@ impl ListingTrait for CompactListing {
} }
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
for r in 0..cmp::min(self.length - top_idx, rows) { for r in 0..cmp::min(self.length - top_idx, rows) {
let thread_hash = self.get_thread_under_cursor(r + top_idx); let thread_hash = self.get_thread_under_cursor(r + top_idx);
let row_attr = row_attr!( let row_attr = row_attr!(
@ -767,7 +769,7 @@ impl ListingTrait for CompactListing {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
match results { match results {
Ok(results) => { Ok(results) => {
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
for env_hash in results { for env_hash in results {
if !account.collection.contains_key(&env_hash) { if !account.collection.contains_key(&env_hash) {
continue; continue;
@ -971,7 +973,7 @@ impl CompactListing {
fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) { fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash); let thread = threads.thread_ref(thread_hash);
let thread_node_hash = threads.thread_group_iter(thread_hash).next().unwrap().1; let thread_node_hash = threads.thread_group_iter(thread_hash).next().unwrap().1;
if let Some(env_hash) = threads.thread_nodes()[&thread_node_hash].message() { if let Some(env_hash) = threads.thread_nodes()[&thread_node_hash].message() {
@ -993,7 +995,7 @@ impl CompactListing {
self.color_cache.odd self.color_cache.odd
}; };
let envelope: EnvelopeRef = account.collection.get_env(env_hash); let envelope: EnvelopeRef = account.collection.get_env(env_hash);
let strings = self.make_entry_string(&envelope, context, threads, thread_hash); let strings = self.make_entry_string(&envelope, context, &threads, thread_hash);
drop(envelope); drop(envelope);
let columns = &mut self.data_columns.columns; let columns = &mut self.data_columns.columns;
let min_width = ( let min_width = (
@ -1136,7 +1138,7 @@ impl CompactListing {
); );
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
for ((idx, (thread_hash, root_env_hash)), strings) in for ((idx, (thread_hash, root_env_hash)), strings) in
self.rows.iter().skip(start).take(end - start + 1) self.rows.iter().skip(start).take(end - start + 1)
@ -1309,7 +1311,7 @@ impl CompactListing {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
match results { match results {
Ok(results) => { Ok(results) => {
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
for env_hash in results { for env_hash in results {
if !account.collection.contains_key(&env_hash) { if !account.collection.contains_key(&env_hash) {
continue; continue;
@ -1497,6 +1499,8 @@ impl Component for CompactListing {
account account
.collection .collection
.threads .threads
.write()
.unwrap()
.entry(self.cursor_pos.1) .entry(self.cursor_pos.1)
.and_modify(|threads| { .and_modify(|threads| {
let is_snoozed = threads.thread_ref(thread).snoozed(); let is_snoozed = threads.thread_ref(thread).snoozed();
@ -1526,7 +1530,7 @@ impl Component for CompactListing {
} }
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
if !account.collection.contains_key(&new_hash) { if !account.collection.contains_key(&new_hash) {
return false; return false;
} }
@ -1536,6 +1540,7 @@ impl Component for CompactListing {
} }
let thread: ThreadHash = let thread: ThreadHash =
threads.find_group(threads.thread_nodes()[&new_env_thread_node_hash].group); threads.find_group(threads.thread_nodes()[&new_env_thread_node_hash].group);
drop(threads);
if self.order.contains_key(&thread) { if self.order.contains_key(&thread) {
self.row_updates.push(thread); self.row_updates.push(thread);
} }
@ -1553,7 +1558,7 @@ impl Component for CompactListing {
} }
UIEvent::EnvelopeUpdate(ref env_hash) => { UIEvent::EnvelopeUpdate(ref env_hash) => {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
if !account.collection.contains_key(&env_hash) { if !account.collection.contains_key(&env_hash) {
return false; return false;
} }
@ -1563,6 +1568,7 @@ impl Component for CompactListing {
} }
let thread: ThreadHash = let thread: ThreadHash =
threads.find_group(threads.thread_nodes()[&new_env_thread_node_hash].group); threads.find_group(threads.thread_nodes()[&new_env_thread_node_hash].group);
drop(threads);
if self.order.contains_key(&thread) { if self.order.contains_key(&thread) {
self.row_updates.push(thread); self.row_updates.push(thread);
} }

View File

@ -152,7 +152,9 @@ impl MailListingTrait for ConversationsListing {
} }
} }
let threads = &context.accounts[self.cursor_pos.0].collection.threads[&self.cursor_pos.1]; let threads = context.accounts[self.cursor_pos.0]
.collection
.get_threads(self.cursor_pos.1);
self.all_threads.clear(); self.all_threads.clear();
let mut roots = threads.roots(); let mut roots = threads.roots();
threads.group_inner_sort_by( threads.group_inner_sort_by(
@ -183,7 +185,7 @@ impl MailListingTrait for ConversationsListing {
) { ) {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
self.order.clear(); self.order.clear();
self.selection.clear(); self.selection.clear();
self.length = 0; self.length = 0;
@ -255,8 +257,13 @@ impl MailListingTrait for ConversationsListing {
} }
} }
let strings = let strings = self.make_entry_string(
self.make_entry_string(root_envelope, context, &from_address_list, threads, thread); root_envelope,
context,
&from_address_list,
&threads,
thread,
);
max_entry_columns = std::cmp::max( max_entry_columns = std::cmp::max(
max_entry_columns, max_entry_columns,
strings.flag.len() strings.flag.len()
@ -436,7 +443,7 @@ impl ListingTrait for ConversationsListing {
let thread_hash = self.get_thread_under_cursor(idx); let thread_hash = self.get_thread_under_cursor(idx);
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash); let thread = threads.thread_ref(thread_hash);
let fg_color = if thread.unseen() > 0 { let fg_color = if thread.unseen() > 0 {
@ -717,7 +724,7 @@ impl ListingTrait for ConversationsListing {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
match results { match results {
Ok(results) => { Ok(results) => {
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
for env_hash in results { for env_hash in results {
if !account.collection.contains_key(&env_hash) { if !account.collection.contains_key(&env_hash) {
continue; continue;
@ -952,7 +959,7 @@ impl ConversationsListing {
fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) { fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash); let thread = threads.thread_ref(thread_hash);
let thread_node_hash = threads.thread_group_iter(thread_hash).next().unwrap().1; let thread_node_hash = threads.thread_group_iter(thread_hash).next().unwrap().1;
let idx: usize = self.order[&thread_hash]; let idx: usize = self.order[&thread_hash];
@ -989,8 +996,13 @@ impl ConversationsListing {
} }
} }
let envelope: EnvelopeRef = account.collection.get_env(env_hash); let envelope: EnvelopeRef = account.collection.get_env(env_hash);
let strings = let strings = self.make_entry_string(
self.make_entry_string(&envelope, context, &from_address_list, threads, thread_hash); &envelope,
context,
&from_address_list,
&threads,
thread_hash,
);
drop(envelope); drop(envelope);
/* draw flags */ /* draw flags */
let (x, _) = write_string_to_grid( let (x, _) = write_string_to_grid(
@ -1236,7 +1248,7 @@ impl Component for ConversationsListing {
} }
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
if !account.collection.contains_key(&new_hash) { if !account.collection.contains_key(&new_hash) {
return false; return false;
} }
@ -1246,6 +1258,7 @@ impl Component for ConversationsListing {
} }
let thread: ThreadHash = let thread: ThreadHash =
threads.find_group(threads.thread_nodes()[&env_thread_node_hash].group); threads.find_group(threads.thread_nodes()[&env_thread_node_hash].group);
drop(threads);
if self.order.contains_key(&thread) { if self.order.contains_key(&thread) {
self.row_updates.push(thread); self.row_updates.push(thread);
} }
@ -1257,7 +1270,7 @@ impl Component for ConversationsListing {
} }
UIEvent::EnvelopeUpdate(ref env_hash) => { UIEvent::EnvelopeUpdate(ref env_hash) => {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
if !account.collection.contains_key(&env_hash) { if !account.collection.contains_key(&env_hash) {
return false; return false;
} }
@ -1267,6 +1280,7 @@ impl Component for ConversationsListing {
} }
let thread: ThreadHash = let thread: ThreadHash =
threads.find_group(threads.thread_nodes()[&env_thread_node_hash].group); threads.find_group(threads.thread_nodes()[&env_thread_node_hash].group);
drop(threads);
if self.order.contains_key(&thread) { if self.order.contains_key(&thread) {
self.row_updates.push(thread); self.row_updates.push(thread);
} }
@ -1315,6 +1329,8 @@ impl Component for ConversationsListing {
account account
.collection .collection
.threads .threads
.write()
.unwrap()
.entry(self.cursor_pos.1) .entry(self.cursor_pos.1)
.and_modify(|threads| { .and_modify(|threads| {
let is_snoozed = threads.thread_ref(thread).snoozed(); let is_snoozed = threads.thread_ref(thread).snoozed();

View File

@ -169,7 +169,9 @@ impl MailListingTrait for PlainListing {
return; return;
} }
} }
self.local_collection = context.accounts[self.cursor_pos.0].collection[&self.cursor_pos.1] self.local_collection = context.accounts[self.cursor_pos.0]
.collection
.get_mailbox(self.cursor_pos.1)
.iter() .iter()
.cloned() .cloned()
.collect(); .collect();
@ -178,8 +180,9 @@ impl MailListingTrait for PlainListing {
.envelopes .envelopes
.read() .read()
.unwrap(); .unwrap();
self.thread_node_hashes = context.accounts[self.cursor_pos.0].collection self.thread_node_hashes = context.accounts[self.cursor_pos.0]
[&self.cursor_pos.1] .collection
.get_mailbox(self.cursor_pos.1)
.iter() .iter()
.map(|h| (*h, env_lck[h].thread())) .map(|h| (*h, env_lck[h].thread()))
.collect(); .collect();
@ -232,7 +235,7 @@ impl MailListingTrait for PlainListing {
items: Box<dyn Iterator<Item = ThreadHash>>, items: Box<dyn Iterator<Item = ThreadHash>>,
) { ) {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
let roots = items let roots = items
.filter_map(|r| threads.groups[&r].root().map(|r| r.root)) .filter_map(|r| threads.groups[&r].root().map(|r| r.root))
.collect::<_>(); .collect::<_>();
@ -1218,7 +1221,10 @@ impl Component for PlainListing {
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
if !account.collection.contains_key(new_hash) if !account.collection.contains_key(new_hash)
|| !account.collection[&self.cursor_pos.1].contains(new_hash) || !account
.collection
.get_mailbox(self.cursor_pos.1)
.contains(new_hash)
{ {
return false; return false;
} }
@ -1244,7 +1250,10 @@ impl Component for PlainListing {
UIEvent::EnvelopeUpdate(ref env_hash) => { UIEvent::EnvelopeUpdate(ref env_hash) => {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
if !account.collection.contains_key(env_hash) if !account.collection.contains_key(env_hash)
|| !account.collection[&self.cursor_pos.1].contains(env_hash) || !account
.collection
.get_mailbox(self.cursor_pos.1)
.contains(env_hash)
{ {
return false; return false;
} }

View File

@ -121,7 +121,9 @@ impl MailListingTrait for ThreadListing {
return; return;
} }
} }
let threads = &context.accounts[self.cursor_pos.0].collection.threads[&self.cursor_pos.1]; let threads = context.accounts[self.cursor_pos.0]
.collection
.get_threads(self.cursor_pos.1);
let mut roots = threads.roots(); let mut roots = threads.roots();
threads.group_inner_sort_by( threads.group_inner_sort_by(
&mut roots, &mut roots,
@ -141,7 +143,7 @@ impl MailListingTrait for ThreadListing {
items: Box<dyn Iterator<Item = ThreadHash>>, items: Box<dyn Iterator<Item = ThreadHash>>,
) { ) {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1]; let threads = account.collection.get_threads(self.cursor_pos.1);
self.length = 0; self.length = 0;
self.order.clear(); self.order.clear();
let default_cell = { let default_cell = {
@ -226,7 +228,7 @@ impl MailListingTrait for ThreadListing {
idx, idx,
indentation, indentation,
thread_node_hash, thread_node_hash,
threads, &threads,
&indentations, &indentations,
has_sibling, has_sibling,
is_root, is_root,
@ -1164,7 +1166,6 @@ impl Component for ThreadListing {
} }
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1];
if !account.collection.contains_key(&new_hash) { if !account.collection.contains_key(&new_hash) {
return false; return false;
} }
@ -1188,7 +1189,6 @@ impl Component for ThreadListing {
} }
UIEvent::EnvelopeUpdate(ref env_hash) => { UIEvent::EnvelopeUpdate(ref env_hash) => {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[self.cursor_pos.0];
let threads = &account.collection.threads[&self.cursor_pos.1];
if !account.collection.contains_key(env_hash) { if !account.collection.contains_key(env_hash) {
return false; return false;
} }

View File

@ -161,7 +161,7 @@ impl ThreadView {
fn initiate(&mut self, expanded_hash: Option<ThreadNodeHash>, context: &Context) { fn initiate(&mut self, expanded_hash: Option<ThreadNodeHash>, context: &Context) {
let account = &context.accounts[self.coordinates.0]; let account = &context.accounts[self.coordinates.0];
let threads = &account.collection.threads[&self.coordinates.1]; let threads = account.collection.get_threads(self.coordinates.1);
if !threads.groups.contains_key(&self.thread_group) { if !threads.groups.contains_key(&self.thread_group) {
return; return;
@ -648,7 +648,7 @@ impl ThreadView {
let y = if self.dirty { let y = if self.dirty {
clear_area(grid, area, crate::conf::value(context, "theme_default")); clear_area(grid, area, crate::conf::value(context, "theme_default"));
let account = &context.accounts[self.coordinates.0]; let account = &context.accounts[self.coordinates.0];
let threads = &account.collection.threads[&self.coordinates.1]; let threads = account.collection.get_threads(self.coordinates.1);
let thread_root = threads let thread_root = threads
.thread_group_iter(self.thread_group) .thread_group_iter(self.thread_group)
.next() .next()
@ -751,7 +751,7 @@ impl ThreadView {
let y = { let y = {
clear_area(grid, area, crate::conf::value(context, "theme_default")); clear_area(grid, area, crate::conf::value(context, "theme_default"));
let account = &context.accounts[self.coordinates.0]; let account = &context.accounts[self.coordinates.0];
let threads = &account.collection.threads[&self.coordinates.1]; let threads = account.collection.get_threads(self.coordinates.1);
let thread_root = threads let thread_root = threads
.thread_group_iter(self.thread_group) .thread_group_iter(self.thread_group)
.next() .next()

View File

@ -726,7 +726,10 @@ impl Account {
RefreshEventKind::Create(envelope) => { RefreshEventKind::Create(envelope) => {
let env_hash = envelope.hash(); let env_hash = envelope.hash();
if self.collection.contains_key(&env_hash) if self.collection.contains_key(&env_hash)
&& self.collection[&mailbox_hash].contains(&env_hash) && self
.collection
.get_mailbox(mailbox_hash)
.contains(&env_hash)
{ {
return None; return None;
} }
@ -770,10 +773,13 @@ impl Account {
let thread = { let thread = {
let thread_hash = self.collection.get_env(env_hash).thread(); let thread_hash = self.collection.get_env(env_hash).thread();
self.collection.threads[&mailbox_hash] self.collection.get_threads(mailbox_hash).find_group(
.find_group(self.collection.threads[&mailbox_hash][&thread_hash].group) self.collection.get_threads(mailbox_hash)[&thread_hash].group,
)
}; };
if self.collection.threads[&mailbox_hash] if self
.collection
.get_threads(mailbox_hash)
.thread_ref(thread) .thread_ref(thread)
.snoozed() .snoozed()
{ {
@ -797,8 +803,9 @@ impl Account {
RefreshEventKind::Remove(env_hash) => { RefreshEventKind::Remove(env_hash) => {
let thread_hash = { let thread_hash = {
let thread_hash = self.collection.get_env(env_hash).thread(); let thread_hash = self.collection.get_env(env_hash).thread();
self.collection.threads[&mailbox_hash] self.collection.get_threads(mailbox_hash).find_group(
.find_group(self.collection.threads[&mailbox_hash][&thread_hash].group) self.collection.get_threads(mailbox_hash)[&thread_hash].group,
)
}; };
#[cfg(feature = "sqlite3")] #[cfg(feature = "sqlite3")]
{ {
@ -1006,7 +1013,12 @@ impl Account {
None => { None => {
return match self.mailbox_entries[&mailbox_hash].status { return match self.mailbox_entries[&mailbox_hash].status {
MailboxStatus::Available | MailboxStatus::Parsing(_, _) MailboxStatus::Available | MailboxStatus::Parsing(_, _)
if self.collection.mailboxes.contains_key(&mailbox_hash) => if self
.collection
.mailboxes
.read()
.unwrap()
.contains_key(&mailbox_hash) =>
{ {
Ok(()) Ok(())
} }
@ -1157,7 +1169,12 @@ impl Account {
} }
if self.mailbox_entries[&mailbox_hash].status.is_available() if self.mailbox_entries[&mailbox_hash].status.is_available()
|| (self.mailbox_entries[&mailbox_hash].status.is_parsing() || (self.mailbox_entries[&mailbox_hash].status.is_parsing()
&& self.collection.mailboxes.contains_key(&mailbox_hash)) && self
.collection
.mailboxes
.read()
.unwrap()
.contains_key(&mailbox_hash))
{ {
Ok(()) Ok(())
} else { } else {
@ -1346,10 +1363,6 @@ impl Account {
}) })
} }
pub fn thread(&self, h: ThreadNodeHash, f: MailboxHash) -> &ThreadNode {
&self.collection.threads[&f].thread_nodes()[&h]
}
pub fn mailbox_operation( pub fn mailbox_operation(
&mut self, &mut self,
op: crate::execute::actions::MailboxOperation, op: crate::execute::actions::MailboxOperation,
@ -1417,9 +1430,13 @@ impl Account {
); );
self.collection self.collection
.threads .threads
.write()
.unwrap()
.insert(mailbox_hash, Threads::default()); .insert(mailbox_hash, Threads::default());
self.collection self.collection
.mailboxes .mailboxes
.write()
.unwrap()
.insert(mailbox_hash, Default::default()); .insert(mailbox_hash, Default::default());
build_mailboxes_order( build_mailboxes_order(
&mut self.tree, &mut self.tree,
@ -1451,7 +1468,11 @@ impl Account {
if self.sent_mailbox == Some(mailbox_hash) { if self.sent_mailbox == Some(mailbox_hash) {
self.sent_mailbox = None; self.sent_mailbox = None;
} }
self.collection.threads.remove(&mailbox_hash); self.collection
.threads
.write()
.unwrap()
.remove(&mailbox_hash);
let deleted_mailbox = self.mailbox_entries.remove(&mailbox_hash).unwrap(); let deleted_mailbox = self.mailbox_entries.remove(&mailbox_hash).unwrap();
/* if deleted mailbox had parent, we need to update its children field */ /* if deleted mailbox had parent, we need to update its children field */
if let Some(parent_hash) = deleted_mailbox.ref_mailbox.parent() { if let Some(parent_hash) = deleted_mailbox.ref_mailbox.parent() {
@ -1461,7 +1482,11 @@ impl Account {
parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap(); parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap();
}); });
} }
self.collection.mailboxes.remove(&mailbox_hash); self.collection
.mailboxes
.write()
.unwrap()
.remove(&mailbox_hash);
build_mailboxes_order( build_mailboxes_order(
&mut self.tree, &mut self.tree,
&self.mailbox_entries, &self.mailbox_entries,
@ -1576,7 +1601,7 @@ impl Account {
let mut ret = SmallVec::new(); let mut ret = SmallVec::new();
let envelopes = self.collection.envelopes.read().unwrap(); let envelopes = self.collection.envelopes.read().unwrap();
for &env_hash in self.collection[&mailbox_hash].iter() { for &env_hash in self.collection.get_mailbox(mailbox_hash).iter() {
let envelope = &envelopes[&env_hash]; let envelope = &envelopes[&env_hash];
if envelope.subject().contains(&search_term) { if envelope.subject().contains(&search_term) {
ret.push(env_hash); ret.push(env_hash);