mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 05:50:39 +00:00
Create mantle chunk flag locks only when a flag needs one
Every mantle chunk allocated a coroutine mutex for all 256 possible flag ordinals up front, about 66 KB of locks per chunk, although only a few flags are ever raised under a lock. During a pregen those locks took well over a gigabyte of heap and ran 3 GB servers out of memory. Each lock is now created when its flag is first raised. Model used: Claude Opus 5.5
This commit is contained in:
1 parent
8a0fd9b9fc
commit
6a85cb53a9
1 file changed
+13
-4
@@ -12,6 +12,7 @@ import java.io.DataInput
|
|||||||
import java.io.DataOutput
|
import java.io.DataOutput
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.Byte
|
import java.lang.Byte
|
||||||
|
import java.util.concurrent.atomic.AtomicReferenceArray
|
||||||
import kotlin.Boolean
|
import kotlin.Boolean
|
||||||
import kotlin.IllegalStateException
|
import kotlin.IllegalStateException
|
||||||
import kotlin.Int
|
import kotlin.Int
|
||||||
@@ -21,14 +22,16 @@ import kotlin.Unit
|
|||||||
|
|
||||||
abstract class FlaggedChunk() {
|
abstract class FlaggedChunk() {
|
||||||
private val flags = AtomicBooleanArray(MantleFlag.MAX_ORDINAL + 1)
|
private val flags = AtomicBooleanArray(MantleFlag.MAX_ORDINAL + 1)
|
||||||
private val locks = 0.rangeUntil(flags.length()).map { Mutex() }.toTypedArray()
|
// Created per flag on first use: a mutex for every possible ordinal cost ~66 KB per chunk, which made the mantle
|
||||||
|
// the largest consumer of heap during generation.
|
||||||
|
private val locks = AtomicReferenceArray<Mutex>(flags.length())
|
||||||
|
|
||||||
abstract fun isClosed(): Boolean
|
abstract fun isClosed(): Boolean
|
||||||
|
|
||||||
protected fun copyFrom(other: FlaggedChunk, action: Runnable) = runBlocking {
|
protected fun copyFrom(other: FlaggedChunk, action: Runnable) = runBlocking {
|
||||||
coroutineScope {
|
coroutineScope {
|
||||||
for (i in 0 until flags.length()) {
|
for (i in 0 until flags.length()) {
|
||||||
launch { locks[i].lock() }.start()
|
launch { lockFor(i).lock() }.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,10 +42,16 @@ abstract class FlaggedChunk() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0 until flags.length()) {
|
for (i in 0 until flags.length()) {
|
||||||
locks[i].unlock()
|
lockFor(i).unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun lockFor(index: Int): Mutex {
|
||||||
|
locks.get(index)?.let { return it }
|
||||||
|
val created = Mutex()
|
||||||
|
return if (locks.compareAndSet(index, null, created)) created else locks.get(index)
|
||||||
|
}
|
||||||
|
|
||||||
fun isFlagged(flag: MantleFlag) = flags.get(flag.ordinal())
|
fun isFlagged(flag: MantleFlag) = flags.get(flag.ordinal())
|
||||||
fun flag(flag: MantleFlag, value: Boolean) {
|
fun flag(flag: MantleFlag, value: Boolean) {
|
||||||
if (isClosed()) throw IllegalStateException("Chunk is closed!")
|
if (isClosed()) throw IllegalStateException("Chunk is closed!")
|
||||||
@@ -53,7 +62,7 @@ abstract class FlaggedChunk() {
|
|||||||
if (isClosed()) throw IllegalStateException("Chunk is closed!")
|
if (isClosed()) throw IllegalStateException("Chunk is closed!")
|
||||||
if (isFlagged(flag)) return
|
if (isFlagged(flag)) return
|
||||||
|
|
||||||
locks[flag.ordinal()].withLock {
|
lockFor(flag.ordinal()).withLock {
|
||||||
if (isFlagged(flag)) return
|
if (isFlagged(flag)) return
|
||||||
task()
|
task()
|
||||||
if (flags.getAndSet(flag.ordinal(), true))
|
if (flags.getAndSet(flag.ordinal(), true))
|
||||||
|
|||||||
Reference in new issue
Block a user