Skip to content

Commit 096d9d3

Browse files
Change the child contexts array to a map, with items removed from it by cleaners.
Should prevent unbounded growth of the context array for contexts with lots of short-lived children, without requiring linear scans of existing subcontexts.
1 parent 83a069e commit 096d9d3

File tree

1 file changed

+17
-8
lines changed

1 file changed

+17
-8
lines changed

src/main/kotlin/org/jitsi/utils/logging2/LogContext.kt

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.jitsi.utils.logging2
1717

18+
import java.lang.ref.Cleaner
1819
import java.lang.ref.WeakReference
1920

2021
/**
@@ -48,23 +49,30 @@ class LogContext private constructor(
4849
var formattedContext: String = formatContext(ancestorsContext + context)
4950
private set
5051

51-
/** Child [LogContext]s of this [LogContext] (which will be notified anytime this context changes) */
52-
private val childContexts: MutableList<WeakReference<LogContext>> = ArrayList()
53-
5452
@Synchronized
5553
private fun updateFormattedContext() {
5654
val combined = ancestorsContext + context
5755
formattedContext = formatContext(combined)
5856
updateChildren(combined)
5957
}
6058

59+
/** Child [LogContext]s of this [LogContext] (which will be notified anytime this context changes) */
60+
private val childContexts = mutableMapOf<Long, WeakReference<LogContext>>()
61+
62+
private var childCounter = 0L
63+
6164
@Synchronized
6265
fun createSubContext(childContextData: Map<String, String>) = LogContext(
6366
ancestorsContext + context,
6467
childContextData
6568
).also {
66-
childContexts.removeIf { r -> r.get() == null }
67-
childContexts.add(WeakReference(it))
69+
val count = childCounter++
70+
childContexts[count] = WeakReference(it)
71+
CLEANER.register(it) {
72+
synchronized(this@LogContext) {
73+
childContexts.remove(count)
74+
}
75+
}
6876
}
6977

7078
fun addContext(key: String, value: String) = addContext(mapOf(key to value))
@@ -83,9 +91,8 @@ class LogContext private constructor(
8391

8492
/** Notify children of changes in this context */
8593
@Synchronized
86-
private fun updateChildren(newAncestorContext: Map<String, String>) = childContexts.apply {
87-
removeIf { it.get() == null }
88-
forEach { it.get()?.ancestorsContext = newAncestorContext }
94+
private fun updateChildren(newAncestorContext: Map<String, String>) = childContexts.values.forEach {
95+
it.get()?.ancestorsContext = newAncestorContext
8996
}
9097

9198
override fun toString() = formattedContext
@@ -94,6 +101,8 @@ class LogContext private constructor(
94101
const val CONTEXT_START_TOKEN = "["
95102
const val CONTEXT_END_TOKEN = "]"
96103

104+
private val CLEANER = Cleaner.create()
105+
97106
private fun formatContext(context: Map<String, String>): String {
98107
val s = context.entries.joinToString(separator = " ") { "${it.key}=${it.value}" }
99108
return if (s.isEmpty()) "" else "$CONTEXT_START_TOKEN$s$CONTEXT_END_TOKEN"

0 commit comments

Comments
 (0)