[ccache] patch: workaround for NFS issues

John Coiner john.coiner at amd.com
Sat Mar 24 21:19:16 GMT 2007


Here is a second attempt at an NFS workaround.

This patch applies to ccache-2.4. The CCACHE_NFS_WORKAROUND variable 
enables the workaround. This workaround requires the existence of the 
"lockfile" program on the $PATH.

Here's what I think is going on, when NFS corruption occurs:

  * Process X writes object A into the cache.
  * Process Y starts reading object A.
  * Process Z writes a new copy of object A into the cache, renaming 
over the original A, while Y is still reading.

A local filesystem will keep the original object A around until Y closes 
the file. But on NFS, which is a stateless protocol, the server 
immediately forgets that the original A ever existed. When process Y 
comes back requesting the next chunk of the original A, it is gone.

This patch prevents overwriting an object that's already in the cache. 
It seems to work, YMMV.

- John



diff -u ccache-2.4/ccache.c ccache-2.4-fix/ccache.c
--- ccache-2.4/ccache.c	Mon Sep 13 06:38:30 2004
+++ ccache-2.4-fix/ccache.c	Sat Mar 24 15:43:45 2007
@@ -158,6 +158,30 @@
  	struct stat st1, st2;
  	int status;

+	char *workaround = getenv("CCACHE_NFS_WORKAROUND");
+	char *lockfile, *lock_cmd;
+	struct stat st;
+
+	if( workaround )
+	{
+	    /* acquire lock -- permission to create the cache entry. */
+	    x_asprintf( &lockfile, "%s.lock", hashname );
+	    x_asprintf( &lock_cmd, "lockfile -l 600 %s", lockfile );
+	    if( 0 != system( lock_cmd ) )
+	    {
+		cc_log( "failed to get lockfile %s\n", lockfile );
+		failed();
+	    }
+
+	    /* got lock -- is the file there now? */
+	    if( stat( hashname, &st ) == 0 )
+	    {
+		/* another ccache process built it. Just return. */
+		unlink( lockfile );
+		return;
+	    }
+	}
+
  	x_asprintf(&tmp_stdout, "%s/tmp.stdout.%s", temp_dir, tmp_string());
  	x_asprintf(&tmp_stderr, "%s/tmp.stderr.%s", temp_dir, tmp_string());
  	x_asprintf(&tmp_hashname, "%s/tmp.hash.%s.o", temp_dir, tmp_string());
@@ -187,6 +211,8 @@
  		unlink(tmp_stdout);
  		unlink(tmp_stderr);
  		unlink(tmp_hashname);
+		if( workaround )
+		    unlink(lockfile);
  		failed();
  	}
  	unlink(tmp_stdout);
@@ -196,6 +222,9 @@
  		cc_log("compile of %s gave status = %d\n", output_file, status);
  		stats_update(STATS_STATUS);

+		if( workaround )
+		    unlink( lockfile );
+
  		fd = open(tmp_stderr, O_RDONLY | O_BINARY);
  		if (fd != -1) {
  			if (strcmp(output_file, "/dev/null") == 0 ||
@@ -236,11 +265,20 @@
  	    rename(tmp_stderr, path_stderr) != 0) {
  		cc_log("failed to rename tmp files - %s\n", strerror(errno));
  		stats_update(STATS_ERROR);
+		if( workaround )
+		    unlink( lockfile );
  		failed();
  	}

  	cc_log("Placed %s into cache\n", output_file);
  	stats_tocache(file_size(&st1) + file_size(&st2));
+
+	if( workaround )
+	{
+	    unlink( lockfile );
+	    free( lockfile );
+	    free( lock_cmd );
+	}

  	free(tmp_hashname);
  	free(tmp_stderr);




More information about the ccache mailing list