orphan/prune sync entries also if messages were expunged externally

deletions we propagated ourselves are implicitly covered by that as
well, so we don't need to record them separately anymore.
This commit is contained in:
Oswald Buddenhagen 2022-06-01 14:04:12 +02:00
parent f2f519e20b
commit eab3874918
3 changed files with 47 additions and 22 deletions

View File

@ -941,6 +941,7 @@ sub test($$$$)
my @x01 = (
I, 0, I,
P, "_", "*", "_",
R, "*", "", "", # Skipped/failed messages to prevent maxuid topping
S, "", "", "*",
A, "*F", "*", "*",
@ -949,6 +950,8 @@ my @x01 = (
D, "*", "*", "*",
E, "*T", "*", "*",
F, "*", "*", "*T",
O, "*T", "*T", "*T",
Q, "_", "*T", "*T",
G, "*F", "*", "_",
H, "*FT", "*", "*",
I, "_", "*", "*",
@ -961,11 +964,13 @@ my @x01 = (
my @O01 = ("", "", "");
my @X01 = (
M, 0, K,
P, "", "/", "",
A, "", "+F", "+F",
B, "+F", "+F", "",
C, "", "+FS", "+S",
E, "", "+T", "+T",
F, "+T", "+T", "",
Q, "", "<", "",
G, "+T", ">", "",
H, "", "+FT", "+FT",
I, "", "<", "+T",
@ -979,11 +984,14 @@ test("full", \@x01, \@X01, \@O01);
my @O02 = ("", "", "Expunge Both\n");
my @X02 = (
M, 0, K,
P, "", "/", "",
A, "", "+F", "+F",
B, "+F", "+F", "",
C, "", "+FS", "+S",
E, "/", "/", "/",
F, "/", "/", "/",
O, "/", "/", "/",
Q, "", "/", "/",
G, "/", "/", "",
H, "/", "/", "/",
I, "", "/", "/",
@ -997,11 +1005,14 @@ test("full + expunge both", \@x01, \@X02, \@O02);
my @O03 = ("", "", "Expunge Near\n");
my @X03 = (
M, 0, K,
P, "", "/", "",
A, "", "+F", "+F",
B, "+F", "+F", "",
C, "", "+FS", "+S",
E, "", ">+T", "/",
F, "+T", ">+T", "/",
O, "", ">", "/",
Q, "", "/", "/",
G, "+T", ">", "",
H, "", ">+T", "/",
I, "", "/", "/",
@ -1014,9 +1025,11 @@ test("full + expunge near side", \@x01, \@X03, \@O03);
my @O04 = ("", "", "Sync Pull\n");
my @X04 = (
K, 0, I,
P, "", "/", "", # Only because test uses Maildir driver
A, "", "+F", "+F",
C, "", "+FS", "+S",
E, "", "+T", "+T",
Q, "", "<", "",
H, "", "+FT", "+FT",
I, "", "<", "+T",
J, "", "*T", "*T",
@ -1027,11 +1040,13 @@ test("pull", \@x01, \@X04, \@O04);
my @O05 = ("", "", "Sync Flags\n");
my @X05 = (
I, 0, I,
P, "", "/", "",
A, "", "+F", "+F",
B, "+F", "+F", "",
C, "", "+FS", "+S",
E, "", "+T", "+T",
F, "+T", "+T", "",
Q, "", "<", "",
H, "", "+FT", "+FT",
);
test("flags", \@x01, \@X05, \@O05);
@ -1039,7 +1054,9 @@ test("flags", \@x01, \@X05, \@O05);
my @O06 = ("", "", "Sync Delete\n");
my @X06 = (
I, 0, I,
P, "", "/", "",
G, "+T", ">", "",
Q, "", "<", "",
I, "", "<", "+T",
);
test("deletions", \@x01, \@X06, \@O06);
@ -1057,9 +1074,11 @@ test("new", \@x01, \@X07, \@O07);
my @O08 = ("", "", "Sync PushFlags PullDelete\n");
my @X08 = (
I, 0, I,
P, "", "/", "",
B, "+F", "+F", "",
C, "", "+F", "",
F, "+T", "+T", "",
Q, "", "<", "",
I, "", "<", "+T",
);
test("push flags + pull deletions", \@x01, \@X08, \@O08);
@ -1067,8 +1086,11 @@ test("push flags + pull deletions", \@x01, \@X08, \@O08);
my @O09 = ("", "", "Sync None\nExpunge Both\n");
my @X09 = (
I, 0, I,
P, "", "/", "",
E, "/", "", "",
F, "", "", "/",
O, "/", "/", "/",
Q, "", "/", "/",
H, "/", "", "",
J, "/", "", "",
L, "", "", "/",
@ -1080,6 +1102,8 @@ my @O0A = ("", "", "Sync None\nExpunge Near\n");
my @X0A = (
I, 0, I,
F, "", "", "/",
O, "", "", "/",
Q, "", "", "/",
L, "", "", "/",
);
test("noop + expunge near side", \@x01, \@X0A, \@O0A);

View File

@ -1036,6 +1036,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
} else if (del[t]) {
// The target was newly expunged, so there is nothing to update.
// The deletion is propagated in the opposite iteration.
srec->status |= S_GONE(t);
} else if (!srec->uid[t]) {
// The target was never stored, or was previously expunged, so there
// is nothing to update.
@ -1340,7 +1341,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
for (t = 0; t < 2; t++) {
if (!srec->uid[t])
continue;
if (!srec->msg[t] && (svars->opts[t] & OPEN_OLD)) {
if (srec->status & S_GONE(t)) {
// The message was expunged. No need to call flags_set(), because:
// - for S_DELETE and S_PURGE, the entry will be pruned due to both sides being gone
// - for regular flag propagations, there is nothing to do
@ -1571,10 +1572,7 @@ flags_set_p2( sync_vars_t *svars, sync_rec_t *srec, int t )
if (srec->status & S_PURGE) {
JLOG( "P %u %u", (srec->uid[F], srec->uid[N]), "deleted dummy" );
srec->status = (srec->status & ~S_PURGE) | S_PURGED;
} else if (srec->status & S_DELETE) {
JLOG( "%c %u %u 0", ("><"[t], srec->uid[F], srec->uid[N]), "%sed deletion", str_hl[t] );
srec->uid[t^1] = 0;
} else {
} else if (!(srec->status & S_DELETE)) {
uchar nflags = (srec->flags | srec->aflags[t]) & ~srec->dflags[t];
if (srec->flags != nflags) {
JLOG( "* %u %u %u", (srec->uid[F], srec->uid[N], nflags), "%sed flags %s; were %s",
@ -1802,13 +1800,16 @@ box_closed_p2( sync_vars_t *svars, int t )
PC_JLOG( "N %d %u", (t, svars->maxuid[t]), "up maxuid of %s", str_fn[t] );
}
if (((svars->state[F] | svars->state[N]) & ST_DID_EXPUNGE) || svars->chan->max_messages) {
debug( "purging obsolete entries\n" );
for (srec = svars->srecs; srec; srec = srec->next) {
if (srec->status & S_DEAD)
continue;
if (!srec->uid[N] || ((srec->status & S_DEL(N)) && (svars->state[N] & ST_DID_EXPUNGE))) {
if (!srec->uid[F] || ((srec->status & S_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE)) ||
if ((srec->status & S_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE))
srec->status |= S_GONE(F);
if ((srec->status & S_DEL(N)) && (svars->state[N] & ST_DID_EXPUNGE))
srec->status |= S_GONE(N);
if (!srec->uid[N] || (srec->status & S_GONE(N))) {
if (!srec->uid[F] || (srec->status & S_GONE(F)) ||
((srec->status & S_EXPIRED) && svars->maxuid[F] >= srec->uid[F] && svars->maxxfuid >= srec->uid[F])) {
PC_JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "killing" );
srec->status = S_DEAD;
@ -1816,12 +1817,11 @@ box_closed_p2( sync_vars_t *svars, int t )
PC_JLOG( "> %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" );
srec->uid[N] = 0;
}
} else if (srec->uid[F] && ((srec->status & S_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE)) && (srec->status & S_DEL(N))) {
} else if (srec->uid[F] && (srec->status & S_GONE(F)) && (srec->status & S_DEL(N))) {
PC_JLOG( "< %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" );
srec->uid[F] = 0;
}
}
}
save_state( svars );

View File

@ -17,6 +17,7 @@ BIT_ENUM(
S_PENDING, // the entry is new and awaits propagation (possibly a retry)
S_DUMMY(2), // f/n message is only a placeholder
S_SKIPPED, // pre-1.4 legacy: the entry was not propagated (message is too big)
S_GONE(2), // ephemeral: f/n message has been expunged
S_DEL(2), // ephemeral: f/n message would be subject to expunge
S_DELETE, // ephemeral: flags propagation is a deletion
S_UPGRADE, // ephemeral: upgrading placeholder, do not apply MaxSize