@@ -8,8 +8,8 @@ import java.io.RandomAccessFile
88import java.net.HttpURLConnection
99import java.net.URI
1010import java.net.URLConnection
11+ import java.nio.channels.OverlappingFileLockException
1112import java.security.MessageDigest
12- import java.util.concurrent.ConcurrentHashMap
1313import java.util.zip.ZipInputStream
1414
1515/* * Nested distributions, under `wrapper/` so CI restores them from its existing cache. */
@@ -23,9 +23,7 @@ private val LAUNCHER_JAR = Regex("gradle-launcher-.*\\.jar")
2323
2424private const val CONNECT_TIMEOUT_MS = 30_000
2525private const val READ_TIMEOUT_MS = 120_000
26-
27- /* * Serializes same-JVM callers before they acquire the cross-process file lock. */
28- private val installMonitors = ConcurrentHashMap <String , Any >()
26+ private const val LOCK_RETRY_DELAY_MS = 100L
2927
3028/* * Provisions [gradleVersion] once in [cacheDir], trying [distributionUris] in order. */
3129internal fun provisionGradleDistribution (
@@ -42,22 +40,35 @@ internal fun provisionGradleDistribution(
4240
4341 installedDistributionRoot(installDir, gradleVersion, marker)?.let { return it }
4442
45- val monitor = installMonitors.computeIfAbsent(installDir.absolutePath) { Any () }
46- synchronized(monitor) {
47- installedDistributionRoot(installDir, gradleVersion, marker)?.let { return it }
48- if (! cacheDir.isDirectory && ! cacheDir.mkdirs()) {
49- throw GradleException (" Could not create Gradle distribution cache: ${cacheDir.absolutePath} " )
50- }
51- RandomAccessFile (File (cacheDir, " gradle-$gradleVersion -bin.lock" ), " rw" ).use { lockFile ->
52- lockFile.channel.lock().use {
53- // Recheck after waiting for the file lock.
54- installedDistributionRoot(installDir, gradleVersion, marker)?.let { return it }
55- install(installDir, marker, gradleVersion, distributionUris, logger)
56- return installedDistributionRoot(installDir, gradleVersion, marker)
57- ? : throw GradleException (
58- " Gradle $gradleVersion was unpacked into ${installDir.absolutePath} but no " +
59- " distribution root could be found in it" ,
60- )
43+ if (! cacheDir.isDirectory && ! cacheDir.mkdirs() && ! cacheDir.isDirectory) {
44+ throw GradleException (" Could not create Gradle distribution cache: ${cacheDir.absolutePath} " )
45+ }
46+ return withDistributionFileLock(File (cacheDir, " gradle-$gradleVersion -bin.lock" )) {
47+ // Recheck after waiting for the file lock.
48+ installedDistributionRoot(installDir, gradleVersion, marker)
49+ ?.let { return @withDistributionFileLock it }
50+ install(installDir, marker, gradleVersion, distributionUris, logger)
51+ installedDistributionRoot(installDir, gradleVersion, marker)
52+ ? : throw GradleException (
53+ " Gradle $gradleVersion was unpacked into ${installDir.absolutePath} but no " +
54+ " distribution root could be found in it" ,
55+ )
56+ }
57+ }
58+
59+ private fun <T > withDistributionFileLock (lockPath : File , action : () -> T ): T {
60+ RandomAccessFile (lockPath, " rw" ).use { lockFile ->
61+ while (true ) {
62+ val lock =
63+ try {
64+ lockFile.channel.lock()
65+ } catch (_: OverlappingFileLockException ) {
66+ // Another caller in this JVM holds the lock.
67+ Thread .sleep(LOCK_RETRY_DELAY_MS )
68+ continue
69+ }
70+ lock.use {
71+ return action()
6172 }
6273 }
6374 }
0 commit comments