[MPP] NativeDistributionCommonizerLock: Support classpath isolation
^KT-56510 Verification Pending
This commit is contained in:
committed by
Space Team
parent
ec67131d82
commit
1936efed11
+33
-2
@@ -7,10 +7,13 @@ package org.jetbrains.kotlin.gradle.targets.native.internal
|
|||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
import java.nio.channels.FileChannel
|
||||||
|
import java.nio.channels.FileLock
|
||||||
|
import java.nio.channels.OverlappingFileLockException
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import kotlin.concurrent.withLock
|
import kotlin.concurrent.withLock
|
||||||
|
|
||||||
internal class NativeDistributionCommonizerLock(
|
internal class NativeDistributionCommonizerLock @JvmOverloads constructor(
|
||||||
private val outputDirectory: File,
|
private val outputDirectory: File,
|
||||||
private val logInfo: (message: String) -> Unit = {}
|
private val logInfo: (message: String) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
@@ -32,7 +35,7 @@ internal class NativeDistributionCommonizerLock(
|
|||||||
outputDirectory.mkdirs()
|
outputDirectory.mkdirs()
|
||||||
logInfo("Acquire lock: ${lockFile.path} ...")
|
logInfo("Acquire lock: ${lockFile.path} ...")
|
||||||
FileOutputStream(outputDirectory.resolve(".lock")).use { stream ->
|
FileOutputStream(outputDirectory.resolve(".lock")).use { stream ->
|
||||||
val lock = stream.channel.lock()
|
val lock: FileLock = stream.channel.lockWithRetries(lockFile)
|
||||||
assert(lock.isValid)
|
assert(lock.isValid)
|
||||||
return try {
|
return try {
|
||||||
logInfo("Lock acquired: ${lockFile.path}")
|
logInfo("Lock acquired: ${lockFile.path}")
|
||||||
@@ -47,6 +50,34 @@ internal class NativeDistributionCommonizerLock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun FileChannel.lockWithRetries(file: File): FileLock {
|
||||||
|
var retries = 0
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
return lock()
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Catching the OverlappingFileLockException which is caused by the same jvm (process) already having locked the file.
|
||||||
|
Since we do use a static re-entrant lock as a monitor to the cache, this can only happen
|
||||||
|
when this code is running in the same JVM but with in complete isolation
|
||||||
|
(e.g. Gradle classpath isolation, or composite builds).
|
||||||
|
|
||||||
|
If we detect this case, we retry the locking after a short period, constantly logging that we're blocked
|
||||||
|
by some other thread using the cache.
|
||||||
|
|
||||||
|
The risk of deadlocking here is low, since we can only get into this code path, *if*
|
||||||
|
the code is very isolated and somebody locked the file.
|
||||||
|
*/
|
||||||
|
catch (t: OverlappingFileLockException) {
|
||||||
|
Thread.sleep(25)
|
||||||
|
retries++
|
||||||
|
if (retries % 10 == 0) {
|
||||||
|
logInfo("Waiting to acquire lock: $file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun checkLocked(outputDirectory: File) {
|
fun checkLocked(outputDirectory: File) {
|
||||||
check(intraProcessLock.isHeldByCurrentThread) {
|
check(intraProcessLock.isHeldByCurrentThread) {
|
||||||
"Expected lock to be held by current thread ${Thread.currentThread().name}"
|
"Expected lock to be held by current thread ${Thread.currentThread().name}"
|
||||||
|
|||||||
Reference in New Issue
Block a user