some changes for SynchedDelegates (will be discarded anyway)

This commit is contained in:
DBotThePony 2024-02-09 18:00:21 +07:00
parent 3c797b9131
commit 164ba29add
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -2,6 +2,7 @@
package ru.dbotthepony.kommons.io package ru.dbotthepony.kommons.io
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ReferenceArraySet import it.unimi.dsi.fastutil.objects.ReferenceArraySet
@ -12,7 +13,6 @@ import ru.dbotthepony.kommons.util.ListenableDelegate
import ru.dbotthepony.kommons.util.DelegateGetter import ru.dbotthepony.kommons.util.DelegateGetter
import ru.dbotthepony.kommons.util.DelegateSetter import ru.dbotthepony.kommons.util.DelegateSetter
import ru.dbotthepony.kommons.util.Listenable import ru.dbotthepony.kommons.util.Listenable
import java.io.ByteArrayOutputStream
import java.io.DataInputStream import java.io.DataInputStream
import java.io.DataOutputStream import java.io.DataOutputStream
import java.io.InputStream import java.io.InputStream
@ -25,7 +25,7 @@ import java.util.function.Supplier
* Universal, one-to-many value synchronizer, allowing to synchronize values from server to client * Universal, one-to-many value synchronizer, allowing to synchronize values from server to client
* anywhere, where input/output streams are supported * anywhere, where input/output streams are supported
*/ */
@Suppress("unused", "BlockingMethodInNonBlockingContext") @Suppress("unused")
class SynchedDelegates(private val callback: Runnable, private val alwaysCallCallback: Boolean) { class SynchedDelegates(private val callback: Runnable, private val alwaysCallCallback: Boolean) {
constructor() : this(Runnable {}, false) constructor() : this(Runnable {}, false)
constructor(callback: Runnable) : this(callback, false) constructor(callback: Runnable) : this(callback, false)
@ -38,16 +38,13 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
// но если поля нет в пакете, то всё окей // но если поля нет в пакете, то всё окей
private val fields = ArrayList<AbstractValue?>(0) private val fields = ArrayList<AbstractValue?>(0)
private val observers = ArrayList<Observer>(0) private val observers = ArrayList<Observer>(0)
private val endpoints = ArrayList<WeakReference<Endpoint>>(1)
private var lastEndpointCleanup = System.nanoTime()
private var nextFieldID = 0 private var nextFieldID = 0
val hasObservers: Boolean get() = observers.isNotEmpty() val hasObservers: Boolean get() = observers.isNotEmpty()
var isEmpty: Boolean = true var isEmpty: Boolean = true
private set private set
val isNotEmpty: Boolean get() = !isEmpty val isNotEmpty: Boolean get() = !isEmpty
var isDirty: Boolean = false var isDirty: Boolean = false
private set(value) { private set(value) {
if (value != field) { if (value != field) {
@ -63,16 +60,24 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
} }
} }
private val boundEndpoints = Collections.synchronizedMap(WeakHashMap<Any, Endpoint>())
fun computeEndpointFor(obj: Any): Endpoint {
return boundEndpoints.computeIfAbsent(obj) { Endpoint() }
}
fun removeEndpointFor(obj: Any): Endpoint? {
return boundEndpoints.remove(obj)
}
fun endpointFor(obj: Any): Endpoint? {
return boundEndpoints[obj]
}
fun markClean() { fun markClean() {
isDirty = false isDirty = false
} }
private var endpointsMaxCapacity = 1
private val endpoints = ArrayList<WeakReference<Endpoint>>(1)
val defaultEndpoint = Endpoint()
private var lastEndpointCleanup = System.nanoTime()
private fun notifyEndpoints(dirtyField: AbstractValue) { private fun notifyEndpoints(dirtyField: AbstractValue) {
isDirty = true isDirty = true
@ -84,21 +89,17 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
private inline fun forEachEndpoint(execute: (Endpoint) -> Unit) { private inline fun forEachEndpoint(execute: (Endpoint) -> Unit) {
synchronized(endpoints) { synchronized(endpoints) {
endpoints.forValidRefs { execute.invoke(it) } endpoints.forValidRefs { execute.invoke(it) }
if (endpoints.size < endpointsMaxCapacity / 2) {
endpoints.trimToSize()
endpointsMaxCapacity = endpoints.size
}
} }
} }
val defaultEndpoint = Endpoint()
inner class Endpoint { inner class Endpoint {
init { init {
synchronized(endpoints) { synchronized(endpoints) {
endpoints.add(WeakReference(this)) endpoints.add(WeakReference(this))
endpointsMaxCapacity = endpointsMaxCapacity.coerceAtLeast(endpoints.size)
if (System.nanoTime() - lastEndpointCleanup <= 60) { if (System.nanoTime() - lastEndpointCleanup >= 60) {
lastEndpointCleanup = System.nanoTime() lastEndpointCleanup = System.nanoTime()
val iterator = endpoints.listIterator() val iterator = endpoints.listIterator()
@ -108,11 +109,6 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
iterator.remove() iterator.remove()
} }
} }
if (endpoints.size < endpointsMaxCapacity / 2) {
endpoints.trimToSize()
endpointsMaxCapacity = endpoints.size
}
} }
} }
} }
@ -123,21 +119,22 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
private val mapBacklogs = Reference2ObjectOpenHashMap<Map<*, *>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>() private val mapBacklogs = Reference2ObjectOpenHashMap<Map<*, *>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
private val setBacklogs = Reference2ObjectOpenHashMap<Set<*>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>() private val setBacklogs = Reference2ObjectOpenHashMap<Set<*>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
var unused: Boolean = false var isDisabled: Boolean = false
private set private set
fun markUnused() { fun disable() {
require(this === defaultEndpoint) { "This is not a default endpoint" } if (isDisabled) return
if (unused) return isDisabled = true
unused = true
mapBacklogs.clear() mapBacklogs.clear()
dirty.clear() dirty.clear()
val iterator = endpoints.listIterator() synchronized(endpoints) {
val iterator = endpoints.listIterator()
for (value in iterator) { for (value in iterator) {
if (value.get() === this) { if (value.get() === this || value.get() == null) {
iterator.remove() iterator.remove()
}
} }
} }
} }
@ -147,16 +144,15 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
} }
fun markDirty() { fun markDirty() {
if (isDisabled) return
for (field in fields) { for (field in fields) {
field?.markDirty(this) field?.markDirty(this)
} }
} }
internal fun addDirty(field: AbstractValue) { internal fun addDirty(field: AbstractValue) {
if (unused) { if (isDisabled) return
return
}
dirty.add(field) dirty.add(field)
} }
@ -165,9 +161,7 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
} }
internal fun <K, V> getMapBacklog(map: Map<K, V>): LinkedList<Pair<Any?, (DataOutputStream) -> Unit>> { internal fun <K, V> getMapBacklog(map: Map<K, V>): LinkedList<Pair<Any?, (DataOutputStream) -> Unit>> {
if (unused) { if (isDisabled) return LinkedList()
return LinkedList()
}
return mapBacklogs.computeIfAbsent(map, Reference2ObjectFunction { return mapBacklogs.computeIfAbsent(map, Reference2ObjectFunction {
LinkedList() LinkedList()
@ -179,9 +173,7 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
} }
internal fun <V> getSetBacklog(set: Set<V>): LinkedList<Pair<Any?, (DataOutputStream) -> Unit>> { internal fun <V> getSetBacklog(set: Set<V>): LinkedList<Pair<Any?, (DataOutputStream) -> Unit>> {
if (unused) { if (isDisabled) return LinkedList()
return LinkedList()
}
return setBacklogs.computeIfAbsent(set, Reference2ObjectFunction { return setBacklogs.computeIfAbsent(set, Reference2ObjectFunction {
LinkedList() LinkedList()
@ -192,12 +184,11 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
setBacklogs.remove(set) setBacklogs.remove(set)
} }
fun collectNetworkPayload(): ByteArrayOutputStream? { fun collectData(): FastByteArrayOutputStream? {
if (unused || dirty.isEmpty()) { if (isDisabled || dirty.isEmpty())
return null return null
}
val stream = ByteArrayOutputStream() val stream = FastByteArrayOutputStream()
val dataStream = DataOutputStream(stream) val dataStream = DataOutputStream(stream)
for (field in dirty) { for (field in dirty) {
@ -212,20 +203,6 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
} }
} }
private val boundEndpoints = WeakHashMap<Any, Endpoint>()
fun computeEndpointFor(obj: Any): Endpoint {
return boundEndpoints.computeIfAbsent(obj) { Endpoint() }
}
fun removeEndpointFor(obj: Any): Endpoint? {
return boundEndpoints.remove(obj)
}
fun endpointFor(obj: Any): Endpoint? {
return boundEndpoints[obj]
}
abstract inner class AbstractValue : Observer { abstract inner class AbstractValue : Observer {
val id: Int val id: Int
@ -912,10 +889,10 @@ class SynchedDelegates(private val callback: Runnable, private val alwaysCallCal
/** /**
* [defaultEndpoint]#collectNetworkPayload * [defaultEndpoint]#collectNetworkPayload
*/ */
fun collectNetworkPayload(): ByteArrayOutputStream? { fun collectData(): FastByteArrayOutputStream? {
check(!defaultEndpoint.unused) { "Default endpoint is not used" } check(!defaultEndpoint.isDisabled) { "Default endpoint is not used" }
observe() observe()
val values = defaultEndpoint.collectNetworkPayload() val values = defaultEndpoint.collectData()
markClean() markClean()
return values return values
} }