Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Look up message in notmuch instead of using heavy query #46

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ toml = "0.5.9"
trust-dns-resolver = "0.21.2"
ureq = { version = "2.4.0", features = ["json"] }
uritemplate-next = "0.2.0"
file-matcher = "0.7.0"
26 changes: 26 additions & 0 deletions src/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use std::io;
use std::path::Path;
use std::path::PathBuf;
use std::path::StripPrefixError;
use file_matcher::FileNamed;

const ID_PATTERN: &'static str = r"[-A-Za-z0-9_]+";
const MAIL_PATTERN: &'static str = formatcp!(r"^({})\.({})(?:$|:)", ID_PATTERN, ID_PATTERN);
Expand Down Expand Up @@ -157,6 +158,31 @@ impl Local {
self.query(&self.all_mail_query)
}

/// Return a boolean of whether this message exists or not
/// We can't look up using msg-id since we have the internal id here
/// so we look to see if a file exists where we expect it to and then
/// confirm the path in the notmuch database

/// @TODO: This could just return the message if I could figure out
/// how to do that properly
pub fn email_exists_from_id(&self, id: &jmap::Id) -> bool {
let f = FileNamed::wildmatch(format!("{}*", id))
.within(&self.mail_cur_dir)
.find();

if let Ok(f) = &f {
let msg = self.db.find_message_by_filename(&f);
if let Ok(Some(msg)) = msg {
debug!("message: {:?}", self.emails_from_message(msg));
return true;
} else {
return false;
}
} else {
return false;
}
}

/// Return all `Email`s that mujmap owns which were modified since the given database revision.
pub fn all_emails_since(&self, last_revision: u64) -> Result<HashMap<jmap::Id, Email>> {
self.query(&format!(
Expand Down
25 changes: 15 additions & 10 deletions src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,14 +240,13 @@ pub fn sync(
.context(IndexMailboxesSnafu {})?;
debug!("Got mailboxes: {:?}", mailboxes);

// Query local database for all email.
let local_emails = local.all_emails().context(IndexLocalEmailsSnafu {})?;

// Function which performs a full sync, i.e. a sync which considers all remote IDs as updated,
// and determines destroyed IDs by finding the difference of all remote IDs from all local IDs.
let full_sync =
|remote: &mut Remote| -> Result<(jmap::State, HashSet<jmap::Id>, HashSet<jmap::Id>)> {
let (state, updated_ids) = remote.all_email_ids().context(IndexRemoteEmailsSnafu {})?;
// Query local database for all email.
let local_emails = local.all_emails().context(IndexLocalEmailsSnafu {})?;
// TODO can we optimize these two lines?
let local_ids: HashSet<jmap::Id> =
local_emails.iter().map(|(id, _)| id).cloned().collect();
Expand All @@ -265,7 +264,9 @@ pub fn sync(
debug!("Remote changes: state={state}, created={created:?}, updated={updated:?}, destroyed={destroyed:?}");
// If we have something in the updated set that isn't in the local database,
// something must have gone wrong somewhere. Do a full sync instead.
if !updated.iter().all(|x| local_emails.contains_key(x)) {
if !updated.iter()
.inspect(|x| debug!("remote_email: {:?}", x))
.all(|x| local.email_exists_from_id(x)) {
warn!(
"Server sent an update which references an ID we don't know about, doing a full sync instead");
full_sync(&mut remote)
Expand Down Expand Up @@ -299,10 +300,8 @@ pub fn sync(
// Before merging, download the new files into the cache.
let mut new_emails: HashMap<jmap::Id, NewEmail> = remote_emails
.values()
.filter(|remote_email| match local_emails.get(&remote_email.id) {
Some(local_email) => local_email.blob_id != remote_email.blob_id,
None => true,
})
.inspect(|x| debug!("get_emails : {:?}", local.email_exists_from_id(&x.id)))
.filter(|remote_email| !local.email_exists_from_id(&remote_email.id))
.map(|remote_email| {
(
remote_email.id.clone(),
Expand All @@ -317,7 +316,7 @@ pub fn sync(

let new_emails_missing_from_cache: Vec<&NewEmail> = new_emails
.values()
.filter(|x| !x.cache_path.exists() && !local_emails.contains_key(&x.remote_email.id))
.filter(|x| !x.cache_path.exists() && !local.email_exists_from_id(&x.remote_email.id))
.collect();

if !new_emails_missing_from_cache.is_empty() {
Expand Down Expand Up @@ -376,7 +375,7 @@ pub fn sync(
//
// 5. Overwrite the symlinks we made earlier with the actual files from the cache.
let notmuch_revision = get_notmuch_revision(
local_emails.is_empty(),
false, // local_emails.is_empty(),
&local,
latest_state.notmuch_revision,
args.dry_run,
Expand Down Expand Up @@ -407,11 +406,17 @@ pub fn sync(
if !args.dry_run {
// Collect the local messages which will be destroyed. We will add to this list any
// messages with new blob IDs.
// this query might not even need to run if there are 0 changes
debug!("line 415");
let local_emails = local.all_emails().context(IndexLocalEmailsSnafu {})?;
let mut destroyed_local_emails: Vec<&local::Email> = destroyed_ids
.into_iter()
.inspect(|y| debug!("{:?}", &y))
.flat_map(|x| local_emails.get(&x))
.collect();

debug!("{:?}", destroyed_local_emails);

// Symlink the new mail files into the maildir...
for new_email in new_emails.values() {
debug!(
Expand Down