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 = ( my @x01 = (
I, 0, I, I, 0, I,
P, "_", "*", "_",
R, "*", "", "", # Skipped/failed messages to prevent maxuid topping R, "*", "", "", # Skipped/failed messages to prevent maxuid topping
S, "", "", "*", S, "", "", "*",
A, "*F", "*", "*", A, "*F", "*", "*",
@ -949,6 +950,8 @@ my @x01 = (
D, "*", "*", "*", D, "*", "*", "*",
E, "*T", "*", "*", E, "*T", "*", "*",
F, "*", "*", "*T", F, "*", "*", "*T",
O, "*T", "*T", "*T",
Q, "_", "*T", "*T",
G, "*F", "*", "_", G, "*F", "*", "_",
H, "*FT", "*", "*", H, "*FT", "*", "*",
I, "_", "*", "*", I, "_", "*", "*",
@ -961,11 +964,13 @@ my @x01 = (
my @O01 = ("", "", ""); my @O01 = ("", "", "");
my @X01 = ( my @X01 = (
M, 0, K, M, 0, K,
P, "", "/", "",
A, "", "+F", "+F", A, "", "+F", "+F",
B, "+F", "+F", "", B, "+F", "+F", "",
C, "", "+FS", "+S", C, "", "+FS", "+S",
E, "", "+T", "+T", E, "", "+T", "+T",
F, "+T", "+T", "", F, "+T", "+T", "",
Q, "", "<", "",
G, "+T", ">", "", G, "+T", ">", "",
H, "", "+FT", "+FT", H, "", "+FT", "+FT",
I, "", "<", "+T", I, "", "<", "+T",
@ -979,11 +984,14 @@ test("full", \@x01, \@X01, \@O01);
my @O02 = ("", "", "Expunge Both\n"); my @O02 = ("", "", "Expunge Both\n");
my @X02 = ( my @X02 = (
M, 0, K, M, 0, K,
P, "", "/", "",
A, "", "+F", "+F", A, "", "+F", "+F",
B, "+F", "+F", "", B, "+F", "+F", "",
C, "", "+FS", "+S", C, "", "+FS", "+S",
E, "/", "/", "/", E, "/", "/", "/",
F, "/", "/", "/", F, "/", "/", "/",
O, "/", "/", "/",
Q, "", "/", "/",
G, "/", "/", "", G, "/", "/", "",
H, "/", "/", "/", H, "/", "/", "/",
I, "", "/", "/", I, "", "/", "/",
@ -997,11 +1005,14 @@ test("full + expunge both", \@x01, \@X02, \@O02);
my @O03 = ("", "", "Expunge Near\n"); my @O03 = ("", "", "Expunge Near\n");
my @X03 = ( my @X03 = (
M, 0, K, M, 0, K,
P, "", "/", "",
A, "", "+F", "+F", A, "", "+F", "+F",
B, "+F", "+F", "", B, "+F", "+F", "",
C, "", "+FS", "+S", C, "", "+FS", "+S",
E, "", ">+T", "/", E, "", ">+T", "/",
F, "+T", ">+T", "/", F, "+T", ">+T", "/",
O, "", ">", "/",
Q, "", "/", "/",
G, "+T", ">", "", G, "+T", ">", "",
H, "", ">+T", "/", H, "", ">+T", "/",
I, "", "/", "/", I, "", "/", "/",
@ -1014,9 +1025,11 @@ test("full + expunge near side", \@x01, \@X03, \@O03);
my @O04 = ("", "", "Sync Pull\n"); my @O04 = ("", "", "Sync Pull\n");
my @X04 = ( my @X04 = (
K, 0, I, K, 0, I,
P, "", "/", "", # Only because test uses Maildir driver
A, "", "+F", "+F", A, "", "+F", "+F",
C, "", "+FS", "+S", C, "", "+FS", "+S",
E, "", "+T", "+T", E, "", "+T", "+T",
Q, "", "<", "",
H, "", "+FT", "+FT", H, "", "+FT", "+FT",
I, "", "<", "+T", I, "", "<", "+T",
J, "", "*T", "*T", J, "", "*T", "*T",
@ -1027,11 +1040,13 @@ test("pull", \@x01, \@X04, \@O04);
my @O05 = ("", "", "Sync Flags\n"); my @O05 = ("", "", "Sync Flags\n");
my @X05 = ( my @X05 = (
I, 0, I, I, 0, I,
P, "", "/", "",
A, "", "+F", "+F", A, "", "+F", "+F",
B, "+F", "+F", "", B, "+F", "+F", "",
C, "", "+FS", "+S", C, "", "+FS", "+S",
E, "", "+T", "+T", E, "", "+T", "+T",
F, "+T", "+T", "", F, "+T", "+T", "",
Q, "", "<", "",
H, "", "+FT", "+FT", H, "", "+FT", "+FT",
); );
test("flags", \@x01, \@X05, \@O05); test("flags", \@x01, \@X05, \@O05);
@ -1039,7 +1054,9 @@ test("flags", \@x01, \@X05, \@O05);
my @O06 = ("", "", "Sync Delete\n"); my @O06 = ("", "", "Sync Delete\n");
my @X06 = ( my @X06 = (
I, 0, I, I, 0, I,
P, "", "/", "",
G, "+T", ">", "", G, "+T", ">", "",
Q, "", "<", "",
I, "", "<", "+T", I, "", "<", "+T",
); );
test("deletions", \@x01, \@X06, \@O06); test("deletions", \@x01, \@X06, \@O06);
@ -1057,9 +1074,11 @@ test("new", \@x01, \@X07, \@O07);
my @O08 = ("", "", "Sync PushFlags PullDelete\n"); my @O08 = ("", "", "Sync PushFlags PullDelete\n");
my @X08 = ( my @X08 = (
I, 0, I, I, 0, I,
P, "", "/", "",
B, "+F", "+F", "", B, "+F", "+F", "",
C, "", "+F", "", C, "", "+F", "",
F, "+T", "+T", "", F, "+T", "+T", "",
Q, "", "<", "",
I, "", "<", "+T", I, "", "<", "+T",
); );
test("push flags + pull deletions", \@x01, \@X08, \@O08); 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 @O09 = ("", "", "Sync None\nExpunge Both\n");
my @X09 = ( my @X09 = (
I, 0, I, I, 0, I,
P, "", "/", "",
E, "/", "", "", E, "/", "", "",
F, "", "", "/", F, "", "", "/",
O, "/", "/", "/",
Q, "", "/", "/",
H, "/", "", "", H, "/", "", "",
J, "/", "", "", J, "/", "", "",
L, "", "", "/", L, "", "", "/",
@ -1080,6 +1102,8 @@ my @O0A = ("", "", "Sync None\nExpunge Near\n");
my @X0A = ( my @X0A = (
I, 0, I, I, 0, I,
F, "", "", "/", F, "", "", "/",
O, "", "", "/",
Q, "", "", "/",
L, "", "", "/", L, "", "", "/",
); );
test("noop + expunge near side", \@x01, \@X0A, \@O0A); 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]) { } else if (del[t]) {
// The target was newly expunged, so there is nothing to update. // The target was newly expunged, so there is nothing to update.
// The deletion is propagated in the opposite iteration. // The deletion is propagated in the opposite iteration.
srec->status |= S_GONE(t);
} else if (!srec->uid[t]) { } else if (!srec->uid[t]) {
// The target was never stored, or was previously expunged, so there // The target was never stored, or was previously expunged, so there
// is nothing to update. // 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++) { for (t = 0; t < 2; t++) {
if (!srec->uid[t]) if (!srec->uid[t])
continue; 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: // 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 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 // - 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) { if (srec->status & S_PURGE) {
JLOG( "P %u %u", (srec->uid[F], srec->uid[N]), "deleted dummy" ); JLOG( "P %u %u", (srec->uid[F], srec->uid[N]), "deleted dummy" );
srec->status = (srec->status & ~S_PURGE) | S_PURGED; srec->status = (srec->status & ~S_PURGE) | S_PURGED;
} else if (srec->status & S_DELETE) { } 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 {
uchar nflags = (srec->flags | srec->aflags[t]) & ~srec->dflags[t]; uchar nflags = (srec->flags | srec->aflags[t]) & ~srec->dflags[t];
if (srec->flags != nflags) { if (srec->flags != nflags) {
JLOG( "* %u %u %u", (srec->uid[F], srec->uid[N], nflags), "%sed flags %s; were %s", 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] ); 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" ); debug( "purging obsolete entries\n" );
for (srec = svars->srecs; srec; srec = srec->next) { for (srec = svars->srecs; srec; srec = srec->next) {
if (srec->status & S_DEAD) if (srec->status & S_DEAD)
continue; continue;
if (!srec->uid[N] || ((srec->status & S_DEL(N)) && (svars->state[N] & ST_DID_EXPUNGE))) { if ((srec->status & S_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE))
if (!srec->uid[F] || ((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])) { ((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" ); PC_JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "killing" );
srec->status = S_DEAD; 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" ); PC_JLOG( "> %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" );
srec->uid[N] = 0; 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" ); PC_JLOG( "< %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" );
srec->uid[F] = 0; srec->uid[F] = 0;
} }
} }
}
save_state( svars ); save_state( svars );

View File

@ -17,6 +17,7 @@ BIT_ENUM(
S_PENDING, // the entry is new and awaits propagation (possibly a retry) S_PENDING, // the entry is new and awaits propagation (possibly a retry)
S_DUMMY(2), // f/n message is only a placeholder 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_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_DEL(2), // ephemeral: f/n message would be subject to expunge
S_DELETE, // ephemeral: flags propagation is a deletion S_DELETE, // ephemeral: flags propagation is a deletion
S_UPGRADE, // ephemeral: upgrading placeholder, do not apply MaxSize S_UPGRADE, // ephemeral: upgrading placeholder, do not apply MaxSize