Remove structural synchronization inside SynchableGroup

Also fixed memory leak when removing remotes
This commit is contained in:
DBotThePony 2025-02-25 16:09:32 +07:00
parent 05913674b1
commit 25e25b0f86
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 35 additions and 43 deletions

View File

@ -180,7 +180,7 @@ class DynamicSynchableGroup<T : ISynchable>(
private data class Slot<T : Any>(val synchable: T, val id: Int) private data class Slot<T : Any>(val synchable: T, val id: Int)
private val remoteStates = CopyOnWriteArrayList<RemoteState>() private val remoteStates = ArrayList<RemoteState>()
private val value2slot = HashMap<T, Slot<T>>() private val value2slot = HashMap<T, Slot<T>>()
private val id2slot = Int2ObjectOpenHashMap<Slot<T>>() private val id2slot = Int2ObjectOpenHashMap<Slot<T>>()
private val idAllocator = IDAllocator() private val idAllocator = IDAllocator()
@ -271,7 +271,7 @@ class DynamicSynchableGroup<T : ISynchable>(
value2slot.clear() value2slot.clear()
id2slot.clear() id2slot.clear()
remoteStates.forEach { it.clear() } remoteStates.toTypedArray().forEach { it.clear() }
} }
} }

View File

@ -40,6 +40,7 @@ import java.util.function.DoubleSupplier
import java.util.function.IntSupplier import java.util.function.IntSupplier
import java.util.function.LongSupplier import java.util.function.LongSupplier
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.collections.ArrayList
import kotlin.concurrent.withLock import kotlin.concurrent.withLock
/** /**
@ -56,7 +57,6 @@ import kotlin.concurrent.withLock
*/ */
@Suppress("UNUSED") @Suppress("UNUSED")
class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> { class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> {
private val lock = ReentrantLock()
private val slots = ArrayList<Slot?>() private val slots = ArrayList<Slot?>()
private val gaps = IntAVLTreeSet() private val gaps = IntAVLTreeSet()
private val observers = ArrayList<Slot>() private val observers = ArrayList<Slot>()
@ -109,7 +109,7 @@ class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> {
val id: Int val id: Int
private var isRemoved = false private var isRemoved = false
val remoteSlots = CopyOnWriteArrayList<Remote.RemoteSlot>() val remoteSlots = ArrayList<Remote.RemoteSlot>()
override fun close() { override fun close() {
if (!isRemoved) { if (!isRemoved) {
@ -118,7 +118,7 @@ class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> {
gaps.add(id) gaps.add(id)
observers.remove(this) observers.remove(this)
remoteSlots.forEach { it.remove() } remoteSlots.toTypedArray().forEach { it.remove() }
} }
} }
@ -128,32 +128,28 @@ class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> {
private fun markDirty() { private fun markDirty() {
if (!isRemote && !isRemoved) { if (!isRemote && !isRemoved) {
remoteSlots.forEach { remoteSlots.forEach { it.markDirty() }
it.markDirty()
}
} }
} }
init { init {
lock.withLock { if (synchable.shouldBeObserved) {
if (synchable.shouldBeObserved) { observers.add(this)
observers.add(this) }
}
if (gaps.isNotEmpty()) { if (gaps.isNotEmpty()) {
val gap = gaps.firstInt() val gap = gaps.firstInt()
gaps.remove(gap) gaps.remove(gap)
id = gap id = gap
check(slots[id] == null) { "Expected slot $id to be empty" } check(slots[id] == null) { "Expected slot $id to be empty" }
slots[id] = this slots[id] = this
} else { } else {
id = slots.size id = slots.size
slots.add(this) slots.add(this)
} }
remotes.forEach { remotes.forEach {
it.addSlot(this) it.addSlot(this)
}
} }
} }
} }
@ -301,12 +297,11 @@ class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> {
* To get changes to be networked to remote client, [write] should be called. * To get changes to be networked to remote client, [write] should be called.
*/ */
inner class Remote(private val listener: Runnable) : Closeable, IRemoteState { inner class Remote(private val listener: Runnable) : Closeable, IRemoteState {
constructor() : this(Runnable { }) constructor() : this(Runnable {})
@Volatile
private var isRemoved = false private var isRemoved = false
internal val dirty = ConcurrentLinkedQueue<RemoteSlot>() internal val dirty = ConcurrentLinkedQueue<RemoteSlot>()
private val remoteSlots = CopyOnWriteArrayList<RemoteSlot>() private val remoteSlots = ArrayList<RemoteSlot>()
internal inner class RemoteSlot(val slot: Slot) { internal inner class RemoteSlot(val slot: Slot) {
private val isDirty = AtomicBoolean() private val isDirty = AtomicBoolean()
@ -357,6 +352,7 @@ class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> {
remoteSlots.remove(this) remoteSlots.remove(this)
dirty.remove(this) dirty.remove(this)
cleanable.clean() cleanable.clean()
slot.remoteSlots.remove(this)
} }
override fun hashCode(): Int { override fun hashCode(): Int {
@ -369,15 +365,13 @@ class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> {
} }
init { init {
lock.withLock { slots.forEach {
slots.forEach { if (it != null) {
if (it != null) { addSlot(it)
addSlot(it)
}
} }
remotes.add(this)
} }
remotes.add(this)
} }
internal fun addSlot(slot: Slot) { internal fun addSlot(slot: Slot) {
@ -435,15 +429,13 @@ class SynchableGroup : Observer, ISynchable, Iterable<ISynchable> {
if (!isRemoved) { if (!isRemoved) {
isRemoved = true isRemoved = true
lock.withLock { remoteSlots.toTypedArray().forEach {
remoteSlots.forEach { it.remove()
it.remove() it.slot.remoteSlots.remove(it)
it.slot.remoteSlots.remove(it)
}
remotes.remove(this)
dirty.clear()
} }
remotes.remove(this)
dirty.clear()
} }
} }
} }