Added support for also changing the aeron driver idle strategies
This commit is contained in:
parent
57480735c3
commit
3016618b1c
|
@ -36,6 +36,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|||
import mu.KLogger
|
||||
import mu.KotlinLogging
|
||||
import org.agrona.concurrent.AgentTerminationException
|
||||
import org.agrona.concurrent.IdleStrategy
|
||||
import org.slf4j.helpers.NOPLogger
|
||||
import java.io.File
|
||||
import java.net.BindException
|
||||
|
@ -325,6 +326,7 @@ abstract class Configuration protected constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the application ID. This is necessary, as it prevents multiple instances of aeron from responding to applications that
|
||||
* is not theirs. Because of the shared nature of aeron drivers, this is necessary.
|
||||
|
@ -542,6 +544,43 @@ abstract class Configuration protected constructor() {
|
|||
field = value
|
||||
}
|
||||
|
||||
/**
|
||||
* The idle strategy used by the Aeron Media Driver to write to the network when in DEDICATED mode. Null will use the aeron defaults
|
||||
*/
|
||||
var senderIdleStrategy: IdleStrategy? = null
|
||||
set(value) {
|
||||
require(!contextDefined) { errorMessage }
|
||||
field = value
|
||||
}
|
||||
|
||||
/**
|
||||
* The idle strategy used by the Aeron Media Driver read from the network when in DEDICATED mode. Null will use the aeron defaults
|
||||
*/
|
||||
var receiverIdleStrategy: IdleStrategy? = null
|
||||
set(value) {
|
||||
require(!contextDefined) { errorMessage }
|
||||
field = value
|
||||
}
|
||||
|
||||
/**
|
||||
* The idle strategy used by the Aeron Media Driver to read/write to the network when in NETWORK_SHARED mode. Null will use the aeron defaults
|
||||
*/
|
||||
var sharedIdleStrategy: IdleStrategy? = null
|
||||
set(value) {
|
||||
require(!contextDefined) { errorMessage }
|
||||
field = value
|
||||
}
|
||||
|
||||
/**
|
||||
* The idle strategy used by the Aeron Media Driver conductor when in DEDICATED mode. Null will use the aeron defaults
|
||||
*/
|
||||
var conductorIdleStrategy: IdleStrategy? = null
|
||||
set(value) {
|
||||
require(!contextDefined) { errorMessage }
|
||||
field = value
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ## A Media Driver, whether being run embedded or not, needs 1-3 threads to perform its operation.
|
||||
*
|
||||
|
@ -601,10 +640,8 @@ abstract class Configuration protected constructor() {
|
|||
* (> 4KB) messages and for maximizing throughput above everything else. Various checks during publication and subscription/connection
|
||||
* setup are done to verify a decent relationship with MTU.
|
||||
*
|
||||
*
|
||||
* However, it is good to understand these relationships.
|
||||
*
|
||||
*
|
||||
* The MTU on the Media Driver controls the length of the MTU of data frames. This value is communicated to the Aeron clients during
|
||||
* registration. So, applications do not have to concern themselves with the MTU value used by the Media Driver and use the same value.
|
||||
*
|
||||
|
@ -612,13 +649,9 @@ abstract class Configuration protected constructor() {
|
|||
* An MTU value over the interface MTU will cause IP to fragment the datagram. This may increase the likelihood of loss under several
|
||||
* circumstances. If increasing the MTU over the interface MTU, consider various ways to increase the interface MTU first in preparation.
|
||||
*
|
||||
*
|
||||
* The MTU value indicates the largest message that Aeron will send as a single data frame.
|
||||
*
|
||||
*
|
||||
* MTU length also has implications for socket buffer sizing.
|
||||
*
|
||||
*
|
||||
* Default value is 1408 for internet; for a LAN, 9k is possible with jumbo frames (if the routers/interfaces support it)
|
||||
*/
|
||||
var networkMtuSize = Configuration.MTU_LENGTH_DEFAULT
|
||||
|
@ -627,6 +660,12 @@ abstract class Configuration protected constructor() {
|
|||
field = value
|
||||
}
|
||||
|
||||
var ipcMtuSize = Configuration.MAX_UDP_PAYLOAD_LENGTH
|
||||
set(value) {
|
||||
require(!contextDefined) { errorMessage }
|
||||
field = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Default initial window length for flow control sender to receiver purposes. This assumes a system free of pauses.
|
||||
*
|
||||
|
@ -781,6 +820,8 @@ abstract class Configuration protected constructor() {
|
|||
|
||||
require(networkMtuSize > 0) { "configuration networkMtuSize must be > 0" }
|
||||
require(networkMtuSize < Configuration.MAX_UDP_PAYLOAD_LENGTH) { "configuration networkMtuSize must be < ${Configuration.MAX_UDP_PAYLOAD_LENGTH}" }
|
||||
require(ipcMtuSize > 0) { "configuration ipcMtuSize must be > 0" }
|
||||
require(ipcMtuSize <= Configuration.MAX_UDP_PAYLOAD_LENGTH) { "configuration ipcMtuSize must be <= ${Configuration.MAX_UDP_PAYLOAD_LENGTH}" }
|
||||
|
||||
require(sendBufferSize >= 0) { "configuration socket send buffer must be >= 0"}
|
||||
require(receiveBufferSize >= 0) { "configuration socket receive buffer must be >= 0"}
|
||||
|
@ -892,6 +933,7 @@ abstract class Configuration protected constructor() {
|
|||
val threadingMode get() = config.threadingMode
|
||||
|
||||
val networkMtuSize get() = config.networkMtuSize
|
||||
val ipcMtuSize get() = config.ipcMtuSize
|
||||
val initialWindowLength get() = config.initialWindowLength
|
||||
val sendBufferSize get() = config.sendBufferSize
|
||||
val receiveBufferSize get() = config.receiveBufferSize
|
||||
|
@ -905,6 +947,10 @@ abstract class Configuration protected constructor() {
|
|||
val ipcTermBufferLength get() = config.ipcTermBufferLength
|
||||
val publicationTermBufferLength get() = config.publicationTermBufferLength
|
||||
|
||||
val conductorIdleStrategy get() = config.conductorIdleStrategy
|
||||
val sharedIdleStrategy get() = config.sharedIdleStrategy
|
||||
val receiverIdleStrategy get() = config.receiverIdleStrategy
|
||||
val senderIdleStrategy get() = config.senderIdleStrategy
|
||||
|
||||
val aeronErrorFilter get() = config.aeronErrorFilter
|
||||
var contextDefined
|
||||
|
@ -918,15 +964,7 @@ abstract class Configuration protected constructor() {
|
|||
*/
|
||||
@Suppress("DuplicatedCode")
|
||||
fun validate() {
|
||||
require(networkMtuSize > 0) { "configuration networkMtuSize must be > 0" }
|
||||
require(networkMtuSize < Configuration.MAX_UDP_PAYLOAD_LENGTH) { "configuration networkMtuSize must be < ${Configuration.MAX_UDP_PAYLOAD_LENGTH}" }
|
||||
|
||||
require(sendBufferSize >= 0) { "configuration socket send buffer must be a >= 0"}
|
||||
require(receiveBufferSize >= 0) { "configuration socket receive buffer must be >= 0"}
|
||||
require(ipcTermBufferLength > 65535) { "configuration IPC term buffer must be > 65535"}
|
||||
require(ipcTermBufferLength < 1_073_741_824) { "configuration IPC term buffer must be < 1,073,741,824"}
|
||||
require(publicationTermBufferLength > 65535) { "configuration publication term buffer must be > 65535"}
|
||||
require(publicationTermBufferLength < 1_073_741_824) { "configuration publication term buffer must be < 1,073,741,824"}
|
||||
// already validated! do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -956,6 +994,7 @@ abstract class Configuration protected constructor() {
|
|||
if (connectionCloseTimeoutInSeconds != other.connectionCloseTimeoutInSeconds) return false
|
||||
if (threadingMode != other.threadingMode) return false
|
||||
if (networkMtuSize != other.networkMtuSize) return false
|
||||
if (ipcMtuSize != other.ipcMtuSize) return false
|
||||
if (initialWindowLength != other.initialWindowLength) return false
|
||||
if (sendBufferSize != other.sendBufferSize) return false
|
||||
if (receiveBufferSize != other.receiveBufferSize) return false
|
||||
|
@ -968,6 +1007,11 @@ abstract class Configuration protected constructor() {
|
|||
if (publicationTermBufferLength != other.publicationTermBufferLength) return false
|
||||
if (aeronErrorFilter != other.aeronErrorFilter) return false
|
||||
|
||||
if (conductorIdleStrategy != other.conductorIdleStrategy) return false
|
||||
if (sharedIdleStrategy != other.sharedIdleStrategy) return false
|
||||
if (receiverIdleStrategy != other.receiverIdleStrategy) return false
|
||||
if (senderIdleStrategy != other.senderIdleStrategy) return false
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -977,10 +1021,16 @@ abstract class Configuration protected constructor() {
|
|||
if (forceAllowSharedAeronDriver != other.forceAllowSharedAeronDriver) return false
|
||||
if (threadingMode != other.threadingMode) return false
|
||||
if (networkMtuSize != other.networkMtuSize) return false
|
||||
if (ipcMtuSize != other.ipcMtuSize) return false
|
||||
if (initialWindowLength != other.initialWindowLength) return false
|
||||
if (sendBufferSize != other.sendBufferSize) return false
|
||||
if (receiveBufferSize != other.receiveBufferSize) return false
|
||||
|
||||
if (conductorIdleStrategy != other.conductorIdleStrategy) return false
|
||||
if (sharedIdleStrategy != other.sharedIdleStrategy) return false
|
||||
if (receiverIdleStrategy != other.receiverIdleStrategy) return false
|
||||
if (senderIdleStrategy != other.senderIdleStrategy) return false
|
||||
|
||||
if (aeronDirectory != other.aeronDirectory) return false
|
||||
if (uniqueAeronDirectory != other.uniqueAeronDirectory) return false
|
||||
if (uniqueAeronDirectoryID != other.uniqueAeronDirectoryID) return false
|
||||
|
@ -1037,6 +1087,7 @@ abstract class Configuration protected constructor() {
|
|||
private fun mediaDriverIdNoDir(): Int {
|
||||
var result = threadingMode.hashCode()
|
||||
result = 31 * result + networkMtuSize
|
||||
result = 31 * result + ipcMtuSize
|
||||
result = 31 * result + initialWindowLength
|
||||
result = 31 * result + sendBufferSize
|
||||
result = 31 * result + receiveBufferSize
|
||||
|
@ -1063,15 +1114,18 @@ abstract class Configuration protected constructor() {
|
|||
if (enableIpc != other.enableIpc) return false
|
||||
if (ipcId != other.ipcId) return false
|
||||
if (udpId != other.udpId) return false
|
||||
|
||||
if (enableRemoteSignatureValidation != other.enableRemoteSignatureValidation) return false
|
||||
if (connectionCloseTimeoutInSeconds != other.connectionCloseTimeoutInSeconds) return false
|
||||
if (connectionCheckIntervalNanos != other.connectionCheckIntervalNanos) return false
|
||||
if (connectionExpirationTimoutNanos != other.connectionExpirationTimoutNanos) return false
|
||||
|
||||
if (isReliable != other.isReliable) return false
|
||||
if (pingTimeoutSeconds != other.pingTimeoutSeconds) return false
|
||||
if (settingsStore != other.settingsStore) return false
|
||||
if (serialization != other.serialization) return false
|
||||
if (maxStreamSizeInMemoryMB != other.maxStreamSizeInMemoryMB) return false
|
||||
|
||||
if (pollIdleStrategy != other.pollIdleStrategy) return false
|
||||
if (sendIdleStrategy != other.sendIdleStrategy) return false
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ internal class AeronContext(config: Configuration.MediaDriverConfig, logger: KLo
|
|||
|
||||
.threadingMode(config.threadingMode)
|
||||
.mtuLength(config.networkMtuSize)
|
||||
.ipcMtuLength(config.networkMtuSize)
|
||||
.ipcMtuLength(config.ipcMtuSize)
|
||||
|
||||
.initialWindowLength(config.initialWindowLength)
|
||||
.socketSndbufLength(config.sendBufferSize)
|
||||
|
@ -74,11 +74,18 @@ internal class AeronContext(config: Configuration.MediaDriverConfig, logger: KLo
|
|||
.sharedNetworkThreadFactory(threadFactory)
|
||||
.sharedThreadFactory(threadFactory)
|
||||
|
||||
// default backoff idle strategy
|
||||
// .conductorIdleStrategy(BusySpinIdleStrategy.INSTANCE)
|
||||
// .sharedIdleStrategy(NoOpIdleStrategy.INSTANCE)
|
||||
// .receiverIdleStrategy(BusySpinIdleStrategy.INSTANCE)
|
||||
// .senderIdleStrategy(BusySpinIdleStrategy.INSTANCE)
|
||||
if (config.conductorIdleStrategy != null) {
|
||||
mediaDriverContext.conductorIdleStrategy(config.conductorIdleStrategy)
|
||||
}
|
||||
if (config.sharedIdleStrategy != null) {
|
||||
mediaDriverContext.sharedIdleStrategy(config.sharedIdleStrategy)
|
||||
}
|
||||
if (config.receiverIdleStrategy != null) {
|
||||
mediaDriverContext.receiverIdleStrategy(config.receiverIdleStrategy)
|
||||
}
|
||||
if (config.senderIdleStrategy != null) {
|
||||
mediaDriverContext.senderIdleStrategy(config.senderIdleStrategy)
|
||||
}
|
||||
|
||||
mediaDriverContext.aeronDirectoryName(config.aeronDirectory!!.path)
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import dorkbox.network.rmi.RmiSupportConnection
|
|||
import io.aeron.Image
|
||||
import io.aeron.logbuffer.FragmentHandler
|
||||
import io.aeron.logbuffer.Header
|
||||
import io.aeron.protocol.DataHeaderFlyweight
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.atomicfu.getAndUpdate
|
||||
import kotlinx.coroutines.delay
|
||||
|
@ -99,7 +100,17 @@ open class Connection(connectionParameters: ConnectionParams<*>) {
|
|||
*/
|
||||
val isNetwork = !isIpc
|
||||
|
||||
|
||||
/**
|
||||
* The largest size a SINGLE message via AERON can be. Because the maximum size we can send in a "single fragment" is the
|
||||
* publication.maxPayloadLength() function (which is the MTU length less header). We could depend on Aeron for fragment reassembly,
|
||||
* but that has a (very low) maximum reassembly size -- so we have our own mechanism for object fragmentation/assembly, which
|
||||
* is (in reality) only limited by available ram.
|
||||
*/
|
||||
internal val maxMessageSize = if (isNetwork) {
|
||||
endPoint.config.networkMtuSize - DataHeaderFlyweight.HEADER_LENGTH
|
||||
} else {
|
||||
endPoint.config.ipcMtuSize - DataHeaderFlyweight.HEADER_LENGTH
|
||||
}
|
||||
|
||||
|
||||
private val listenerManager = atomic<ListenerManager<Connection>?>(null)
|
||||
|
@ -184,7 +195,7 @@ open class Connection(connectionParameters: ConnectionParams<*>) {
|
|||
internal suspend fun send(message: Any, abortEarly: Boolean): Boolean {
|
||||
// The handshake sessionId IS NOT globally unique
|
||||
logger.trace { "[$toString0] send: ${message.javaClass.simpleName} : $message" }
|
||||
return endPoint.write(message, publication, sendIdleStrategy, this@Connection, abortEarly)
|
||||
return endPoint.write(message, publication, sendIdleStrategy, this@Connection, maxMessageSize, abortEarly)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -119,14 +119,6 @@ abstract class EndPoint<CONNECTION : Connection> private constructor(val type: C
|
|||
*/
|
||||
val serialization: Serialization<CONNECTION>
|
||||
|
||||
/**
|
||||
* The largest size a SINGLE message via AERON can be. Because the maximum size we can send in a "single fragment" is the
|
||||
* publication.maxPayloadLength() function (which is the MTU length less header). We could depend on Aeron for fragment reassembly,
|
||||
* but that has a (very low) maximum reassembly size -- so we have our own mechanism for object fragmentation/assembly, which
|
||||
* is (in reality) only limited by available ram.
|
||||
*/
|
||||
private val maxMessageSize = config.networkMtuSize - DataHeaderFlyweight.HEADER_LENGTH
|
||||
|
||||
/**
|
||||
* Read and Write can be concurrent (different buffers are used)
|
||||
* GLOBAL, single threaded only kryo instances.
|
||||
|
@ -475,6 +467,7 @@ abstract class EndPoint<CONNECTION : Connection> private constructor(val type: C
|
|||
publication: Publication,
|
||||
sendIdleStrategy: CoroutineIdleStrategy,
|
||||
connection: Connection,
|
||||
maxMessageSize: Int,
|
||||
abortEarly: Boolean
|
||||
): Boolean {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
|
|
@ -36,7 +36,6 @@ import dorkbox.network.serialization.KryoWriter
|
|||
import dorkbox.os.OS
|
||||
import dorkbox.util.Sys
|
||||
import io.aeron.Publication
|
||||
import io.aeron.protocol.DataHeaderFlyweight
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import mu.KLogger
|
||||
|
@ -53,7 +52,7 @@ internal class StreamingManager<CONNECTION : Connection>(private val logger: KLo
|
|||
private const val GIGABYTE = 1024 * MEGABYTE
|
||||
private const val TERABYTE = 1024L * GIGABYTE
|
||||
|
||||
@Suppress("UNUSED_CHANGED_VALUE")
|
||||
@Suppress("UNUSED_CHANGED_VALUE", "SameParameterValue")
|
||||
private fun writeVarInt(internalBuffer: MutableDirectBuffer, position: Int, value: Int, optimizePositive: Boolean): Int {
|
||||
var p = position
|
||||
var newValue = value
|
||||
|
@ -571,6 +570,7 @@ internal class StreamingManager<CONNECTION : Connection>(private val logger: KLo
|
|||
*
|
||||
* @return true if ALL the message blocks were successfully sent by aeron, false otherwise. Exceptions are caught and rethrown!
|
||||
*/
|
||||
@Suppress("SameParameterValue")
|
||||
suspend fun sendFile(
|
||||
file: File,
|
||||
publication: Publication,
|
||||
|
@ -580,8 +580,7 @@ internal class StreamingManager<CONNECTION : Connection>(private val logger: KLo
|
|||
connection: CONNECTION,
|
||||
streamSessionId: Int
|
||||
): Boolean {
|
||||
val maxMessageSize = (config.networkMtuSize - DataHeaderFlyweight.HEADER_LENGTH).toLong()
|
||||
|
||||
val maxMessageSize = connection.maxMessageSize.toLong()
|
||||
val fileInputStream = file.inputStream()
|
||||
|
||||
// if the message is a file, we xfer the file AS a file, and leave it as a temp file (with a file reference to it) on the remote endpoint
|
||||
|
|
Loading…
Reference in New Issue