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;
|
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_DEAD (1<<0)
|
||||||
#define S_EXPIRED (1<<1)
|
#define S_EXPIRED (1<<1)
|
||||||
#define S_DEL(ms) (1<<(2+(ms)))
|
#define S_DEL(ms) (1<<(2+(ms)))
|
||||||
|
@ -129,9 +87,51 @@ typedef struct sync_rec {
|
||||||
struct sync_rec *next;
|
struct sync_rec *next;
|
||||||
/* string_list_t *keywords; */
|
/* string_list_t *keywords; */
|
||||||
int uid[2];
|
int uid[2];
|
||||||
|
message_t *msg[2];
|
||||||
unsigned char flags, status;
|
unsigned char flags, status;
|
||||||
} sync_rec_t;
|
} 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:
|
/* cases:
|
||||||
a) both non-null
|
a) both non-null
|
||||||
|
@ -177,7 +177,7 @@ int
|
||||||
sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
||||||
{
|
{
|
||||||
driver_t *driver[2];
|
driver_t *driver[2];
|
||||||
message_t *msg[2], *tmsg, *nmmsg, *nsmsg;
|
message_t *tmsg;
|
||||||
sync_rec_t *recs, *srec, **srecadd, *nsrec;
|
sync_rec_t *recs, *srec, **srecadd, *nsrec;
|
||||||
char *dname, *jname, *nname, *lname, *s, *cmname, *csname;
|
char *dname, *jname, *nname, *lname, *s, *cmname, *csname;
|
||||||
FILE *dfp, *jfp, *nfp;
|
FILE *dfp, *jfp, *nfp;
|
||||||
|
@ -196,8 +196,6 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
||||||
ret = SYNC_OK;
|
ret = SYNC_OK;
|
||||||
recs = 0, srecadd = &recs;
|
recs = 0, srecadd = &recs;
|
||||||
|
|
||||||
nmmsg = nsmsg = 0;
|
|
||||||
|
|
||||||
opts[M] = opts[S] = 0;
|
opts[M] = opts[S] = 0;
|
||||||
for (t = 0; t < 2; t++) {
|
for (t = 0; t < 2; t++) {
|
||||||
if (chan->ops[t] & (OP_DELETE|OP_FLAGS)) {
|
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->status = 0;
|
||||||
srec->flags = parse_flags( s );
|
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" : "" );
|
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;
|
srec->next = 0;
|
||||||
*srecadd = srec;
|
*srecadd = srec;
|
||||||
srecadd = &srec->next;
|
srecadd = &srec->next;
|
||||||
|
@ -379,6 +378,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
||||||
srec->uid[S] = t2;
|
srec->uid[S] = t2;
|
||||||
srec->flags = t3;
|
srec->flags = t3;
|
||||||
debug( " new entry(%d,%d,%u)\n", t1, t2, t3 );
|
debug( " new entry(%d,%d,%u)\n", t1, t2, t3 );
|
||||||
|
srec->msg[M] = srec->msg[S] = 0;
|
||||||
srec->status = 0;
|
srec->status = 0;
|
||||||
srec->next = 0;
|
srec->next = 0;
|
||||||
*srecadd = srec;
|
*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;
|
case DRV_BOX_BAD: ret = SYNC_FAIL; goto bail;
|
||||||
}
|
}
|
||||||
info( "%d messages, %d recent\n", ctx[S]->count, ctx[S]->recent );
|
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) {
|
if (suidval && suidval != ctx[S]->uidvalidity) {
|
||||||
fprintf( stderr, "Error: UIDVALIDITY of slave changed\n" );
|
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)
|
if (srec->status & S_DEAD)
|
||||||
continue;
|
continue;
|
||||||
if (srec->status & S_EXPIRED) {
|
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;
|
srec->status |= S_EXP_S;
|
||||||
continue;
|
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;
|
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||||
}
|
}
|
||||||
info( "%d messages, %d recent\n", ctx[M]->count, ctx[M]->recent );
|
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) {
|
if (muidval && muidval != ctx[M]->uidvalidity) {
|
||||||
fprintf( stderr, "Error: UIDVALIDITY of master changed\n" );
|
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)
|
if (srec->status & S_DEAD)
|
||||||
continue;
|
continue;
|
||||||
debug( "pair (%d,%d)\n", srec->uid[M], srec->uid[S] );
|
debug( "pair (%d,%d)\n", srec->uid[M], srec->uid[S] );
|
||||||
msg[M] = findmsg( ctx[M], srec->uid[M], &nmmsg, "master" );
|
nom = !srec->msg[M] && (ctx[M]->opts & OPEN_OLD);
|
||||||
msg[S] = (srec->status & S_EXP_S) ? 0 : findmsg( ctx[S], srec->uid[S], &nsmsg, "slave" );
|
nos = !srec->msg[S] && (ctx[S]->opts & OPEN_OLD);
|
||||||
nom = !msg[M] && (ctx[M]->opts & OPEN_OLD);
|
|
||||||
nos = !msg[S] && (ctx[S]->opts & OPEN_OLD);
|
|
||||||
if (nom && nos) {
|
if (nom && nos) {
|
||||||
debug( " vanished\n" );
|
debug( " vanished\n" );
|
||||||
/* d.1) d.5) d.6) d.10) d.11) */
|
/* 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]) {
|
} else if (del[1-t]) {
|
||||||
/* c.4) d.9) / b.4) d.4) */
|
/* c.4) d.9) / b.4) d.4) */
|
||||||
debug( " %s vanished\n", str_ms[1-t] );
|
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] );
|
info( "Info: conflicting changes in (%d,%d)\n", srec->uid[M], srec->uid[S] );
|
||||||
if (chan->ops[t] & OP_DELETE) {
|
if (chan->ops[t] & OP_DELETE) {
|
||||||
debug( " -> %s delete\n", str_hl[t] );
|
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_STORE_BAD: ret = SYNC_BAD(t); goto finish;
|
||||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||||
default: /* ok */ break;
|
default: /* ok */ break;
|
||||||
|
@ -621,48 +619,48 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
||||||
srec->uid[1-t] = 0;
|
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) */
|
/* c.1) c.2) d.7) d.8) / b.1) b.2) d.2) d.3) */
|
||||||
;
|
;
|
||||||
else if (srec->uid[t] < 0) {
|
else if (srec->uid[t] < 0) {
|
||||||
/* b.2) / c.2) */
|
/* b.2) / c.2) */
|
||||||
debug( " no %s yet\n", str_ms[t] );
|
debug( " no %s yet\n", str_ms[t] );
|
||||||
if (chan->ops[t] & OP_RENEW) {
|
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] );
|
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 {
|
} 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] );
|
debug( " -> %sing it\n", str_hl[t] );
|
||||||
msgdata.flags = msg[1-t]->flags;
|
msgdata.flags = srec->msg[1-t]->flags;
|
||||||
switch (driver[1-t]->fetch_msg( ctx[1-t], msg[1-t], &msgdata )) {
|
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_STORE_BAD: ret = SYNC_BAD(1-t); goto finish;
|
||||||
case DRV_BOX_BAD: ret = SYNC_FAIL; 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:
|
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 )) {
|
switch (driver[t]->store_msg( ctx[t], &msgdata, &uid )) {
|
||||||
case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
|
case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
|
||||||
default: ret = SYNC_FAIL; goto finish;
|
default: ret = SYNC_FAIL; goto finish;
|
||||||
case DRV_OK:
|
case DRV_OK:
|
||||||
Fprintf( jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], srec->uid[S], uid );
|
Fprintf( jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], srec->uid[S], uid );
|
||||||
srec->uid[t] = uid;
|
srec->uid[t] = uid;
|
||||||
nflags = msg[1-t]->flags;
|
nflags = srec->msg[1-t]->flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug( " -> not %sing - still too big\n", str_hl[t] );
|
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
|
} else
|
||||||
msg[1-t]->status |= M_NOT_SYNCED;
|
srec->msg[1-t]->status |= M_NOT_SYNCED;
|
||||||
} else if (!del[t]) {
|
} else if (!del[t]) {
|
||||||
/* a) & b.3) / c.3) */
|
/* a) & b.3) / c.3) */
|
||||||
debug( " may %s\n", str_hl[t] );
|
debug( " may %s\n", str_hl[t] );
|
||||||
if (chan->ops[t] & OP_FLAGS) {
|
if (chan->ops[t] & OP_FLAGS) {
|
||||||
debug( " -> %sing flags\n", str_hl[t] );
|
debug( " -> %sing flags\n", str_hl[t] );
|
||||||
sflags = msg[1-t]->flags;
|
sflags = srec->msg[1-t]->flags;
|
||||||
aflags = sflags & ~nflags;
|
aflags = sflags & ~nflags;
|
||||||
dflags = ~sflags & nflags;
|
dflags = ~sflags & nflags;
|
||||||
unex = 0;
|
unex = 0;
|
||||||
|
@ -686,7 +684,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
||||||
aflags &= F_DELETED;
|
aflags &= F_DELETED;
|
||||||
dflags = 0;
|
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_STORE_BAD: ret = SYNC_BAD(t); goto finish;
|
||||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||||
default: /* ok */ break;
|
default: /* ok */ break;
|
||||||
|
@ -708,9 +706,9 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
|
||||||
srec->flags = nflags;
|
srec->flags = nflags;
|
||||||
Fprintf( jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], 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);
|
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);
|
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) {
|
for (srec = recs; srec; srec = srec->next) {
|
||||||
if (srec->status & (S_DEAD|S_EXPIRED))
|
if (srec->status & (S_DEAD|S_EXPIRED))
|
||||||
continue;
|
continue;
|
||||||
tmsg = findmsg( ctx[S], srec->uid[S], &nsmsg, "slave" );
|
if (srec->msg[S] && (srec->msg[S]->status & M_EXPIRED)) {
|
||||||
if (tmsg && (tmsg->status & M_EXPIRED)) {
|
|
||||||
debug( " expiring pair(%d,%d)\n", srec->uid[M], srec->uid[S] );
|
debug( " expiring pair(%d,%d)\n", srec->uid[M], srec->uid[S] );
|
||||||
/* log first, so deletion can't be misinterpreted! */
|
/* log first, so deletion can't be misinterpreted! */
|
||||||
Fprintf( jfp, "~ %d %d 1\n", srec->uid[M], srec->uid[S] );
|
Fprintf( jfp, "~ %d %d 1\n", srec->uid[M], srec->uid[S] );
|
||||||
if (smaxxuid < srec->uid[S])
|
if (smaxxuid < srec->uid[S])
|
||||||
smaxxuid = srec->uid[S];
|
smaxxuid = srec->uid[S];
|
||||||
srec->status |= S_EXPIRED;
|
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_STORE_BAD: ret = SYNC_BAD(S); goto finish;
|
||||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||||
default: /* ok */ break;
|
default: /* ok */ break;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user