소스 검색

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";
 
 	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";

+ 50 - 21
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 );