isync

mailbox synchronization program
git clone https://git.code.sf.net/p/isync/isync
Log | Files | Refs | README | LICENSE

commit b3155a8bcb14943c42432382f406e620d505c684
parent 6a78e2c5f61fdc1ec18a87f05f800d22ca59dfa6
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Thu, 16 Jun 2022 10:40:34 +0200

merge wstate back into status

this optimizes space usage, prospectively (we'd have to extend wstate
soon otherwise).

this partially reverts 4ffe1496.

Diffstat:
Msrc/sync.c | 54+++++++++++++++++++++++++++++-------------------------
Msrc/sync_p.h | 21+++++++++------------
Msrc/sync_state.c | 17+++++++----------
3 files changed, 45 insertions(+), 47 deletions(-)

diff --git a/src/sync.c b/src/sync.c @@ -722,11 +722,11 @@ box_opened2( sync_vars_t *svars, int t ) else warn( "Warning: sync record (%u,%u) has stray TUID. Ignoring.\n", srec->uid[F], srec->uid[N] ); } - if (srec->wstate & W_PURGE) { + if (srec->status & S_PURGE) { t = srec->uid[F] ? F : N; opts[t] |= OPEN_SETFLAGS; } - if (srec->wstate & W_UPGRADE) { + if (srec->status & S_UPGRADE) { t = !srec->uid[F] ? F : N; opts[t] |= OPEN_APPEND; opts[t^1] |= OPEN_OLD; @@ -970,7 +970,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux for (t = 0; t < 2; t++) { if (srec->msg[t] && (srec->msg[t]->flags & F_DELETED)) - srec->wstate |= W_DEL(t); + srec->status |= S_DEL(t); if (del[t]) { // The target was newly expunged, so there is nothing to update. // The deletion is propagated in the opposite iteration. @@ -996,7 +996,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux if (svars->chan->ops[t] & OP_DELETE) { debug( " %sing delete\n", str_hl[t] ); srec->aflags[t] = F_DELETED; - srec->wstate |= W_DELETE; + srec->status |= S_DELETE; } else { debug( " not %sing delete\n", str_hl[t] ); } @@ -1051,7 +1051,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux } } // This is separated, because the upgrade can come from the journal. - if (srec->wstate & W_UPGRADE) { + if (srec->status & S_UPGRADE) { t = !srec->uid[F] ? F : N; tmsg = srec->msg[t^1]; if ((svars->chan->ops[t] & OP_EXPUNGE) && (srec->pflags & F_DELETED)) { @@ -1087,7 +1087,8 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux srec->status |= S_DUMMY(t); JLOG( "_ %u %u", (srec->uid[F], srec->uid[N]), "placeholder only - was previously skipped" ); } else { - JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "was previously skipped" ); + JLOG( "~ %u %u %d", (srec->uid[F], srec->uid[N], srec->status & S_LOGGED), + "was previously skipped" ); } } else { if (!(svars->chan->ops[t] & OP_NEW)) @@ -1141,7 +1142,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux JLOG( "+ %u %u", (srec->uid[F], srec->uid[N]), "fresh" ); } if (!(tmsg->flags & F_FLAGGED) && tmsg->size > svars->chan->stores[t]->max_size && - !(srec->wstate & W_UPGRADE) && !(srec->status & (S_DUMMY(F)|S_DUMMY(N)))) { + !(srec->status & (S_DUMMY(F) | S_DUMMY(N) | S_UPGRADE))) { srec->status |= S_DUMMY(t); JLOG( "_ %u %u", (srec->uid[F], srec->uid[N]), "placeholder only - too big" ); } @@ -1206,7 +1207,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ((srec->status & (S_EXPIRE|S_EXPIRED)) == (S_EXPIRE|S_EXPIRED)) || ((srec->status & (S_EXPIRE|S_EXPIRED)) && (srec->msg[N]->flags & F_DELETED))) { /* The message is excess or was already (being) expired. */ - srec->wstate |= W_NEXPIRE; + srec->status |= S_NEXPIRE; debug( " pair(%u,%u) expired\n", srec->uid[F], srec->uid[N] ); if (svars->maxxfuid < srec->uid[F]) svars->maxxfuid = srec->uid[F]; @@ -1229,23 +1230,24 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux if (!(srec->status & S_PENDING)) { if (!srec->msg[N]) continue; - uchar nex = (srec->wstate / W_NEXPIRE) & 1; + uchar nex = (srec->status / S_NEXPIRE) & 1; if (nex != ((srec->status / S_EXPIRED) & 1)) { /* The record needs a state change ... */ if (nex != ((srec->status / S_EXPIRE) & 1)) { /* ... and we need to start a transaction. */ srec->status = (srec->status & ~S_EXPIRE) | (nex * S_EXPIRE); - JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "expire %u - begin", nex ); + JLOG( "~ %u %u %d", (srec->uid[F], srec->uid[N], srec->status & S_LOGGED), + "expire %u - begin", nex ); } else { /* ... but the "right" transaction is already pending. */ debug( "-> pair(%u,%u): expire %u (pending)\n", srec->uid[F], srec->uid[N], nex ); } } else { /* Note: the "wrong" transaction may be pending here, - * e.g.: W_NEXPIRE = 0, S_EXPIRE = 1, S_EXPIRED = 0. */ + * e.g.: S_NEXPIRE = 0, S_EXPIRE = 1, S_EXPIRED = 0. */ } } else { - if (srec->wstate & W_NEXPIRE) { + if (srec->status & S_NEXPIRE) { JLOG( "= %u %u", (srec->uid[F], srec->uid[N]), "expire unborn" ); // If we have so many new messages that some of them are instantly expired, // but some are still propagated because they are important, we need to @@ -1270,14 +1272,14 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux continue; aflags = srec->aflags[t]; dflags = srec->dflags[t]; - if (srec->wstate & (W_DELETE|W_PURGE)) { + if (srec->status & (S_DELETE | S_PURGE)) { if (!aflags) { // This deletion propagation goes the other way round, or // this deletion of a dummy happens on the other side. continue; } if (!srec->msg[t] && (svars->opts[t] & OPEN_OLD)) { - // The message disappeared. This can happen, because the wstate may + // The message disappeared. This can happen, because the status may // come from the journal, and things could have happened meanwhile. continue; } @@ -1286,7 +1288,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux if ((t == N) && ((shifted_bit(srec->status, S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED)) { // ... but the actual action derives from the wanted state - // so that canceled transactions are rolled back as well. - if (srec->wstate & W_NEXPIRE) + if (srec->status & S_NEXPIRE) aflags |= F_DELETED; else dflags |= F_DELETED; @@ -1369,7 +1371,7 @@ msg_copied( int sts, uint uid, copy_vars_t *vars ) sync_rec_t *srec = vars->srec; switch (sts) { case SYNC_OK: - if (!(srec->wstate & W_UPGRADE) && vars->msg->flags != srec->flags) { + if (!(srec->status & S_UPGRADE) && vars->msg->flags != srec->flags) { srec->flags = vars->msg->flags; JLOG( "* %u %u %u", (srec->uid[F], srec->uid[N], srec->flags), "%sed with flags", str_hl[t] ); } @@ -1480,9 +1482,9 @@ flags_set( int sts, void *aux ) switch (sts) { case DRV_OK: if (vars->aflags & F_DELETED) - srec->wstate |= W_DEL(t); + srec->status |= S_DEL(t); else if (vars->dflags & F_DELETED) - srec->wstate &= ~W_DEL(t); + srec->status &= ~S_DEL(t); flags_set_p2( svars, srec, t ); break; } @@ -1496,7 +1498,7 @@ flags_set( int sts, void *aux ) static void flags_set_p2( sync_vars_t *svars, sync_rec_t *srec, int t ) { - if (srec->wstate & W_DELETE) { + 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 { @@ -1506,13 +1508,15 @@ flags_set_p2( sync_vars_t *svars, sync_rec_t *srec, int t ) srec->flags = nflags; } if (t == N) { - uchar nex = (srec->wstate / W_NEXPIRE) & 1; + uchar nex = (srec->status / S_NEXPIRE) & 1; if (nex != ((srec->status / S_EXPIRED) & 1)) { srec->status = (srec->status & ~S_EXPIRED) | (nex * S_EXPIRED); - JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "expired %d - commit", nex ); + JLOG( "~ %u %u %d", (srec->uid[F], srec->uid[N], srec->status & S_LOGGED), + "expired %d - commit", nex ); } else if (nex != ((srec->status / S_EXPIRE) & 1)) { srec->status = (srec->status & ~S_EXPIRE) | (nex * S_EXPIRE); - JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "expire %d - cancel", nex ); + JLOG( "~ %u %u %d", (srec->uid[F], srec->uid[N], srec->status & S_LOGGED), + "expire %d - cancel", nex ); } } } @@ -1690,8 +1694,8 @@ box_closed_p2( sync_vars_t *svars, int t ) for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; - if (!srec->uid[N] || ((srec->wstate & W_DEL(N)) && (svars->state[N] & ST_DID_EXPUNGE))) { - if (!srec->uid[F] || ((srec->wstate & W_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE)) || + 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)) || ((srec->status & S_EXPIRED) && svars->maxuid[F] >= srec->uid[F] && svars->maxxfuid >= srec->uid[F])) { JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "killing" ); srec->status = S_DEAD; @@ -1699,7 +1703,7 @@ box_closed_p2( sync_vars_t *svars, int t ) JLOG( "> %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" ); srec->uid[N] = 0; } - } else if (srec->uid[F] && ((srec->wstate & W_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE))) { + } else if (srec->uid[F] && ((srec->status & S_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE))) { JLOG( "< %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" ); srec->uid[F] = 0; } diff --git a/src/sync_p.h b/src/sync_p.h @@ -9,33 +9,30 @@ #include "sync.h" #include "sync_p_enum.h" -// This is the (mostly) persistent status of the sync record. -// Most of these bits are actually mutually exclusive. It is a -// bitfield to allow for easy testing for multiple states. BIT_ENUM( S_DEAD, // ephemeral: the entry was killed and should be ignored S_EXPIRE, // the entry is being expired (near side message removal scheduled) S_EXPIRED, // the entry is expired (near side message removal confirmed) + S_NEXPIRE, // temporary: new expiration state 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_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 + S_PURGE, // ephemeral: placeholder is being nuked ) -// Ephemeral working set. -BIT_ENUM( - W_NEXPIRE, // temporary: new expiration state - W_DELETE, // ephemeral: flags propagation is a deletion - W_DEL(2), // ephemeral: f/n message would be subject to expunge - W_UPGRADE, // ephemeral: upgrading placeholder, do not apply MaxSize - W_PURGE, // ephemeral: placeholder is being nuked -) +// This is the persistent status of the sync record, with regard to the journal. +#define S_LOGGED (S_EXPIRE | S_EXPIRED | S_PENDING | S_DUMMY(F) | S_DUMMY(N) | S_SKIPPED) typedef struct sync_rec { struct sync_rec *next; /* string_list_t *keywords; */ uint uid[2]; message_t *msg[2]; - uchar status, wstate, flags, pflags, aflags[2], dflags[2]; + ushort status; + uchar flags, pflags, aflags[2], dflags[2]; char tuid[TUIDL]; } sync_rec_t; diff --git a/src/sync_state.c b/src/sync_state.c @@ -356,16 +356,15 @@ load_state( sync_vars_t *svars ) debug( "flags now %u\n", t3 ); srec->flags = (uchar)t3; srec->aflags[F] = srec->aflags[N] = 0; // Clear F_DELETED from purge - srec->wstate &= ~W_PURGE; + srec->status &= ~S_PURGE; break; case '~': - debug( "status now %#x\n", t3 ); - srec->status = (uchar)t3; + srec->status = (srec->status & ~S_LOGGED) | t3; + debug( "status now %#x\n", srec->status ); break; case '_': debug( "has placeholder now\n" ); - srec->status = S_PENDING; // Pre-1.4 legacy only - srec->status |= !srec->uid[F] ? S_DUMMY(F) : S_DUMMY(N); + srec->status = S_PENDING | (!srec->uid[F] ? S_DUMMY(F) : S_DUMMY(N)); break; case '^': debug( "is being upgraded, flags %u, srec flags %u\n", t3, t4 ); @@ -482,8 +481,7 @@ assign_uid( sync_vars_t *svars, sync_rec_t *srec, int t, uint uid ) srec->uid[t] = uid; if (uid == svars->maxuid[t] + 1) svars->maxuid[t] = uid; - srec->status &= ~S_PENDING; - srec->wstate &= ~W_UPGRADE; + srec->status &= ~(S_PENDING | S_UPGRADE); srec->tuid[0] = 0; } @@ -560,10 +558,9 @@ upgrade_srec( sync_vars_t *svars, sync_rec_t *srec ) srec->msg[t] = NULL; } // Mark the original entry for upgrade. - srec->status = (srec->status & ~(S_DUMMY(F)|S_DUMMY(N))) | S_PENDING; - srec->wstate |= W_UPGRADE; + srec->status = (srec->status & ~(S_DUMMY(F) | S_DUMMY(N))) | S_PENDING | S_UPGRADE; // Mark the placeholder for nuking. - nsrec->wstate = W_PURGE; + nsrec->status = S_PURGE; nsrec->aflags[t] = F_DELETED; return nsrec; }