put message references into the sync records. match up the uids after
opening the boxes instead of "sort-of-on-demand" - this is much simpler. match from messages to sync records, not the other way round - makes the debug output shorter, as the separate dump_box() is gone now.
This commit is contained in:
parent
61dfbea617
commit
8c30ec4a25
141
src/sync.c
141
src/sync.c
|
@ -78,48 +78,6 @@ make_flags( int flags, char *buf )
|
|||
return d;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_box( store_t *ctx )
|
||||
{
|
||||
message_t *msg;
|
||||
char fbuf[16]; /* enlarge when support for keywords is added */
|
||||
|
||||
if (Debug)
|
||||
for (msg = ctx->msgs; msg; msg = msg->next) {
|
||||
make_flags( msg->flags, fbuf );
|
||||
printf( " message %d, %s, %d\n", msg->uid, fbuf, msg->size );
|
||||
}
|
||||
}
|
||||
|
||||
static message_t *
|
||||
findmsg( store_t *ctx, int uid, message_t **nmsg, const char *who )
|
||||
{
|
||||
message_t *msg;
|
||||
|
||||
if (uid > 0) {
|
||||
if (*nmsg && (*nmsg)->uid == uid) {
|
||||
debug( " %s came in sequence\n", who );
|
||||
msg = *nmsg;
|
||||
found:
|
||||
*nmsg = msg->next;
|
||||
if (!(msg->status & M_DEAD)) {
|
||||
msg->status |= M_PROCESSED;
|
||||
return msg;
|
||||
}
|
||||
debug( " ... but it vanished under our feet!\n" );
|
||||
} else {
|
||||
for (msg = ctx->msgs; msg; msg = msg->next)
|
||||
if (msg->uid == uid) {
|
||||
debug( " %s came out of sequence\n", who );
|
||||
goto found;
|
||||
}
|
||||
debug( " %s not present\n", who );
|
||||
}
|
||||
} else
|
||||
debug( " no %s expected\n", who );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define S_DEAD (1<<0)
|
||||
#define S_EXPIRED (1<<1)
|
||||
#define S_DEL(ms) (1<<(2+(ms)))
|
||||
|
@ -129,9 +87,51 @@ typedef struct sync_rec {
|
|||
struct sync_rec *next;
|
||||
/* string_list_t *keywords; */
|
||||
int uid[2];
|
||||
message_t *msg[2];
|
||||
unsigned char flags, status;
|
||||
} sync_rec_t;
|
||||
|
||||
static void
|
||||
findmsgs( sync_rec_t *srecs, store_t *ctx[], int t )
|
||||
{
|
||||
sync_rec_t *srec, *nsrec = 0;
|
||||
message_t *msg;
|
||||
const char *diag;
|
||||
int uid;
|
||||
char fbuf[16]; /* enlarge when support for keywords is added */
|
||||
|
||||
for (msg = ctx[t]->msgs; msg; msg = msg->next) {
|
||||
uid = msg->uid;
|
||||
if (Debug) {
|
||||
make_flags( msg->flags, fbuf );
|
||||
printf( ctx[t]->opts & OPEN_SIZE ? " message %5d, %-4s, %6d: " : " message %5d, %-4s: ", uid, fbuf, msg->size );
|
||||
}
|
||||
for (srec = nsrec; srec; srec = srec->next) {
|
||||
if (srec->status & S_DEAD)
|
||||
continue;
|
||||
if (srec->uid[t] == uid) {
|
||||
diag = srec == nsrec ? "adjacently" : "after gap";
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
for (srec = srecs; srec != nsrec; srec = srec->next) {
|
||||
if (srec->status & S_DEAD)
|
||||
continue;
|
||||
if (srec->uid[t] == uid) {
|
||||
diag = "after reset";
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
debug( "new\n" );
|
||||
continue;
|
||||
found:
|
||||
msg->status |= M_PROCESSED;
|
||||
srec->msg[t] = msg;
|
||||
nsrec = srec->next;
|
||||
debug( "pairs %5d %s\n", srec->uid[1-t], diag );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* cases:
|
||||
a) both non-null
|
||||
|
@ -177,7 +177,7 @@ int
|
|||
sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
||||
{
|
||||
driver_t *driver[2];
|
||||
message_t *msg[2], *tmsg, *nmmsg, *nsmsg;
|
||||
message_t *tmsg;
|
||||
sync_rec_t *recs, *srec, **srecadd, *nsrec;
|
||||
char *dname, *jname, *nname, *lname, *s, *cmname, *csname;
|
||||
FILE *dfp, *jfp, *nfp;
|
||||
|
@ -196,8 +196,6 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
ret = SYNC_OK;
|
||||
recs = 0, srecadd = &recs;
|
||||
|
||||
nmmsg = nsmsg = 0;
|
||||
|
||||
opts[M] = opts[S] = 0;
|
||||
for (t = 0; t < 2; t++) {
|
||||
if (chan->ops[t] & (OP_DELETE|OP_FLAGS)) {
|
||||
|
@ -327,6 +325,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
srec->status = 0;
|
||||
srec->flags = parse_flags( s );
|
||||
debug( " entry (%d,%d,%u,%s)\n", srec->uid[M], srec->uid[S], srec->flags, srec->status & S_EXPIRED ? "X" : "" );
|
||||
srec->msg[M] = srec->msg[S] = 0;
|
||||
srec->next = 0;
|
||||
*srecadd = srec;
|
||||
srecadd = &srec->next;
|
||||
|
@ -379,6 +378,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
srec->uid[S] = t2;
|
||||
srec->flags = t3;
|
||||
debug( " new entry(%d,%d,%u)\n", t1, t2, t3 );
|
||||
srec->msg[M] = srec->msg[S] = 0;
|
||||
srec->status = 0;
|
||||
srec->next = 0;
|
||||
*srecadd = srec;
|
||||
|
@ -455,7 +455,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto bail;
|
||||
}
|
||||
info( "%d messages, %d recent\n", ctx[S]->count, ctx[S]->recent );
|
||||
dump_box( ctx[S] );
|
||||
findmsgs( recs, ctx, S );
|
||||
|
||||
if (suidval && suidval != ctx[S]->uidvalidity) {
|
||||
fprintf( stderr, "Error: UIDVALIDITY of slave changed\n" );
|
||||
|
@ -495,7 +495,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
if (srec->status & S_DEAD)
|
||||
continue;
|
||||
if (srec->status & S_EXPIRED) {
|
||||
if (!srec->uid[S] || ((ctx[S]->opts & OPEN_OLD) && !findmsg( ctx[S], srec->uid[S], &nsmsg, "slave" ))) {
|
||||
if (!srec->uid[S] || ((ctx[S]->opts & OPEN_OLD) && !srec->msg[S])) {
|
||||
srec->status |= S_EXP_S;
|
||||
continue;
|
||||
}
|
||||
|
@ -562,7 +562,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||
}
|
||||
info( "%d messages, %d recent\n", ctx[M]->count, ctx[M]->recent );
|
||||
dump_box( ctx[M] );
|
||||
findmsgs( recs, ctx, M );
|
||||
|
||||
if (muidval && muidval != ctx[M]->uidvalidity) {
|
||||
fprintf( stderr, "Error: UIDVALIDITY of master changed\n" );
|
||||
|
@ -583,10 +583,8 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
if (srec->status & S_DEAD)
|
||||
continue;
|
||||
debug( "pair (%d,%d)\n", srec->uid[M], srec->uid[S] );
|
||||
msg[M] = findmsg( ctx[M], srec->uid[M], &nmmsg, "master" );
|
||||
msg[S] = (srec->status & S_EXP_S) ? 0 : findmsg( ctx[S], srec->uid[S], &nsmsg, "slave" );
|
||||
nom = !msg[M] && (ctx[M]->opts & OPEN_OLD);
|
||||
nos = !msg[S] && (ctx[S]->opts & OPEN_OLD);
|
||||
nom = !srec->msg[M] && (ctx[M]->opts & OPEN_OLD);
|
||||
nos = !srec->msg[S] && (ctx[S]->opts & OPEN_OLD);
|
||||
if (nom && nos) {
|
||||
debug( " vanished\n" );
|
||||
/* d.1) d.5) d.6) d.10) d.11) */
|
||||
|
@ -608,11 +606,11 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
} else if (del[1-t]) {
|
||||
/* c.4) d.9) / b.4) d.4) */
|
||||
debug( " %s vanished\n", str_ms[1-t] );
|
||||
if (msg[t] && msg[t]->flags != nflags)
|
||||
if (srec->msg[t] && srec->msg[t]->flags != nflags)
|
||||
info( "Info: conflicting changes in (%d,%d)\n", srec->uid[M], srec->uid[S] );
|
||||
if (chan->ops[t] & OP_DELETE) {
|
||||
debug( " -> %s delete\n", str_hl[t] );
|
||||
switch (driver[t]->set_flags( ctx[t], msg[t], srec->uid[t], F_DELETED, 0 )) {
|
||||
switch (driver[t]->set_flags( ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0 )) {
|
||||
case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
|
||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||
default: /* ok */ break;
|
||||
|
@ -621,48 +619,48 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
srec->uid[1-t] = 0;
|
||||
}
|
||||
}
|
||||
} else if (!msg[1-t])
|
||||
} else if (!srec->msg[1-t])
|
||||
/* c.1) c.2) d.7) d.8) / b.1) b.2) d.2) d.3) */
|
||||
;
|
||||
else if (srec->uid[t] < 0) {
|
||||
/* b.2) / c.2) */
|
||||
debug( " no %s yet\n", str_ms[t] );
|
||||
if (chan->ops[t] & OP_RENEW) {
|
||||
if ((chan->ops[t] & OP_EXPUNGE) && (msg[1-t]->flags & F_DELETED)) {
|
||||
if ((chan->ops[t] & OP_EXPUNGE) && (srec->msg[1-t]->flags & F_DELETED)) {
|
||||
debug( " -> not %sing - would be expunged anyway\n", str_hl[t] );
|
||||
msg[1-t]->status |= M_NOT_SYNCED;
|
||||
srec->msg[1-t]->status |= M_NOT_SYNCED;
|
||||
} else {
|
||||
if ((msg[1-t]->flags & F_FLAGGED) || !chan->stores[t]->max_size || msg[1-t]->size <= chan->stores[t]->max_size) {
|
||||
if ((srec->msg[1-t]->flags & F_FLAGGED) || !chan->stores[t]->max_size || srec->msg[1-t]->size <= chan->stores[t]->max_size) {
|
||||
debug( " -> %sing it\n", str_hl[t] );
|
||||
msgdata.flags = msg[1-t]->flags;
|
||||
switch (driver[1-t]->fetch_msg( ctx[1-t], msg[1-t], &msgdata )) {
|
||||
msgdata.flags = srec->msg[1-t]->flags;
|
||||
switch (driver[1-t]->fetch_msg( ctx[1-t], srec->msg[1-t], &msgdata )) {
|
||||
case DRV_STORE_BAD: ret = SYNC_BAD(1-t); goto finish;
|
||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||
default: /* ok */ msg[1-t]->status |= M_NOT_SYNCED; break;
|
||||
default: /* ok */ srec->msg[1-t]->status |= M_NOT_SYNCED; break;
|
||||
case DRV_OK:
|
||||
msg[1-t]->flags = msgdata.flags;
|
||||
srec->msg[1-t]->flags = msgdata.flags;
|
||||
switch (driver[t]->store_msg( ctx[t], &msgdata, &uid )) {
|
||||
case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
|
||||
default: ret = SYNC_FAIL; goto finish;
|
||||
case DRV_OK:
|
||||
Fprintf( jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], srec->uid[S], uid );
|
||||
srec->uid[t] = uid;
|
||||
nflags = msg[1-t]->flags;
|
||||
nflags = srec->msg[1-t]->flags;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug( " -> not %sing - still too big\n", str_hl[t] );
|
||||
msg[1-t]->status |= M_NOT_SYNCED;
|
||||
srec->msg[1-t]->status |= M_NOT_SYNCED;
|
||||
}
|
||||
}
|
||||
} else
|
||||
msg[1-t]->status |= M_NOT_SYNCED;
|
||||
srec->msg[1-t]->status |= M_NOT_SYNCED;
|
||||
} else if (!del[t]) {
|
||||
/* a) & b.3) / c.3) */
|
||||
debug( " may %s\n", str_hl[t] );
|
||||
if (chan->ops[t] & OP_FLAGS) {
|
||||
debug( " -> %sing flags\n", str_hl[t] );
|
||||
sflags = msg[1-t]->flags;
|
||||
sflags = srec->msg[1-t]->flags;
|
||||
aflags = sflags & ~nflags;
|
||||
dflags = ~sflags & nflags;
|
||||
unex = 0;
|
||||
|
@ -686,7 +684,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
aflags &= F_DELETED;
|
||||
dflags = 0;
|
||||
}
|
||||
switch ((aflags | dflags) ? driver[t]->set_flags( ctx[t], msg[t], srec->uid[t], aflags, dflags ) : DRV_OK) {
|
||||
switch ((aflags | dflags) ? driver[t]->set_flags( ctx[t], srec->msg[t], srec->uid[t], aflags, dflags ) : DRV_OK) {
|
||||
case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
|
||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||
default: /* ok */ break;
|
||||
|
@ -708,9 +706,9 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
srec->flags = nflags;
|
||||
Fprintf( jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], nflags );
|
||||
}
|
||||
if (msg[M] && (msg[M]->flags & F_DELETED))
|
||||
if (srec->msg[M] && (srec->msg[M]->flags & F_DELETED))
|
||||
srec->status |= S_DEL(M);
|
||||
if (msg[S] && (msg[S]->flags & F_DELETED))
|
||||
if (srec->msg[S] && (srec->msg[S]->flags & F_DELETED))
|
||||
srec->status |= S_DEL(S);
|
||||
}
|
||||
}
|
||||
|
@ -795,15 +793,14 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
|||
for (srec = recs; srec; srec = srec->next) {
|
||||
if (srec->status & (S_DEAD|S_EXPIRED))
|
||||
continue;
|
||||
tmsg = findmsg( ctx[S], srec->uid[S], &nsmsg, "slave" );
|
||||
if (tmsg && (tmsg->status & M_EXPIRED)) {
|
||||
if (srec->msg[S] && (srec->msg[S]->status & M_EXPIRED)) {
|
||||
debug( " expiring pair(%d,%d)\n", srec->uid[M], srec->uid[S] );
|
||||
/* log first, so deletion can't be misinterpreted! */
|
||||
Fprintf( jfp, "~ %d %d 1\n", srec->uid[M], srec->uid[S] );
|
||||
if (smaxxuid < srec->uid[S])
|
||||
smaxxuid = srec->uid[S];
|
||||
srec->status |= S_EXPIRED;
|
||||
switch (driver[S]->set_flags( ctx[S], tmsg, 0, F_DELETED, 0 )) {
|
||||
switch (driver[S]->set_flags( ctx[S], srec->msg[S], 0, F_DELETED, 0 )) {
|
||||
case DRV_STORE_BAD: ret = SYNC_BAD(S); goto finish;
|
||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||
default: /* ok */ break;
|
||||
|
|
Loading…
Reference in New Issue
Block a user