From 68a412115a75223fb9561f0a467970d2a4af65bf Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 25 Nov 2019 20:55:41 +0100 Subject: [PATCH] don't rewrite state gratuitously delay the creation of the new state and journal until there is actually something interesting to write. this saves some cpu cycles and prolongs ssd life a whee bit. --- src/run-tests.pl | 5 ++-- src/sync.c | 71 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/run-tests.pl b/src/run-tests.pl index 1033407..4b936d9 100755 --- a/src/run-tests.pl +++ b/src/run-tests.pl @@ -702,7 +702,7 @@ sub test($$$@) rmtree "far"; my $njl = (@nj - 1) * 2; - for (my $l = 2; $l < $njl; $l++) { + for (my $l = 1; $l <= $njl; $l++) { mkchan($$sx[0], $$sx[1], @{ $$sx[2] }); my ($nxc, @nret) = runsync("-J$l", "4-interrupt.log"); @@ -721,7 +721,8 @@ sub test($$$@) print "Options:\n"; print " [ ".join(", ", map('"'.qm($_).'"', @sfx))." ]\n"; my @nnj = readfile("near/.mbsyncstate.journal"); - print "Journal:\n".join("", @nnj[0..($l / 2 - 1)])."-------\n".join("", @nnj[($l / 2)..$#nnj])."\n"; + my $ln = int($l / 2); + print "Journal:\n".join("", @nnj[0..$ln])."-------\n".join("", @nnj[($ln + 1)..$#nnj])."\n"; print "Full journal:\n".join("", @nj)."\n"; if (!$nxc) { print "Expected result:\n"; diff --git a/src/sync.c b/src/sync.c index 8dbdc62..f191e68 100644 --- a/src/sync.c +++ b/src/sync.c @@ -39,6 +39,8 @@ # define fdatasync fsync #endif +#define JOURNAL_VERSION "4" + channel_conf_t global_conf; channel_conf_t *channels; group_conf_t *groups; @@ -167,10 +169,12 @@ typedef struct { uint ref_count, nsrecs, opts[2]; uint new_pending[2], flags_pending[2], trash_pending[2]; uint maxuid[2]; // highest UID that was already propagated + uint oldmaxuid[2]; // highest UID that was already propagated before this run uint uidval[2]; // UID validity value uint newuidval[2]; // UID validity obtained from driver uint finduid[2]; // TUID lookup makes sense only for UIDs >= this uint maxxfuid; // highest expired UID on far side + uint oldmaxxfuid; // highest expired UID on far side before this run uchar good_flags[2], bad_flags[2]; } sync_vars_t; @@ -218,6 +222,15 @@ static int check_cancel( sync_vars_t *svars ); #define ST_SENDING_NEW (1<<15) +static void +create_state( sync_vars_t *svars ) +{ + if (!(svars->nfp = fopen( svars->nname, "w" ))) { + sys_error( "Error: cannot create new sync state %s", svars->nname ); + exit( 1 ); + } +} + static void ATTR_PRINTFLIKE(2, 3) jFprintf( sync_vars_t *svars, const char *msg, ... ) { @@ -225,6 +238,16 @@ jFprintf( sync_vars_t *svars, const char *msg, ... ) if (JLimit && !--JLimit) exit( 101 ); + if (!svars->jfp) { + create_state( svars ); + if (!(svars->jfp = fopen( svars->jname, svars->replayed ? "a" : "w" ))) { + sys_error( "Error: cannot create journal %s", svars->jname ); + exit( 1 ); + } + setlinebuf( svars->jfp ); + if (!svars->replayed) + Fprintf( svars->jfp, JOURNAL_VERSION "\n" ); + } va_start( va, msg ); vFprintf( svars->jfp, msg, va ); va_end( va ); @@ -625,8 +648,6 @@ clean_strdup( const char *s ) } -#define JOURNAL_VERSION "4" - static int prepare_state( sync_vars_t *svars ) { @@ -704,6 +725,12 @@ save_state( sync_vars_t *svars ) sync_rec_t *srec; char fbuf[16]; /* enlarge when support for keywords is added */ + // If no change was made, the state is also unmodified. + if (!svars->jfp && !svars->replayed) + return; + + if (!svars->nfp) + create_state( svars ); Fprintf( svars->nfp, "FarUidValidity %u\nNearUidValidity %u\nMaxPulledUid %u\nMaxPushedUid %u\n", svars->uidval[F], svars->uidval[N], svars->maxuid[F], svars->maxuid[N] ); @@ -719,7 +746,8 @@ save_state( sync_vars_t *svars ) } Fclose( svars->nfp, 1 ); - Fclose( svars->jfp, 0 ); + if (svars->jfp) + Fclose( svars->jfp, 0 ); if (!(DFlags & KEEPJOURNAL)) { /* order is important! */ if (rename( svars->nname, svars->dname )) @@ -1234,18 +1262,6 @@ box_opened2( sync_vars_t *svars, int t ) if (!lock_state( svars )) goto bail; - if (!(svars->nfp = fopen( svars->nname, "w" ))) { - sys_error( "Error: cannot create new sync state %s", svars->nname ); - goto bail; - } - if (!(svars->jfp = fopen( svars->jname, "a" ))) { - sys_error( "Error: cannot create journal %s", svars->jname ); - fclose( svars->nfp ); - goto bail; - } - setlinebuf( svars->jfp ); - if (!svars->replayed) - jFprintf( svars, JOURNAL_VERSION "\n" ); opts[F] = opts[N] = 0; if (fails) @@ -1495,10 +1511,16 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux JLOG( "| %u %u", (svars->uidval[F], svars->uidval[N]), "new UIDVALIDITYs" ); } + svars->oldmaxuid[F] = svars->maxuid[F]; + svars->oldmaxuid[N] = svars->maxuid[N]; + svars->oldmaxxfuid = svars->maxxfuid; + info( "Synchronizing...\n" ); for (t = 0; t < 2; t++) svars->good_flags[t] = (uchar)svars->drv[t]->get_supported_flags( svars->ctx[t] ); + int any_new[2] = { 0, 0 }; + debug( "synchronizing old entries\n" ); for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) @@ -1643,6 +1665,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux srec->status = S_PENDING; JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "was too big" ); } + any_new[t] = 1; } else { if (srec->status == S_SKIPPED) { debug( "-> still too big\n" ); @@ -1825,12 +1848,16 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux } debug( "propagating new messages\n" ); - if (UseFSync) + if (UseFSync && svars->jfp) fdatasync( fileno( svars->jfp ) ); for (t = 0; t < 2; t++) { - svars->finduid[t] = svars->drv[t]->get_uidnext( svars->ctx[t] ); - JLOG( "F %d %u", (t, svars->finduid[t]), "save UIDNEXT of %s", str_fn[t] ); - svars->new_msgs[t] = svars->msgs[1-t]; + if (any_new[t]) { + svars->finduid[t] = svars->drv[t]->get_uidnext( svars->ctx[t] ); + JLOG( "F %d %u", (t, svars->finduid[t]), "save UIDNEXT of %s", str_fn[t] ); + svars->new_msgs[t] = svars->msgs[1-t]; + } else { + svars->state[t] |= ST_SENT_NEW; + } msgs_copied( svars, t ); if (check_cancel( svars )) goto out; @@ -2164,7 +2191,8 @@ box_closed_p2( sync_vars_t *svars, int t ) // ensure that all pending messages are still loaded next time in case // of interruption - in particular skipping big messages would otherwise // up the limit too early. - JLOG( "N %d %u", (t, svars->maxuid[t]), "up maxuid of %s", str_fn[t] ); + if (svars->maxuid[t] != svars->oldmaxuid[t]) + JLOG( "N %d %u", (t, svars->maxuid[t]), "up maxuid of %s", str_fn[t] ); } if (((svars->state[F] | svars->state[N]) & ST_DID_EXPUNGE) || svars->chan->max_messages) { @@ -2191,7 +2219,8 @@ box_closed_p2( sync_vars_t *svars, int t ) // This is just an optimization, so it needs no journaling of intermediate states. // However, doing it before the entry purge would require ensuring that the // exception list includes all relevant messages. - JLOG( "! %u", svars->maxxfuid, "max expired UID on far side" ); + if (svars->maxxfuid != svars->oldmaxxfuid) + JLOG( "! %u", svars->maxxfuid, "max expired UID on far side" ); save_state( svars );