Improve ExceptionCollector.collect for better performance, close #1308

This commit is contained in:
Him188 2021-06-06 18:26:16 +08:00
parent ef439f1dea
commit 71b128b06c
2 changed files with 22 additions and 25 deletions

View File

@ -12,9 +12,7 @@ package net.mamoe.mirai.utils
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
public class ExceptionCollector : Sequence<Throwable> { public class ExceptionCollector {
// TODO: 2021/4/20 drop last
public constructor() public constructor()
public constructor(initial: Throwable?) { public constructor(initial: Throwable?) {
@ -29,20 +27,14 @@ public class ExceptionCollector : Sequence<Throwable> {
@Volatile @Volatile
private var last: Throwable? = null private var last: Throwable? = null
private val hashCodes = mutableSetOf<Int>()
@Synchronized @Synchronized
public fun collect(e: Throwable?) { public fun collect(e: Throwable?) {
if (e == null) return if (e == null) return
val last = last val hashCode = e.stackTrace.contentHashCode()
if (last != null) { if (!hashCodes.add(hashCode)) return // filter out duplications
last.itr().forEach { suppressed -> // we can also check suppressed exceptions of [e] but actual influence would be slight.
if (suppressed.stackTrace.contentEquals(e.stackTrace)) {
// filter out useless duplicates.
return
}
}
e.addSuppressed(last)
}
this.last = e this.last = e
} }
@ -72,14 +64,18 @@ public class ExceptionCollector : Sequence<Throwable> {
@DslMarker @DslMarker
private annotation class TerminalOperation private annotation class TerminalOperation
private fun Throwable.itr(): Iterator<Throwable> { @TestOnly
return (sequenceOf(this) + this.suppressed.asSequence().flatMap { it.itr().asSequence() }).iterator() public fun asSequence(): Sequence<Throwable> {
fun Throwable.itr(): Iterator<Throwable> {
return (sequenceOf(this) + this.suppressed.asSequence().flatMap { it.itr().asSequence() }).iterator()
}
return Sequence {
val last = getLast() ?: return@Sequence emptyList<Throwable>().iterator()
last.itr()
}
} }
override fun iterator(): Iterator<Throwable> {
val last = getLast() ?: return emptyList<Throwable>().iterator()
return last.itr()
}
} }
/** /**

View File

@ -14,6 +14,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertSame import kotlin.test.assertSame
import kotlin.test.assertTrue import kotlin.test.assertTrue
@OptIn(TestOnly::class)
internal class ExceptionCollectorTest { internal class ExceptionCollectorTest {
@Test @Test
@ -23,7 +24,7 @@ internal class ExceptionCollectorTest {
collector.collect(IllegalArgumentException()) collector.collect(IllegalArgumentException())
assertTrue { collector.getLast() is IllegalArgumentException } assertTrue { collector.getLast() is IllegalArgumentException }
assertEquals(1, collector.count()) assertEquals(1, collector.asSequence().count())
} }
@Test @Test
@ -35,7 +36,7 @@ internal class ExceptionCollectorTest {
assertTrue { collector.getLast() is IllegalStateException } assertTrue { collector.getLast() is IllegalStateException }
assertTrue { collector.getLast()!!.suppressed.single() is IllegalArgumentException } assertTrue { collector.getLast()!!.suppressed.single() is IllegalArgumentException }
assertEquals(2, collector.count()) assertEquals(2, collector.asSequence().count())
} }
@Test @Test
@ -49,7 +50,7 @@ internal class ExceptionCollectorTest {
assertTrue { collector.getLast() is IllegalStateException } assertTrue { collector.getLast() is IllegalStateException }
assertTrue { collector.getLast()!!.suppressed.single() is IllegalArgumentException } assertTrue { collector.getLast()!!.suppressed.single() is IllegalArgumentException }
assertTrue { collector.getLast()!!.suppressed.single()!!.suppressed.single() is StackOverflowError } assertTrue { collector.getLast()!!.suppressed.single()!!.suppressed.single() is StackOverflowError }
assertEquals(3, collector.count()) assertEquals(3, collector.asSequence().count())
} }
@Test @Test
@ -62,9 +63,9 @@ internal class ExceptionCollectorTest {
collector.collect(exception) collector.collect(exception)
collector.collect(exception) collector.collect(exception)
assertSame(exception, collector.last()) assertSame(exception, collector.asSequence().last())
assertEquals(0, collector.getLast()!!.suppressed.size) assertEquals(0, collector.getLast()!!.suppressed.size)
assertEquals(1, collector.count()) assertEquals(1, collector.asSequence().count())
} }
@Test @Test
@ -82,7 +83,7 @@ internal class ExceptionCollectorTest {
} }
assertEquals(0, collector.getLast()!!.suppressed.size) assertEquals(0, collector.getLast()!!.suppressed.size)
assertEquals(1, collector.count()) assertEquals(1, collector.asSequence().count())
assertSame(exceptions.first(), collector.getLast()) assertSame(exceptions.first(), collector.getLast())
assertEquals("#0", collector.getLast()!!.message) assertEquals("#0", collector.getLast()!!.message)
} }