@@ -185,6 +185,10 @@ module Version = struct
185
185
186
186
let bin_dir t = Path.Outside_build_dir. relative (target_dir t) " bin"
187
187
let is_installed t = Path. exists (Path. outside_build_dir (target_dir t))
188
+
189
+ let flock_path t =
190
+ Path.Outside_build_dir. relative (toolchain_dir t) " lock" |> Path. outside_build_dir
191
+ ;;
188
192
end
189
193
190
194
let handle_checksum_mismatch { Compiler_package. version; url; checksum } ~got_checksum =
@@ -289,18 +293,17 @@ let get ~log version =
289
293
| `Never -> ()
290
294
| _ -> User_message. print (User_message. make [ Pp. tag style pp ])
291
295
in
292
- if Version. is_installed version
293
- then (
294
- (match log with
295
- | `Always ->
296
- log_print Success
297
- @@ Pp. textf
298
- " Version %s of the compiler toolchain is already installed in %s"
299
- (Version. to_string version)
300
- (Version. target_dir version |> Path.Outside_build_dir. to_string)
301
- | _ -> () );
302
- Fiber. return () )
303
- else (
296
+ let print_already_installed_message () =
297
+ match log with
298
+ | `Always ->
299
+ log_print Success
300
+ @@ Pp. textf
301
+ " Version %s of the compiler toolchain is already installed in %s"
302
+ (Version. to_string version)
303
+ (Version. target_dir version |> Path.Outside_build_dir. to_string)
304
+ | _ -> ()
305
+ in
306
+ let download_build_install () =
304
307
let compiler_package = Compiler_package. of_version version in
305
308
log_print Details
306
309
@@ Pp. textf
@@ -319,5 +322,40 @@ let get ~log version =
319
322
@@ Pp. textf
320
323
" Success! Compiler toolchain version %s installed to %s."
321
324
(Version. to_string version)
322
- (Version. target_dir version |> Path.Outside_build_dir. to_string))
325
+ (Version. target_dir version |> Path.Outside_build_dir. to_string)
326
+ in
327
+ if Version. is_installed version
328
+ then (
329
+ print_already_installed_message () ;
330
+ Fiber. return () )
331
+ else
332
+ Flock. with_flock
333
+ (Version. flock_path version)
334
+ ~name_for_messages: (sprintf " toolchain version %s" (Version. to_string version))
335
+ ~timeout_s: infinity
336
+ ~f: (fun () ->
337
+ (* Note that we deliberately check if the toolchain is
338
+ installed before and after taking the flock.
339
+
340
+ The first check prevents us from trying to take the lock if
341
+ the toolchain is installed. To build any package dune first
342
+ checks if the necessary toolchain is installed, so to build
343
+ a project with many dependencies, dune will check if the
344
+ toolchain is installed many times. If this check required
345
+ first taking a lock, multiple concurrent dune instances
346
+ would sometimes contest the lock. This isn't too bad for
347
+ performance as the lock is only held briefly, but when dune
348
+ waits on a flock it prints a message, so freqeunt, brief
349
+ lock acquisitions can lead to a lot of noise in the
350
+ output.
351
+
352
+ The second check is to handle the case where the toolchain
353
+ was installed in between the first check, and the flock
354
+ being acquired.
355
+ *)
356
+ if Version. is_installed version
357
+ then (
358
+ print_already_installed_message () ;
359
+ Fiber. return () )
360
+ else download_build_install () )
323
361
;;
0 commit comments