commit 8bd78b71046cccdafc658c0afa95bf01a72f3498 Author: Oswald Buddenhagen <o...@users.sf.net> Date: Mon Nov 25 20:55:41 2019 +0100
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 | 81 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 58 insertions(+), 28 deletions(-) diff --git a/src/run-tests.pl b/src/run-tests.pl index 5ab27aa..029ba2f 100755 --- a/src/run-tests.pl +++ b/src/run-tests.pl @@ -706,7 +706,7 @@ sub test($$$@) rmtree "master"; 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"); @@ -725,7 +725,8 @@ sub test($$$@) print "Options:\n"; print " [ ".join(", ", map('"'.qm($_).'"', @sfx))." ]\n"; my @nnj = readfile("slave/.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 e43d852..d9f0355 100644 --- a/src/sync.c +++ b/src/sync.c @@ -39,6 +39,8 @@ # define fdatasync fsync #endif +#define JOURNAL_VERSION "3" + channel_conf_t global_conf; channel_conf_t *channels; group_conf_t *groups; @@ -172,6 +174,7 @@ typedef struct { uint newuidval[2]; // UID validity obtained from driver uint newuid[2]; // TUID lookup makes sense only for UIDs >= this uint mmaxxuid; // highest expired UID on master + uint oldmmaxxuid; // highest expired UID on master before this run } sync_vars_t; static void sync_ref( sync_vars_t *svars ) { ++svars->ref_count; } @@ -218,6 +221,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 +237,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, "a" ))) { + 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 ); @@ -605,8 +627,6 @@ clean_strdup( const char *s ) } -#define JOURNAL_VERSION "3" - static int prepare_state( sync_vars_t *svars ) { @@ -684,6 +704,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, "MasterUidValidity %u\nSlaveUidValidity %u\nMaxPulledUid %u\nMaxPushedUid %u\n", svars->uidval[M], svars->uidval[S], svars->maxuid[M], svars->maxuid[S] ); @@ -699,12 +725,13 @@ 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 )) warn( "Warning: cannot commit sync state %s\n", svars->dname ); - else if (unlink( svars->jname )) + else if (svars->jfp && unlink( svars->jname )) warn( "Warning: cannot delete journal %s\n", svars->jname ); } } @@ -1245,18 +1272,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[M] = opts[S] = 0; if (fails) @@ -1514,6 +1529,8 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux jFprintf( svars, "| %u %u\n", svars->uidval[M], svars->uidval[S] ); } + svars->oldmmaxxuid = svars->mmaxxuid; + info( "Synchronizing...\n" ); for (t = 0; t < 2; t++) svars->good_flags[t] = svars->drv[t]->get_supported_flags( svars->ctx[t] ); @@ -1598,7 +1615,9 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux } debug( "synchronizing new entries\n" ); + int any_new[2] = { 0, 0 }; for (t = 0; t < 2; t++) { + uint newmaxuid = svars->newmaxuid[1-t]; for (tmsg = svars->msgs[1-t]; tmsg; tmsg = tmsg->next) { // If we have no srec, the message is always New. If we have a srec: // - message is paired or expired => ignore @@ -1616,7 +1635,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux if (srec ? !srec->uid[t] && (((srec->status & S_PENDING) && (svars->chan->ops[t] & OP_NEW)) || ((srec->status & S_SKIPPED) && (svars->chan->ops[t] & OP_RENEW))) - : svars->newmaxuid[1-t] < tmsg->uid && (svars->chan->ops[t] & OP_NEW)) { + : newmaxuid < tmsg->uid && (svars->chan->ops[t] & OP_NEW)) { debug( "new message %u on %s\n", tmsg->uid, str_ms[1-t] ); if ((svars->chan->ops[t] & OP_EXPUNGE) && (tmsg->flags & F_DELETED)) { debug( " -> not %sing - would be expunged anyway\n", str_hl[t] ); @@ -1647,6 +1666,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux srec->status = S_PENDING; jFprintf( svars, "~ %u %u %u\n", srec->uid[M], srec->uid[S], srec->status ); } + any_new[t] = 1; } else { if (srec->status == S_SKIPPED) { debug( " -> not %sing - still too big\n", str_hl[t] ); @@ -1662,11 +1682,14 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux // actually a result of syncing are also skipped over in subsequent runs // (this only matters when the instant tracking is disturbed by delivery // of new messages while we are syncing). - if (svars->newmaxuid[1-t] < tmsg->uid && (svars->chan->ops[t] & OP_NEW)) - svars->newmaxuid[1-t] = tmsg->uid; + if (newmaxuid < tmsg->uid && (svars->chan->ops[t] & OP_NEW)) + newmaxuid = tmsg->uid; } // This can be done outside the (approximately) idempotent loop. - jFprintf( svars, "N %d %u\n", 1-t, svars->newmaxuid[1-t] ); + if (svars->newmaxuid[1-t] != newmaxuid) { + svars->newmaxuid[1-t] = newmaxuid; + jFprintf( svars, "N %d %u\n", 1-t, newmaxuid ); + } } if ((svars->chan->ops[S] & (OP_NEW|OP_RENEW|OP_FLAGS)) && svars->chan->max_messages) { @@ -1845,12 +1868,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->newuid[t] = svars->drv[t]->get_uidnext( svars->ctx[t] ); - jFprintf( svars, "F %d %u\n", t, svars->newuid[t] ); - svars->new_msgs[t] = svars->msgs[1-t]; + if (any_new[t]) { + svars->newuid[t] = svars->drv[t]->get_uidnext( svars->ctx[t] ); + jFprintf( svars, "F %d %u\n", t, svars->newuid[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; @@ -2221,8 +2248,10 @@ 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. - debug( "max expired uid on master is now %u\n", svars->mmaxxuid ); - jFprintf( svars, "! %u\n", svars->mmaxxuid ); + if (svars->mmaxxuid != svars->oldmmaxxuid) { + debug( "max expired uid on master is now %u\n", svars->mmaxxuid ); + jFprintf( svars, "! %u\n", svars->mmaxxuid ); + } for (t = 0; t < 2; t++) { if (svars->maxuid[t] != svars->newmaxuid[t]) { _______________________________________________ isync-devel mailing list isync-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/isync-devel