Browse Source

*** implement fallback path in UIDVALIDITY recovery

mailboxes with mostly messages with no Message-Id (such as Drafts and
Templates) cannot recover the usual way.

this patch implements a statistical method. as such, it has a (very)
slight chance to yield a false positive which would subsequently clobber
actual messages (specifically, the ones which were not sufficient to
throw off the algorithm). it would be possible to be even stricter, but
then any actual modification of the box would make the algorithm fail.
and even in this case, it would be still possible that even though the
UIDs match (and thus nothing gets deleted), the actual messages are in
reality different (though this is ridiculously unlikely).
the added tolerance doesn't help with stores which are synced seldomly,
as too much is likely to happen in the mean time.

*** actually make it stricter?
wip/uidval-recovery
Oswald Buddenhagen 8 years ago
parent
commit
224a783e83
  1. 28
      src/sync.c

28
src/sync.c

@ -1434,11 +1434,12 @@ box_loaded( int sts, void *aux )
for (t = 0; t < 2; t++) {
if (svars->uidval[t] >= 0 && svars->uidval[t] != svars->ctx[t]->uidvalidity) {
unsigned need = 0, got = 0;
unsigned total = 0, need = 0, got = 0;
debug( "trying to re-approve uid validity of %s\n", str_ms[t] );
for (srec = svars->srecs; srec; srec = srec->next) {
if (srec->status & S_DEAD)
continue;
total++;
if (!srec->msg[t])
continue; // Message disappeared.
need++; // Present paired messages require re-validation.
@ -1461,12 +1462,37 @@ box_loaded( int sts, void *aux )
// A proper fallback would be fetching more headers (which potentially need
// normalization) or the message body (which should be truncated for sanity)
// and comparing.
// But for simplicity, we employ a heuristic instead. We limit it to mailboxes
// with at most 10 messages as a means to limit (hypothetical) damage (though
// with more messages, the likelihood of a false positive is even lower).
// The algorithm checks whether enough (80%) of the messages are still in place,
// not too many (20%) new messages appeared, and that no new messages appeared
// in the already seen UID range. A genuine UID re-enumeration would quickly
// invalidate these assertions. The algorithm is most reliable when the UIDs
// are non-adjacent (which increases with mailbox use) due to looking random.
if (total <= 10 && need * 5 >= total * 4) {
unsigned neu = 0;
debug( "doing purely UID-based recovery\n" );
for (tmsg = svars->ctx[t]->msgs; tmsg; tmsg = tmsg->next) {
if (!tmsg->srec) {
if (tmsg->uid <= svars->maxuid[t]) {
error( "Error: channel %s, %s %s: UIDVALIDITY genuinely changed (at UID %d).\n",
svars->chan->name, str_ms[t], svars->orig_name[t], tmsg->uid );
goto uvchg;
}
neu++;
}
}
if (neu * 5 <= total)
goto uvchgok;
}
error( "Error: channel %s, %s %s: Unable to recover from UIDVALIDITY change\n"
"(got %d, expected %d).\n",
svars->chan->name, str_ms[t], svars->orig_name[t],
svars->ctx[t]->uidvalidity, svars->uidval[t] );
goto uvchg;
}
uvchgok:
notice( "Notice: channel %s, %s %s: Recovered from change of UIDVALIDITY.\n",
svars->chan->name, str_ms[t], svars->orig_name[t] );
svars->uidval[t] = -1;

Loading…
Cancel
Save