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

Reply via email to