fix some logic error in the internals

This commit is contained in:
Quentin 2024-01-10 12:55:38 +01:00
parent a2d6efc962
commit 51510c97f7
Signed by: quentin
GPG key ID: E9602264D639FF68
4 changed files with 34 additions and 23 deletions

View file

@ -507,7 +507,7 @@ impl<'a> AuthenticatedContext<'a> {
) -> Result<(Response<'static>, flow::Transition)> { ) -> Result<(Response<'static>, flow::Transition)> {
let append_tag = self.req.tag.clone(); let append_tag = self.req.tag.clone();
match self.append_internal(mailbox, flags, date, message).await { match self.append_internal(mailbox, flags, date, message).await {
Ok((_mb, uidvalidity, uid)) => Ok(( Ok((_mb, uidvalidity, uid, _modseq)) => Ok((
Response::build() Response::build()
.tag(append_tag) .tag(append_tag)
.message("APPEND completed") .message("APPEND completed")
@ -548,7 +548,7 @@ impl<'a> AuthenticatedContext<'a> {
flags: &[Flag<'a>], flags: &[Flag<'a>],
date: &Option<DateTime>, date: &Option<DateTime>,
message: &Literal<'a>, message: &Literal<'a>,
) -> Result<(Arc<Mailbox>, ImapUidvalidity, ImapUidvalidity)> { ) -> Result<(Arc<Mailbox>, ImapUidvalidity, ImapUid, ModSeq)> {
let name: &str = MailboxName(mailbox).try_into()?; let name: &str = MailboxName(mailbox).try_into()?;
let mb_opt = self.user.open_mailbox(&name).await?; let mb_opt = self.user.open_mailbox(&name).await?;
@ -566,9 +566,9 @@ impl<'a> AuthenticatedContext<'a> {
let flags = flags.iter().map(|x| x.to_string()).collect::<Vec<_>>(); let flags = flags.iter().map(|x| x.to_string()).collect::<Vec<_>>();
// TODO: filter allowed flags? ping @Quentin // TODO: filter allowed flags? ping @Quentin
let (uidvalidity, uid) = mb.append(msg, None, &flags[..]).await?; let (uidvalidity, uid, modseq) = mb.append(msg, None, &flags[..]).await?;
Ok((mb, uidvalidity, uid)) Ok((mb, uidvalidity, uid, modseq))
} }
} }

View file

@ -21,7 +21,7 @@ impl<'a> Index<'a> {
.table .table
.get(&uuid) .get(&uuid)
.ok_or(anyhow!("mail is missing from index"))? .ok_or(anyhow!("mail is missing from index"))?
.1 .2
.as_ref(); .as_ref();
let i_int: u32 = (i_enum + 1).try_into()?; let i_int: u32 = (i_enum + 1).try_into()?;
let i: NonZeroU32 = i_int.try_into()?; let i: NonZeroU32 = i_int.try_into()?;

View file

@ -108,7 +108,7 @@ impl MailboxView {
let old_mail = old_snapshot.table.get(uuid); let old_mail = old_snapshot.table.get(uuid);
let new_mail = new_snapshot.table.get(uuid); let new_mail = new_snapshot.table.get(uuid);
if old_mail.is_some() && old_mail != new_mail { if old_mail.is_some() && old_mail != new_mail {
if let Some((uid, flags)) = new_mail { if let Some((uid, _modseq, flags)) = new_mail {
data.push(Body::Data(Data::Fetch { data.push(Body::Data(Data::Fetch {
seq: NonZeroU32::try_from((i + 1) as u32).unwrap(), seq: NonZeroU32::try_from((i + 1) as u32).unwrap(),
items: vec![ items: vec![
@ -185,7 +185,7 @@ impl MailboxView {
let msgs = state let msgs = state
.table .table
.iter() .iter()
.filter(|(_uuid, (_uid, flags))| flags.iter().any(|x| *x == deleted_flag)) .filter(|(_uuid, (_uid, _modseq, flags))| flags.iter().any(|x| *x == deleted_flag))
.map(|(uuid, _)| *uuid); .map(|(uuid, _)| *uuid);
for msg in msgs { for msg in msgs {
@ -438,7 +438,7 @@ impl MailboxView {
.table .table
.values() .values()
.enumerate() .enumerate()
.find(|(_i, (_imap_uid, flags))| !flags.contains(&"\\Seen".to_string())) .find(|(_i, (_imap_uid, _modseq, flags))| !flags.contains(&"\\Seen".to_string()))
.map(|(i, _)| NonZeroU32::try_from(i as u32 + 1)) .map(|(i, _)| NonZeroU32::try_from(i as u32 + 1))
.transpose()?) .transpose()?)
} }

View file

@ -136,7 +136,7 @@ impl BayouState for UidIndex {
// Change UIDValidity if there is a UID conflict or a MODSEQ conflict // Change UIDValidity if there is a UID conflict or a MODSEQ conflict
// @FIXME Need to prove that summing work // @FIXME Need to prove that summing work
// The intuition: we increase the UIDValidity by the number of possible conflicts // The intuition: we increase the UIDValidity by the number of possible conflicts
if *uid < new.internalseq || *modseq < new.highestmodseq { if *uid < new.internalseq || *modseq < new.internalmodseq {
let bump_uid = new.internalseq.get() - uid.get(); let bump_uid = new.internalseq.get() - uid.get();
let bump_modseq = new.internalmodseq.get() - modseq.get(); let bump_modseq = new.internalmodseq.get() - modseq.get();
new.uidvalidity = new.uidvalidity =
@ -148,7 +148,7 @@ impl BayouState for UidIndex {
let new_uid = new.internalseq; let new_uid = new.internalseq;
// Assign the real modseq of the email and its new flags // Assign the real modseq of the email and its new flags
let new_modseq = new.highestmodseq; let new_modseq = new.internalmodseq;
// Delete the previous entry if any. // Delete the previous entry if any.
// Our proof has no assumption on `ident` uniqueness, // Our proof has no assumption on `ident` uniqueness,
@ -175,11 +175,11 @@ impl BayouState for UidIndex {
// We update the counter // We update the counter
new.internalseq = NonZeroU32::new(new.internalseq.get() + 1).unwrap(); new.internalseq = NonZeroU32::new(new.internalseq.get() + 1).unwrap();
} }
UidIndexOp::FlagAdd(ident, modseq, new_flags) => { UidIndexOp::FlagAdd(ident, candidate_modseq, new_flags) => {
if let Some((uid, modseq, existing_flags)) = new.table.get_mut(ident) { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) {
// Bump UIDValidity if required // Bump UIDValidity if required
if *modseq < new.highestmodseq { if *candidate_modseq < new.internalmodseq {
let bump_modseq = new.internalmodseq.get() - modseq.get(); let bump_modseq = new.internalmodseq.get() - candidate_modseq.get();
new.uidvalidity = new.uidvalidity =
NonZeroU32::new(new.uidvalidity.get() + bump_modseq) NonZeroU32::new(new.uidvalidity.get() + bump_modseq)
.unwrap(); .unwrap();
@ -192,7 +192,8 @@ impl BayouState for UidIndex {
.cloned() .cloned()
.collect(); .collect();
new.idx_by_flag.insert(*uid, &to_add); new.idx_by_flag.insert(*uid, &to_add);
new.idx_by_modseq.insert(*modseq, *ident); *email_modseq = new.internalmodseq;
new.idx_by_modseq.insert(new.internalmodseq, *ident);
existing_flags.append(&mut to_add); existing_flags.append(&mut to_add);
// Update counters // Update counters
@ -200,11 +201,11 @@ impl BayouState for UidIndex {
new.internalmodseq = NonZeroU32::new(new.internalmodseq.get() + 1).unwrap(); new.internalmodseq = NonZeroU32::new(new.internalmodseq.get() + 1).unwrap();
} }
} }
UidIndexOp::FlagDel(ident, modseq, rm_flags) => { UidIndexOp::FlagDel(ident, candidate_modseq, rm_flags) => {
if let Some((uid, modseq, existing_flags)) = new.table.get_mut(ident) { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) {
// Bump UIDValidity if required // Bump UIDValidity if required
if *modseq < new.highestmodseq { if *candidate_modseq < new.internalmodseq {
let bump_modseq = new.internalmodseq.get() - modseq.get(); let bump_modseq = new.internalmodseq.get() - candidate_modseq.get();
new.uidvalidity = new.uidvalidity =
NonZeroU32::new(new.uidvalidity.get() + bump_modseq) NonZeroU32::new(new.uidvalidity.get() + bump_modseq)
.unwrap(); .unwrap();
@ -215,15 +216,24 @@ impl BayouState for UidIndex {
new.idx_by_flag.remove(*uid, rm_flags); new.idx_by_flag.remove(*uid, rm_flags);
// Register that email has been modified // Register that email has been modified
new.idx_by_modseq.insert(*modseq, *ident); new.idx_by_modseq.insert(new.internalmodseq, *ident);
*email_modseq = new.internalmodseq;
// Update counters // Update counters
new.highestmodseq = new.internalmodseq; new.highestmodseq = new.internalmodseq;
new.internalmodseq = NonZeroU32::new(new.internalmodseq.get() + 1).unwrap(); new.internalmodseq = NonZeroU32::new(new.internalmodseq.get() + 1).unwrap();
} }
} }
UidIndexOp::FlagSet(ident, modseq, new_flags) => { UidIndexOp::FlagSet(ident, candidate_modseq, new_flags) => {
if let Some((uid, modseq, existing_flags)) = new.table.get_mut(ident) { if let Some((uid, email_modseq, existing_flags)) = new.table.get_mut(ident) {
// Bump UIDValidity if required
if *candidate_modseq < new.internalmodseq {
let bump_modseq = new.internalmodseq.get() - candidate_modseq.get();
new.uidvalidity =
NonZeroU32::new(new.uidvalidity.get() + bump_modseq)
.unwrap();
}
// Remove flags from the source of trust and the cache // Remove flags from the source of trust and the cache
let (keep_flags, rm_flags): (Vec<String>, Vec<String>) = existing_flags let (keep_flags, rm_flags): (Vec<String>, Vec<String>) = existing_flags
.iter() .iter()
@ -240,7 +250,8 @@ impl BayouState for UidIndex {
new.idx_by_flag.insert(*uid, &to_add); new.idx_by_flag.insert(*uid, &to_add);
// Register that email has been modified // Register that email has been modified
new.idx_by_modseq.insert(*modseq, *ident); new.idx_by_modseq.insert(new.internalmodseq, *ident);
*email_modseq = new.internalmodseq;
// Update counters // Update counters
new.highestmodseq = new.internalmodseq; new.highestmodseq = new.internalmodseq;