isync

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

commit f9fe75602e36878d92c8476ba2a3dac524712e1c
parent ec4b21535fa61caed26c544c82f3e744febb3a15
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Sun, 18 Dec 2016 21:22:52 +0100

don't fetch message size unless necessary

when syncing flags but not re-newing non-fetched messages, there is no
need to query the message size for all messages, as the old ones are
queried only for their flags.

Diffstat:
Msrc/driver.h | 11+++++++----
Msrc/drv_imap.c | 9++++++---
Msrc/drv_maildir.c | 7++++---
Msrc/sync.c | 46++++++++++++++++++++++++++++++++++------------
4 files changed, 51 insertions(+), 22 deletions(-)

diff --git a/src/driver.h b/src/driver.h @@ -74,7 +74,8 @@ typedef struct message { #define OPEN_OLD (1<<0) #define OPEN_NEW (1<<1) #define OPEN_FLAGS (1<<2) -#define OPEN_SIZE (1<<3) +#define OPEN_OLD_SIZE (1<<3) +#define OPEN_NEW_SIZE (1<<4) #define OPEN_EXPUNGE (1<<5) #define OPEN_SETFLAGS (1<<6) #define OPEN_APPEND (1<<7) @@ -205,9 +206,11 @@ struct driver { /* Load the message attributes needed to perform the requested operations. * Consider only messages with UIDs between minuid and maxuid (inclusive) * and those named in the excs array (smaller than minuid). - * The driver takes ownership of the excs array. Messages below newuid do not need - * to have the TUID populated even if OPEN_FIND is set. */ - void (*load_box)( store_t *ctx, int minuid, int maxuid, int newuid, int_array_t excs, + * The driver takes ownership of the excs array. + * Messages starting with newuid need to have the TUID populated when OPEN_FIND is set. + * Messages up to seenuid need to have the size populated when OPEN_OLD_SIZE is set; + * likewise messages above seenuid when OPEN_NEW_SIZE is set. */ + void (*load_box)( store_t *ctx, int minuid, int maxuid, int newuid, int seenuid, int_array_t excs, void (*cb)( int sts, void *aux ), void *aux ); /* Fetch the contents and flags of the given message from the current mailbox. */ diff --git a/src/drv_imap.c b/src/drv_imap.c @@ -2352,7 +2352,7 @@ imap_set_range( imap_range_t *ranges, int *nranges, int low_flags, int high_flag static void imap_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * ); static void -imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t excs, +imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int seenuid, int_array_t excs, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; @@ -2380,11 +2380,14 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t ex if (maxuid == INT_MAX) maxuid = ctx->gen.uidnext ? ctx->gen.uidnext - 1 : 0x7fffffff; if (maxuid >= minuid) { - imap_range_t ranges[2]; + imap_range_t ranges[3]; ranges[0].first = minuid; ranges[0].last = maxuid; - ranges[0].flags = shifted_bit( ctx->gen.opts, OPEN_SIZE, WantSize); + ranges[0].flags = 0; int nranges = 1; + if (ctx->gen.opts & (OPEN_OLD_SIZE | OPEN_NEW_SIZE)) + imap_set_range( ranges, &nranges, shifted_bit( ctx->gen.opts, OPEN_OLD_SIZE, WantSize), + shifted_bit( ctx->gen.opts, OPEN_NEW_SIZE, WantSize), seenuid ); if (ctx->gen.opts & OPEN_FIND) imap_set_range( ranges, &nranges, 0, WantTuids, newuid - 1 ); for (int r = 0; r < nranges; r++) { diff --git a/src/drv_maildir.c b/src/drv_maildir.c @@ -70,7 +70,7 @@ typedef struct maildir_message { typedef struct maildir_store { store_t gen; int uvfd, uvok, nuid, is_inbox, fresh[3]; - int minuid, maxuid, newuid; + int minuid, maxuid, newuid, seenuid; int_array_t excs; char *trash; #ifdef USE_DB @@ -1048,7 +1048,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) free( entry->base ); entry->base = nfstrndup( buf + bl + 4, fnl ); } - int want_size = (ctx->gen.opts & OPEN_SIZE); + int want_size = (uid > ctx->seenuid) ? (ctx->gen.opts & OPEN_NEW_SIZE) : (ctx->gen.opts & OPEN_OLD_SIZE); int want_tuid = ((ctx->gen.opts & OPEN_FIND) && uid >= ctx->newuid); if (!want_size && !want_tuid) continue; @@ -1280,7 +1280,7 @@ maildir_prepare_load_box( store_t *gctx, int opts ) } static void -maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t excs, +maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int seenuid, int_array_t excs, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; @@ -1291,6 +1291,7 @@ maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t ctx->minuid = minuid; ctx->maxuid = maxuid; ctx->newuid = newuid; + ctx->seenuid = seenuid; ARRAY_SQUEEZE( &excs ); ctx->excs = excs; diff --git a/src/sync.c b/src/sync.c @@ -1208,8 +1208,12 @@ box_opened2( sync_vars_t *svars, int t ) opts[1-t] |= OPEN_NEW; if (chan->ops[t] & OP_EXPUNGE) opts[1-t] |= OPEN_FLAGS; - if (chan->stores[t]->max_size != INT_MAX) - opts[1-t] |= OPEN_SIZE; + if (chan->stores[t]->max_size != INT_MAX) { + if (chan->ops[t] & OP_RENEW) + opts[1-t] |= OPEN_OLD_SIZE; + if (chan->ops[t] & OP_NEW) + opts[1-t] |= OPEN_NEW_SIZE; + } } if (chan->ops[t] & OP_EXPUNGE) { opts[t] |= OPEN_EXPUNGE; @@ -1298,28 +1302,46 @@ box_opened2( sync_vars_t *svars, int t ) sync_deref( svars ); } +static int +get_seenuid( sync_vars_t *svars, int t ) +{ + int seenuid = 0; + for (sync_rec_t *srec = svars->srecs; srec; srec = srec->next) + if (!(srec->status & S_DEAD) && seenuid < srec->uid[t]) + seenuid = srec->uid[t]; + return seenuid; +} + static void box_loaded( int sts, void *aux ); static void load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs ) { - sync_rec_t *srec; - int maxwuid; + int maxwuid, seenuid; if (svars->ctx[t]->opts & OPEN_NEW) { if (minwuid > svars->maxuid[t] + 1) minwuid = svars->maxuid[t] + 1; maxwuid = INT_MAX; + if (svars->ctx[t]->opts & OPEN_OLD_SIZE) + seenuid = get_seenuid( svars, t ); + else + seenuid = 0; } else if (svars->ctx[t]->opts & OPEN_OLD) { - maxwuid = 0; - for (srec = svars->srecs; srec; srec = srec->next) - if (!(srec->status & S_DEAD) && srec->uid[t] > maxwuid) - maxwuid = srec->uid[t]; + maxwuid = seenuid = get_seenuid( svars, t ); } else - maxwuid = 0; + maxwuid = seenuid = 0; + if (seenuid < svars->maxuid[t]) { + /* We cannot rely on the maxuid, as uni-directional syncing does not update it. + * But if it is there, use it to avoid a possible gap in the fetched range. */ + seenuid = svars->maxuid[t]; + } info( "Loading %s...\n", str_ms[t] ); - debug( maxwuid == INT_MAX ? "loading %s [%d,inf]\n" : "loading %s [%d,%d]\n", str_ms[t], minwuid, maxwuid ); - svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], mexcs, box_loaded, AUX ); + if (maxwuid == INT_MAX) + debug( "loading %s [%d,inf] (new >= %d, seen <= %d)\n", str_ms[t], minwuid, svars->newuid[t], seenuid ); + else + debug( "loading %s [%d,%d] (new >= %d, seen <= %d)\n", str_ms[t], minwuid, maxwuid, svars->newuid[t], seenuid ); + svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], seenuid, mexcs, box_loaded, AUX ); } typedef struct { @@ -1384,7 +1406,7 @@ box_loaded( int sts, void *aux ) uid = tmsg->uid; if (DFlags & DEBUG_SYNC) { make_flags( tmsg->flags, fbuf ); - printf( svars->ctx[t]->opts & OPEN_SIZE ? " message %5d, %-4s, %6lu: " : " message %5d, %-4s: ", uid, fbuf, tmsg->size ); + printf( tmsg->size ? " message %5d, %-4s, %6lu: " : " message %5d, %-4s: ", uid, fbuf, tmsg->size ); } idx = (uint)((uint)uid * 1103515245U) % hashsz; while (srecmap[idx].uid) {