for review: bug fix for concurrent writes to `.d' files

Fergus Henderson fjh at cs.mu.OZ.AU
Sat Feb 28 00:04:35 AEDT 1998


On 27-Feb-1998, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> 	The fix is to write the dependency file to `<foo>.d.tmp' and
> 	then rename the `.d.tmp' to `.d'.  This ensures that the update
> 	to the `.d' file is atomic. 

Well, gee, now we have a concurrent write problem for
the `.d.tmp' files.  Doh!

Obviously we need to use io__tepnam.  Let me try that again. 

[Testing this revised change revealed bugs in io__tmpnam;
I'll commit the fixes for those as a separate change.]

--------------------

Estimated hours taken: 1

compiler/modules.m:
	Fix a bug with parallel makes where the `.d' files were being
	stuffed up because two different invocations of the Mercury
	compiler were writing to them at the same time. 
	The problem occurs because the `.d' file is written out
	both when creating the `.c' file and when creating the
	`.trans_opt' file, and these steps might happen in parallel.

	The fix is to write the dependency file to a unique temporary
	file name and then rename it to the desired `.d' file name when
	we're done.  This ensures that the update to the `.d' file is atomic. 
	[In theory this is not a 100% portable solution, because
	rename() might not be atomic, but in practice it should be
	fine, because rename() is atomic on all the platforms of
	interest (i.e. all the ones that support parallel GNU make).]

	An alternative fix would be to not write out the `.d' files
	when creating `.trans_opt' files.  This would also be more
	efficient.  However, the danger is that the `.d' files might
	not be updated often enough.  I'm not really sure exactly
	how often they need to be updated, but the fix using
	renaming seems safer.

cvs diff  compiler/modules.m
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.56
diff -u -r1.56 modules.m
--- modules.m	1998/02/07 09:55:32	1.56
+++ modules.m	1998/02/27 12:25:19
@@ -509,11 +509,19 @@
 		MaybeTransOptDeps) -->
 	globals__io_lookup_bool_option(verbose, Verbose),
 	{ string__append(ModuleName, ".d", DependencyFileName) },
+	%
+	% To avoid problems with concurrent updates of `.d' files
+	% during parallel makes, we first create the file with a
+	% temporary name, and then rename it to the desired name
+	% when we've finished.
+	%
+	{ dir__dirname(DependencyFileName, DirName) },
+	io__tmpnam(DirName, "tmp_d", TmpDependencyFileName),
 	maybe_write_string(Verbose, "% Writing auto-dependency file `"),
 	maybe_write_string(Verbose, DependencyFileName),
 	maybe_write_string(Verbose, "'..."),
 	maybe_flush_output(Verbose),
-	io__open_output(DependencyFileName, Result),
+	io__open_output(TmpDependencyFileName, Result),
 	( { Result = ok(DepStream) } ->
 		{ set__list_to_set(LongDeps0, LongDepsSet0) },
 		{ set__delete(LongDepsSet0, ModuleName, LongDepsSet) },
@@ -661,10 +669,22 @@
 		]),
 
 		io__close_output(DepStream),
-		maybe_write_string(Verbose, " done.\n")
+		io__remove_file(DependencyFileName, _Result2),
+		io__rename_file(TmpDependencyFileName, DependencyFileName,
+			Result3),
+		( { Result3 = error(Error) } ->
+			{ io__error_message(Error, ErrorMsg) },
+			{ string__append_list(["can't rename file `",
+				TmpDependencyFileName, "' as `",
+				DependencyFileName, "': ", ErrorMsg],
+				Message) },
+			report_error(Message)
+		;
+			maybe_write_string(Verbose, " done.\n")
+		)
 	;
-		{ string__append_list(["can't open file `", DependencyFileName,
-				"' for output."], Message) },
+		{ string__append_list(["can't open file `",
+			TmpDependencyFileName, "' for output."], Message) },
 		report_error(Message)
 	).
 

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list