mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[threading] IJPL-179848: Treat context elements with different hashcodes in their default string representation as equal
GitOrigin-RevId: 2b9b0a3494d3e5777f45f9dabdd4d2231f56e63a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5fd6813a79
commit
7f548f80e7
@@ -333,9 +333,24 @@ private fun CoroutineContext.joinElementsToString(): String =
|
||||
if (acc.isNotEmpty()) {
|
||||
acc.append(", ")
|
||||
}
|
||||
acc.append(element.toString())
|
||||
acc.append(element.toStringSmart())
|
||||
}.toString()
|
||||
|
||||
/**
|
||||
* Default implementation of [Object.toString] includes hex representation of the object's hash code
|
||||
* This prevents our logic for deduplication, resulting in huge coroutine dumps
|
||||
*/
|
||||
private fun Any.toStringSmart(): String {
|
||||
val baseToString = toString()
|
||||
val hashCodeSuffix = "@" + Integer.toHexString(this.hashCode())
|
||||
return if (baseToString.endsWith(hashCodeSuffix)) {
|
||||
baseToString.substring(0, baseToString.length - hashCodeSuffix.length)
|
||||
}
|
||||
else {
|
||||
return baseToString
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T, R> MutableSet<T>.withElement(elem: T, body: (added: Boolean) -> R): R {
|
||||
val added = add(elem)
|
||||
try {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
package com.intellij.diagnostic
|
||||
|
||||
import com.intellij.platform.util.coroutines.childScope
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.junit5.SystemProperty
|
||||
import kotlinx.coroutines.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
@@ -11,6 +13,8 @@ import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.concurrent.locks.LockSupport
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.coroutines.AbstractCoroutineContextElement
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class CoroutineDumpTest {
|
||||
companion object {
|
||||
@@ -97,4 +101,30 @@ class CoroutineDumpTest {
|
||||
t.join()
|
||||
}
|
||||
}
|
||||
|
||||
private class AnElement : AbstractCoroutineContextElement(Key) {
|
||||
companion object Key : CoroutineContext.Key<AnElement>
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `different instances of the same class with base toString are deduplicated`() = timeoutRunBlocking {
|
||||
val job = Job()
|
||||
repeat(10) {
|
||||
launch(AnElement()) {
|
||||
job.join()
|
||||
}
|
||||
}
|
||||
try {
|
||||
val dumpWithDeduplication = dumpCoroutines(this, stripDump = false, deduplicateTrees = true)!!
|
||||
// because in debug mode, there is CoroutineId which appears in the context and in coroutine names
|
||||
val dumpWithReplacedNumbers = dumpWithDeduplication.replace(Regex("[0-9]+"), "<NUM>").lines()
|
||||
val targetLine = dumpWithReplacedNumbers.find { it.contains("AnElement") }!!
|
||||
// if it was not for CoroutineId, this dump would be deduplicated
|
||||
// here we check that apart from these numbers, nothing blocks the deduplication
|
||||
assert(dumpWithReplacedNumbers.count { it == targetLine } == 10)
|
||||
}
|
||||
finally {
|
||||
job.complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user