Send all buffered messages at once, instead of 1-at-a-time.

master
Robinson 2023-12-04 10:47:37 +01:00
parent b9f7a552f0
commit cb7f8b2990
No known key found for this signature in database
GPG Key ID: 8E7DB78588BD6F5C
5 changed files with 78 additions and 6 deletions

View File

@ -19,6 +19,7 @@ import dorkbox.network.Client
import dorkbox.network.Server
import dorkbox.network.aeron.AeronDriver.Companion.sessionIdAllocator
import dorkbox.network.aeron.AeronDriver.Companion.streamIdAllocator
import dorkbox.network.connection.buffer.BufferedMessages
import dorkbox.network.connection.buffer.BufferedSession
import dorkbox.network.ping.Ping
import dorkbox.network.rmi.RmiSupportConnection
@ -344,13 +345,16 @@ open class Connection(connectionParameters: ConnectionParams<*>) {
internal fun sendBufferedMessages() {
if (enableBufferedMessages) {
// now send all buffered/pending messages
if (logger.isDebugEnabled) {
logger.debug("Sending buffered messages: ${bufferedSession.pendingMessagesQueue.size}")
}
val bufferedMessage = BufferedMessages()
val numberDrained = bufferedSession.pendingMessagesQueue.drainTo(bufferedMessage.messages)
bufferedSession.pendingMessagesQueue.forEach {
sendNoBuffer(it)
if (numberDrained > 0) {
// now send all buffered/pending messages
if (logger.isDebugEnabled) {
logger.debug("Sending buffered messages: ${bufferedSession.pendingMessagesQueue.size}")
}
sendNoBuffer(bufferedMessage)
}
}
}

View File

@ -24,6 +24,7 @@ import dorkbox.network.ServerConfiguration
import dorkbox.network.aeron.AeronDriver
import dorkbox.network.aeron.BacklogStat
import dorkbox.network.aeron.EventPoller
import dorkbox.network.connection.buffer.BufferedMessages
import dorkbox.network.connection.streaming.StreamingControl
import dorkbox.network.connection.streaming.StreamingData
import dorkbox.network.connection.streaming.StreamingManager
@ -676,6 +677,14 @@ abstract class EndPoint<CONNECTION : Connection> private constructor(val type: C
}
}
is BufferedMessages -> {
// this can potentially be an EXTREMELY large set of data -- so when there are buffered messages, it is often better
// to batch-send them instead of one-at-a-time (which can cause excessive CPU load and Network I/O)
message.messages.forEach {
processMessageFromChannel(connection, it)
}
}
// small problem... If we expect IN ORDER messages (ie: setting a value, then later reading the value), multiple threads don't work.
// this is worked around by having RMI always return (unless async), even with a null value, so the CALLING side of RMI will always
// go in "lock step"

View File

@ -0,0 +1,21 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.connection.buffer
class BufferedMessages {
var messages = arrayListOf<Any>()
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.connection.buffer
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.Serializer
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output
internal class BufferedSerializer: Serializer<BufferedMessages>() {
override fun write(kryo: Kryo, output: Output, messages: BufferedMessages) {
kryo.writeClassAndObject(output, messages.messages)
}
override fun read(kryo: Kryo, input: Input, type: Class<out BufferedMessages>): BufferedMessages {
val messages = BufferedMessages()
messages.messages = kryo.readClassAndObject(input) as ArrayList<Any>
return messages
}
}

View File

@ -26,6 +26,8 @@ import dorkbox.network.Server
import dorkbox.network.connection.Connection
import dorkbox.network.connection.DisconnectMessage
import dorkbox.network.connection.SendSync
import dorkbox.network.connection.buffer.BufferedMessages
import dorkbox.network.connection.buffer.BufferedSerializer
import dorkbox.network.connection.streaming.StreamingControl
import dorkbox.network.connection.streaming.StreamingControlSerializer
import dorkbox.network.connection.streaming.StreamingData
@ -185,6 +187,7 @@ open class Serialization<CONNECTION: Connection>(private val references: Boolean
private val pingSerializer = PingSerializer()
private val sendSyncSerializer = SendSyncSerializer()
private val disconnectSerializer = DisconnectSerializer()
private val bufferedMessageSerializer = BufferedSerializer()
internal val fileContentsSerializer = FileContentsSerializer<CONNECTION>()
@ -438,6 +441,7 @@ open class Serialization<CONNECTION: Connection>(private val references: Boolean
kryo.register(SendSync::class.java, sendSyncSerializer)
kryo.register(HandshakeMessage::class.java)
kryo.register(DisconnectMessage::class.java, disconnectSerializer)
kryo.register(BufferedMessages::class.java, bufferedMessageSerializer)
@Suppress("UNCHECKED_CAST")