From 2243838a1b5645295730e5f3f83ce71248fc55b5 Mon Sep 17 00:00:00 2001
From: Takafumi Arakaki <aka.tkf@gmail.com>
Date: Tue, 27 Nov 2018 22:53:28 -0800
Subject: [PATCH 1/4] Make compilecache atomic

Previously, the cache path is directly passed to the --output-ji
option of the subprocess for generating compile cache.  However, when
several processes are compiling the same package, one process may
modify the file while another process is calculating the checksum,
yielding a broken cache.  This patch let each process create a cache
in a private temporary path and then atomically rename it to the final
cache path.
---
 base/loading.jl | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/base/loading.jl b/base/loading.jl
index b68d005f53a8c..ce95387cce473 100644
--- a/base/loading.jl
+++ b/base/loading.jl
@@ -1185,18 +1185,31 @@ function compilecache(pkg::PkgId, path::String)
     else
         @logmsg verbosity "Precompiling $pkg"
     end
-    p = create_expr_cache(path, cachefile, concrete_deps, pkg.uuid)
-    if success(p)
-        # append checksum to the end of the .ji file:
-        open(cachefile, "a+") do f
-            write(f, _crc32c(seekstart(f)))
+    # create a temporary file in `cachepath` directory, write the cache in it,
+    # write the checksum, _and then_ atomically swap the file with `cachefile`.
+    tmppath, tmpio = mktemp(cachepath)
+    local p
+    try
+        close(tmpio)
+        p = create_expr_cache(path, tmppath, concrete_deps, pkg.uuid)
+        if success(p)
+            # append checksum to the end of the .ji file:
+            open(tmppath, "a+") do f
+                write(f, _crc32c(seekstart(f)))
+            end
+            # this is atomic according to POSIX:
+            rename(tmppath, cachefile)
+            return cachefile
         end
-    elseif p.exitcode == 125
+    finally
+        # not using `mktemp() do ...` to pass `force=true` to `rm`
+        rm(tmppath, force=true)
+    end
+    if p.exitcode == 125
         return PrecompilableError()
     else
         error("Failed to precompile $pkg to $cachefile.")
     end
-    return cachefile
 end
 
 module_build_id(m::Module) = ccall(:jl_module_build_id, UInt64, (Any,), m)

From d367552467ab108588b22bdfb77d8e0fd558f45c Mon Sep 17 00:00:00 2001
From: Takafumi Arakaki <aka.tkf@gmail.com>
Date: Wed, 28 Nov 2018 18:04:24 -0800
Subject: [PATCH 2/4] Tweak comment [no ci]

---
 base/loading.jl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/base/loading.jl b/base/loading.jl
index ce95387cce473..aa60adf8cb4e1 100644
--- a/base/loading.jl
+++ b/base/loading.jl
@@ -1186,7 +1186,7 @@ function compilecache(pkg::PkgId, path::String)
         @logmsg verbosity "Precompiling $pkg"
     end
     # create a temporary file in `cachepath` directory, write the cache in it,
-    # write the checksum, _and then_ atomically swap the file with `cachefile`.
+    # write the checksum, _and then_ atomically move the file to `cachefile`.
     tmppath, tmpio = mktemp(cachepath)
     local p
     try

From b40b7264eeabd8c21d424354575dbfb88cc8ac8c Mon Sep 17 00:00:00 2001
From: Takafumi Arakaki <aka.tkf@gmail.com>
Date: Thu, 29 Nov 2018 19:50:10 -0800
Subject: [PATCH 3/4] Add NEWS and FAQ [skip ci]

---
 NEWS.md               |  3 +++
 doc/src/manual/faq.md | 16 ++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/NEWS.md b/NEWS.md
index 368b3fbe7e0cc..b9160111e6d27 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -18,6 +18,9 @@ Language changes
     Previously they were sometimes parsed as tuples, depending on whitespace ([#28506]).
   * `Regex` now behaves like a scalar when used in broadcasting ([#29913]).
   * `Char` now behaves like a read-only 0-dimensional array ([#29819]).
+  * Precompilation cache files are now created atomically ([#30174]).  Note that
+    invoking _n_ `julia` processes simultaneously may creates _n_ temporary
+    copies of cache files.
 
 New library functions
 ---------------------
diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md
index e6ae749fd1b5a..01cab373fe29f 100644
--- a/doc/src/manual/faq.md
+++ b/doc/src/manual/faq.md
@@ -834,6 +834,22 @@ a scalar can participate in linear algebra operations such as `2 * rand(2,2)`,
 but the analogous operation with a zero-dimensional array
 `fill(2) * rand(2,2)` is an error.
 
+## Computing cluster
+
+### How do I manage precompilation cache files in distributed file systems?
+
+When using `julia` in high-performance computing (HPC) facilities, invoking
+_n_ `julia` processes simultaneously creates at most _n_ temporary copies of
+cache files.  It may become a major issue in slow and/or small distributed
+file systems.  There are a few possible workarounds:
+
+1. Use `julia` with `--compilecache=no` flag to turn off precompilation.
+2. Configure a private writable depot using `pushfirst!(DEPOT_PATH, private_path)`
+   where `private_path` is a path unique to this `julia` process.  This
+   can also be done by setting environment variable `JULIA_DEPOT_PATH` to
+   `$private_path:$HOME/.julia`.
+3. Create a symlink from `~/.julia/compiled` to a directory in a scratch space.
+
 ## Julia Releases
 
 ### Do I want to use a release, beta, or nightly version of Julia?

From 9844c1e36f22c60a95b89ddda9f338e665e37e0f Mon Sep 17 00:00:00 2001
From: Takafumi Arakaki <takafumi.a@gmail.com>
Date: Fri, 21 Jun 2019 23:56:26 -0700
Subject: [PATCH 4/4] Update NEWS.md

Co-Authored-By: Charles Kawczynski <charliekawczynski@gmail.com>
---
 NEWS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/NEWS.md b/NEWS.md
index 1090e4724e84b..0deb5ebd87f65 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -21,7 +21,7 @@ Language changes
   * Using the same name for both a local variable and a static parameter is now an error instead
     of a warning ([#29429]).
   * Precompilation cache files are now created atomically ([#30174]).  Note that
-    invoking _n_ `julia` processes simultaneously may creates _n_ temporary
+    invoking _n_ `julia` processes simultaneously may create _n_ temporary
     copies of cache files.
 
 New library functions