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.
This commit is contained in:
Oswald Buddenhagen 2016-12-18 21:22:52 +01:00
parent ec4b21535f
commit f9fe75602e
4 changed files with 51 additions and 22 deletions

View File

@ -74,7 +74,8 @@ typedef struct message {
#define OPEN_OLD (1<<0) #define OPEN_OLD (1<<0)
#define OPEN_NEW (1<<1) #define OPEN_NEW (1<<1)
#define OPEN_FLAGS (1<<2) #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_EXPUNGE (1<<5)
#define OPEN_SETFLAGS (1<<6) #define OPEN_SETFLAGS (1<<6)
#define OPEN_APPEND (1<<7) #define OPEN_APPEND (1<<7)
@ -205,9 +206,11 @@ struct driver {
/* Load the message attributes needed to perform the requested operations. /* Load the message attributes needed to perform the requested operations.
* Consider only messages with UIDs between minuid and maxuid (inclusive) * Consider only messages with UIDs between minuid and maxuid (inclusive)
* and those named in the excs array (smaller than minuid). * and those named in the excs array (smaller than minuid).
* The driver takes ownership of the excs array. Messages below newuid do not need * The driver takes ownership of the excs array.
* to have the TUID populated even if OPEN_FIND is set. */ * Messages starting with newuid need to have the TUID populated when OPEN_FIND is set.
void (*load_box)( store_t *ctx, int minuid, int maxuid, int newuid, int_array_t excs, * 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 ); void (*cb)( int sts, void *aux ), void *aux );
/* Fetch the contents and flags of the given message from the current mailbox. */ /* Fetch the contents and flags of the given message from the current mailbox. */

View File

@ -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_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * );
static void 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 ) void (*cb)( int sts, void *aux ), void *aux )
{ {
imap_store_t *ctx = (imap_store_t *)gctx; 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) if (maxuid == INT_MAX)
maxuid = ctx->gen.uidnext ? ctx->gen.uidnext - 1 : 0x7fffffff; maxuid = ctx->gen.uidnext ? ctx->gen.uidnext - 1 : 0x7fffffff;
if (maxuid >= minuid) { if (maxuid >= minuid) {
imap_range_t ranges[2]; imap_range_t ranges[3];
ranges[0].first = minuid; ranges[0].first = minuid;
ranges[0].last = maxuid; ranges[0].last = maxuid;
ranges[0].flags = shifted_bit( ctx->gen.opts, OPEN_SIZE, WantSize); ranges[0].flags = 0;
int nranges = 1; 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) if (ctx->gen.opts & OPEN_FIND)
imap_set_range( ranges, &nranges, 0, WantTuids, newuid - 1 ); imap_set_range( ranges, &nranges, 0, WantTuids, newuid - 1 );
for (int r = 0; r < nranges; r++) { for (int r = 0; r < nranges; r++) {

View File

@ -70,7 +70,7 @@ typedef struct maildir_message {
typedef struct maildir_store { typedef struct maildir_store {
store_t gen; store_t gen;
int uvfd, uvok, nuid, is_inbox, fresh[3]; int uvfd, uvok, nuid, is_inbox, fresh[3];
int minuid, maxuid, newuid; int minuid, maxuid, newuid, seenuid;
int_array_t excs; int_array_t excs;
char *trash; char *trash;
#ifdef USE_DB #ifdef USE_DB
@ -1048,7 +1048,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist )
free( entry->base ); free( entry->base );
entry->base = nfstrndup( buf + bl + 4, fnl ); 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); int want_tuid = ((ctx->gen.opts & OPEN_FIND) && uid >= ctx->newuid);
if (!want_size && !want_tuid) if (!want_size && !want_tuid)
continue; continue;
@ -1280,7 +1280,7 @@ maildir_prepare_load_box( store_t *gctx, int opts )
} }
static void 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 ) void (*cb)( int sts, void *aux ), void *aux )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx; 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->minuid = minuid;
ctx->maxuid = maxuid; ctx->maxuid = maxuid;
ctx->newuid = newuid; ctx->newuid = newuid;
ctx->seenuid = seenuid;
ARRAY_SQUEEZE( &excs ); ARRAY_SQUEEZE( &excs );
ctx->excs = excs; ctx->excs = excs;

View File

@ -1208,8 +1208,12 @@ box_opened2( sync_vars_t *svars, int t )
opts[1-t] |= OPEN_NEW; opts[1-t] |= OPEN_NEW;
if (chan->ops[t] & OP_EXPUNGE) if (chan->ops[t] & OP_EXPUNGE)
opts[1-t] |= OPEN_FLAGS; opts[1-t] |= OPEN_FLAGS;
if (chan->stores[t]->max_size != INT_MAX) if (chan->stores[t]->max_size != INT_MAX) {
opts[1-t] |= OPEN_SIZE; 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) { if (chan->ops[t] & OP_EXPUNGE) {
opts[t] |= OPEN_EXPUNGE; opts[t] |= OPEN_EXPUNGE;
@ -1298,28 +1302,46 @@ box_opened2( sync_vars_t *svars, int t )
sync_deref( svars ); 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 box_loaded( int sts, void *aux );
static void static void
load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs ) load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs )
{ {
sync_rec_t *srec; int maxwuid, seenuid;
int maxwuid;
if (svars->ctx[t]->opts & OPEN_NEW) { if (svars->ctx[t]->opts & OPEN_NEW) {
if (minwuid > svars->maxuid[t] + 1) if (minwuid > svars->maxuid[t] + 1)
minwuid = svars->maxuid[t] + 1; minwuid = svars->maxuid[t] + 1;
maxwuid = INT_MAX; 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) { } else if (svars->ctx[t]->opts & OPEN_OLD) {
maxwuid = 0; maxwuid = seenuid = get_seenuid( svars, t );
for (srec = svars->srecs; srec; srec = srec->next)
if (!(srec->status & S_DEAD) && srec->uid[t] > maxwuid)
maxwuid = srec->uid[t];
} else } 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] ); 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 ); if (maxwuid == INT_MAX)
svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], mexcs, box_loaded, AUX ); 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 { typedef struct {
@ -1384,7 +1406,7 @@ box_loaded( int sts, void *aux )
uid = tmsg->uid; uid = tmsg->uid;
if (DFlags & DEBUG_SYNC) { if (DFlags & DEBUG_SYNC) {
make_flags( tmsg->flags, fbuf ); 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; idx = (uint)((uint)uid * 1103515245U) % hashsz;
while (srecmap[idx].uid) { while (srecmap[idx].uid) {