Browse Source

melib/imap: put imap folders in RwLock instead of Mutex

This should prevent lockups if the IMAP conn thread gets blocked
jmap
Manos Pitsidianakis 2 years ago
parent
commit
b2cd4f4b7a
Signed by: epilys GPG Key ID: 73627C2F690DF710
  1. 31
      melib/src/backends/imap.rs
  2. 10
      melib/src/backends/imap/watch.rs

31
melib/src/backends/imap.rs

@ -44,7 +44,7 @@ use fnv::{FnvHashMap, FnvHashSet};
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, RwLock};
pub type UID = usize;
pub static SUPPORTED_CAPABILITIES: &'static [&'static str] = &["IDLE"];
@ -100,7 +100,7 @@ pub struct ImapType {
server_conf: ImapServerConf,
uid_store: Arc<UIDStore>,
folders: Arc<Mutex<FnvHashMap<FolderHash, ImapFolder>>>,
folders: Arc<RwLock<FnvHashMap<FolderHash, ImapFolder>>>,
}
impl MailBackend for ImapType {
@ -125,7 +125,7 @@ impl MailBackend for ImapType {
let folder_path = folder.path().to_string();
let folder_hash = folder.hash();
let (permissions, folder_exists) = {
let f = &self.folders.lock().unwrap()[&folder_hash];
let f = &self.folders.read().unwrap()[&folder_hash];
(f.permissions.clone(), f.exists.clone())
};
let connection = self.connection.clone();
@ -270,13 +270,16 @@ impl MailBackend for ImapType {
}
fn folders(&self) -> FnvHashMap<FolderHash, Folder> {
let mut folders = self.folders.lock().unwrap();
if !folders.is_empty() {
return folders
.iter()
.map(|(h, f)| (*h, Box::new(Clone::clone(f)) as Folder))
.collect();
{
let folders = self.folders.read().unwrap();
if !folders.is_empty() {
return folders
.iter()
.map(|(h, f)| (*h, Box::new(Clone::clone(f)) as Folder))
.collect();
}
}
let mut folders = self.folders.write().unwrap();
*folders = ImapType::imap_folders(&self.connection);
folders.retain(|_, f| (self.is_subscribed)(f.path()));
let keys = folders.keys().cloned().collect::<FnvHashSet<FolderHash>>();
@ -294,7 +297,7 @@ impl MailBackend for ImapType {
let (uid, folder_hash) = self.uid_store.hash_index.lock().unwrap()[&hash];
Box::new(ImapOp::new(
uid,
self.folders.lock().unwrap()[&folder_hash]
self.folders.read().unwrap()[&folder_hash]
.path()
.to_string(),
self.connection.clone(),
@ -304,7 +307,7 @@ impl MailBackend for ImapType {
fn save(&self, bytes: &[u8], folder: &str, flags: Option<Flag>) -> Result<()> {
let path = {
let folders = self.folders.lock().unwrap();
let folders = self.folders.read().unwrap();
let f_result = folders.values().find(|v| v.name == folder);
if f_result
@ -349,7 +352,7 @@ impl MailBackend for ImapType {
match (
&op,
self.folders
.lock()
.read()
.unwrap()
.values()
.any(|f| f.path == path),
@ -472,7 +475,7 @@ impl ImapType {
server_conf,
is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)),
folders: Arc::new(Mutex::new(Default::default())),
folders: Arc::new(RwLock::new(Default::default())),
connection: Arc::new(Mutex::new(connection)),
uid_store: Arc::new(UIDStore {
uidvalidity: Default::default(),
@ -575,7 +578,7 @@ impl ImapType {
query: String,
folder_hash: FolderHash,
) -> Result<crate::structs::StackVec<EnvelopeHash>> {
let folders_lck = self.folders.lock()?;
let folders_lck = self.folders.read()?;
let mut response = String::with_capacity(8 * 1024);
let mut conn = self.connection.lock()?;
conn.send_command(format!("EXAMINE {}", folders_lck[&folder_hash].path()).as_bytes())?;

10
melib/src/backends/imap/watch.rs

@ -19,7 +19,7 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use super::*;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, RwLock};
/// Arguments for IMAP watching functions
pub struct ImapWatchKit {
@ -27,7 +27,7 @@ pub struct ImapWatchKit {
pub is_online: Arc<Mutex<bool>>,
pub main_conn: Arc<Mutex<ImapConnection>>,
pub uid_store: Arc<UIDStore>,
pub folders: Arc<Mutex<FnvHashMap<FolderHash, ImapFolder>>>,
pub folders: Arc<RwLock<FnvHashMap<FolderHash, ImapFolder>>>,
pub sender: RefreshEventConsumer,
pub work_context: WorkContext,
}
@ -71,7 +71,7 @@ pub fn poll_with_examine(kit: ImapWatchKit) -> Result<()> {
.send((thread_id, "sleeping...".to_string()))
.unwrap();
std::thread::sleep(std::time::Duration::from_millis(5 * 60 * 1000));
let folders = folders.lock().unwrap();
let folders = folders.read().unwrap();
for folder in folders.values() {
work_context
.set_status
@ -109,7 +109,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
}
let thread_id: std::thread::ThreadId = std::thread::current().id();
let folder: ImapFolder = folders
.lock()
.read()
.unwrap()
.values()
.find(|f| f.parent.is_none() && f.path().eq_ignore_ascii_case("INBOX"))
@ -207,7 +207,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
if now.duration_since(watch) >= _5_mins {
/* Time to poll all inboxes */
let mut conn = main_conn.lock().unwrap();
for folder in folders.lock().unwrap().values() {
for folder in folders.read().unwrap().values() {
work_context
.set_status
.send((

Loading…
Cancel
Save