瀏覽代碼

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.
Oswald Buddenhagen 5 年之前
父節點
當前提交
68a412115a
共有 2 個文件被更改,包括 53 次插入23 次删除
  1. 3 2
      src/run-tests.pl
  2. 50 21
      src/sync.c

+ 3 - 2
src/run-tests.pl

@@ -702,7 +702,7 @@ sub test($$$@)
 	rmtree "far";
 	rmtree "far";
 
 
 	my $njl = (@nj - 1) * 2;
 	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] });
 		mkchan($$sx[0], $$sx[1], @{ $$sx[2] });
 
 
 		my ($nxc, @nret) = runsync("-J$l", "4-interrupt.log");
 		my ($nxc, @nret) = runsync("-J$l", "4-interrupt.log");
@@ -721,7 +721,8 @@ sub test($$$@)
 			print "Options:\n";
 			print "Options:\n";
 			print " [ ".join(", ", map('"'.qm($_).'"', @sfx))." ]\n";
 			print " [ ".join(", ", map('"'.qm($_).'"', @sfx))." ]\n";
 			my @nnj = readfile("near/.mbsyncstate.journal");
 			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";
 			print "Full journal:\n".join("", @nj)."\n";
 			if (!$nxc) {
 			if (!$nxc) {
 				print "Expected result:\n";
 				print "Expected result:\n";

+ 50 - 21
src/sync.c

@@ -39,6 +39,8 @@
 # define fdatasync fsync
 # define fdatasync fsync
 #endif
 #endif
 
 
+#define JOURNAL_VERSION "4"
+
 channel_conf_t global_conf;
 channel_conf_t global_conf;
 channel_conf_t *channels;
 channel_conf_t *channels;
 group_conf_t *groups;
 group_conf_t *groups;
@@ -167,10 +169,12 @@ typedef struct {
 	uint ref_count, nsrecs, opts[2];
 	uint ref_count, nsrecs, opts[2];
 	uint new_pending[2], flags_pending[2], trash_pending[2];
 	uint new_pending[2], flags_pending[2], trash_pending[2];
 	uint maxuid[2];     // highest UID that was already propagated
 	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 uidval[2];     // UID validity value
 	uint newuidval[2];  // UID validity obtained from driver
 	uint newuidval[2];  // UID validity obtained from driver
 	uint finduid[2];    // TUID lookup makes sense only for UIDs >= this
 	uint finduid[2];    // TUID lookup makes sense only for UIDs >= this
 	uint maxxfuid;      // highest expired UID on far side
 	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];
 	uchar good_flags[2], bad_flags[2];
 } sync_vars_t;
 } sync_vars_t;
 
 
@@ -218,6 +222,15 @@ static int check_cancel( sync_vars_t *svars );
 #define ST_SENDING_NEW     (1<<15)
 #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)
 static void ATTR_PRINTFLIKE(2, 3)
 jFprintf( sync_vars_t *svars, const char *msg, ... )
 jFprintf( sync_vars_t *svars, const char *msg, ... )
 {
 {
@@ -225,6 +238,16 @@ jFprintf( sync_vars_t *svars, const char *msg, ... )
 
 
 	if (JLimit && !--JLimit)
 	if (JLimit && !--JLimit)
 		exit( 101 );
 		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 );
 	va_start( va, msg );
 	vFprintf( svars->jfp, msg, va );
 	vFprintf( svars->jfp, msg, va );
 	va_end( va );
 	va_end( va );
@@ -625,8 +648,6 @@ clean_strdup( const char *s )
 }
 }
 
 
 
 
-#define JOURNAL_VERSION "4"
-
 static int
 static int
 prepare_state( sync_vars_t *svars )
 prepare_state( sync_vars_t *svars )
 {
 {
@@ -704,6 +725,12 @@ save_state( sync_vars_t *svars )
 	sync_rec_t *srec;
 	sync_rec_t *srec;
 	char fbuf[16]; /* enlarge when support for keywords is added */
 	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,
 	Fprintf( svars->nfp,
 	         "FarUidValidity %u\nNearUidValidity %u\nMaxPulledUid %u\nMaxPushedUid %u\n",
 	         "FarUidValidity %u\nNearUidValidity %u\nMaxPulledUid %u\nMaxPushedUid %u\n",
 	         svars->uidval[F], svars->uidval[N], svars->maxuid[F], svars->maxuid[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->nfp, 1 );
-	Fclose( svars->jfp, 0 );
+	if (svars->jfp)
+		Fclose( svars->jfp, 0 );
 	if (!(DFlags & KEEPJOURNAL)) {
 	if (!(DFlags & KEEPJOURNAL)) {
 		/* order is important! */
 		/* order is important! */
 		if (rename( svars->nname, svars->dname ))
 		if (rename( svars->nname, svars->dname ))
@@ -1234,18 +1262,6 @@ box_opened2( sync_vars_t *svars, int t )
 
 
 	if (!lock_state( svars ))
 	if (!lock_state( svars ))
 		goto bail;
 		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;
 	opts[F] = opts[N] = 0;
 	if (fails)
 	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" );
 		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" );
 	info( "Synchronizing...\n" );
 	for (t = 0; t < 2; t++)
 	for (t = 0; t < 2; t++)
 		svars->good_flags[t] = (uchar)svars->drv[t]->get_supported_flags( svars->ctx[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" );
 	debug( "synchronizing old entries\n" );
 	for (srec = svars->srecs; srec; srec = srec->next) {
 	for (srec = svars->srecs; srec; srec = srec->next) {
 		if (srec->status & S_DEAD)
 		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;
 					srec->status = S_PENDING;
 					JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "was too big" );
 					JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "was too big" );
 				}
 				}
+				any_new[t] = 1;
 			} else {
 			} else {
 				if (srec->status == S_SKIPPED) {
 				if (srec->status == S_SKIPPED) {
 					debug( "-> still too big\n" );
 					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" );
 	debug( "propagating new messages\n" );
-	if (UseFSync)
+	if (UseFSync && svars->jfp)
 		fdatasync( fileno( svars->jfp ) );
 		fdatasync( fileno( svars->jfp ) );
 	for (t = 0; t < 2; t++) {
 	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 );
 		msgs_copied( svars, t );
 		if (check_cancel( svars ))
 		if (check_cancel( svars ))
 			goto out;
 			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
 		// ensure that all pending messages are still loaded next time in case
 		// of interruption - in particular skipping big messages would otherwise
 		// of interruption - in particular skipping big messages would otherwise
 		// up the limit too early.
 		// 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) {
 	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.
 	// 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
 	// However, doing it before the entry purge would require ensuring that the
 	// exception list includes all relevant messages.
 	// 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 );
 	save_state( svars );