Skip to content

Commit 13fbc76

Browse files
simplify and reduce allocations (#73)
1 parent 296856b commit 13fbc76

File tree

4 files changed

+134
-102
lines changed

4 files changed

+134
-102
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#
1616

1717
group=io.rsocket.kotlin
18-
version=0.9.7
18+
version=0.9.8
1919

2020
buildScanPluginVersion=2.4.1
2121
dependencyManagementPluginVersion=1.0.8.RELEASE

rsocket-core/src/main/kotlin/io/rsocket/kotlin/internal/RSocketRequester.kt

Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import io.reactivex.processors.UnicastProcessor
2323
import io.rsocket.kotlin.*
2424
import io.rsocket.kotlin.exceptions.ApplicationException
2525
import io.rsocket.kotlin.exceptions.ChannelRequestException
26+
import io.rsocket.kotlin.internal.util.reactiveStreamsRequestN
2627
import org.reactivestreams.Publisher
2728
import org.reactivestreams.Subscriber
2829
import org.reactivestreams.Subscription
@@ -121,10 +122,11 @@ internal class RSocketRequester(
121122
val streamId = streamIds.nextStreamId(receivers)
122123
val receiver = StreamReceiver.create()
123124
receivers[streamId] = receiver
124-
val reqN = Cond()
125+
var isFirstRequestN = true
125126

126127
receiver.doOnRequestIfActive { requestN ->
127-
val frame = if (reqN.first()) {
128+
val frame = if (isFirstRequestN) {
129+
isFirstRequestN = false
128130
Frame.Request.from(
129131
streamId,
130132
FrameType.REQUEST_STREAM,
@@ -148,35 +150,37 @@ internal class RSocketRequester(
148150
return Flowable.defer {
149151
val receiver = StreamReceiver.create()
150152
val streamId = streamIds.nextStreamId(receivers)
151-
val reqN = Cond()
153+
var firstReqN = true
154+
var firstReqPayload = true
152155

153156
receiver.doOnRequestIfActive { requestN ->
154157

155-
if (reqN.first()) {
156-
val wrappedRequest = request.compose {
157-
val sender = RequestingPublisher.wrap(it)
158-
sender.request(1)
159-
senders[streamId] = sender
160-
receivers[streamId] = receiver
161-
sender
162-
}.publish().autoConnect(2)
158+
if (firstReqN) {
159+
firstReqN = false
163160

164-
val first = wrappedRequest.take(1)
165-
.map { payload ->
166-
Frame.Request.from(
167-
streamId,
168-
FrameType.REQUEST_CHANNEL,
169-
payload,
170-
requestN)
161+
val requestFrames = request
162+
.compose {
163+
val sender = RequestingPublisher.wrap(it)
164+
sender.request(1)
165+
senders[streamId] = sender
166+
receivers[streamId] = receiver
167+
sender
171168
}
172-
val rest = wrappedRequest.skip(1)
173169
.map { payload ->
174-
Frame.PayloadFrame.from(
175-
streamId,
176-
FrameType.NEXT,
177-
payload)
170+
if (firstReqPayload) {
171+
firstReqPayload = false
172+
Frame.Request.from(
173+
streamId,
174+
FrameType.REQUEST_CHANNEL,
175+
payload,
176+
requestN)
177+
} else {
178+
Frame.PayloadFrame.from(
179+
streamId,
180+
FrameType.NEXT,
181+
payload)
182+
}
178183
}
179-
val requestFrames = Flowable.concatArrayEager(first, rest)
180184
requestFrames.subscribe(
181185
ChannelRequestSubscriber(
182186
{ payload -> frameSender.send(payload) },
@@ -248,10 +252,7 @@ internal class RSocketRequester(
248252
FrameType.NEXT -> receiver.onNext(DefaultPayload(frame))
249253
FrameType.REQUEST_N -> {
250254
val sender = senders[streamId]
251-
sender?.let {
252-
val n = Frame.RequestN.requestN(frame).toLong()
253-
it.request(n)
254-
}
255+
sender?.request(reactiveStreamsRequestN(Frame.RequestN.requestN(frame)))
255256
}
256257
FrameType.COMPLETE -> {
257258
receiver.onComplete()
@@ -320,18 +321,6 @@ internal class RSocketRequester(
320321
}
321322
}
322323

323-
private class Cond {
324-
private var first = true
325-
326-
fun first(): Boolean =
327-
if (first) {
328-
first = false
329-
true
330-
} else {
331-
false
332-
}
333-
}
334-
335324
private class ChannelRequestSubscriber(private val next: (Frame) -> Unit,
336325
private val error: (Throwable) -> Unit,
337326
private val complete: (Boolean) -> Unit)

rsocket-core/src/main/kotlin/io/rsocket/kotlin/internal/RSocketResponder.kt

Lines changed: 96 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616

1717
package io.rsocket.kotlin.internal
1818

19-
import io.reactivex.Completable
20-
import io.reactivex.Flowable
21-
import io.reactivex.Single
19+
import io.reactivex.*
2220
import io.reactivex.disposables.Disposable
2321
import io.rsocket.kotlin.*
2422
import io.rsocket.kotlin.Frame.Request.initialRequestN
@@ -27,6 +25,7 @@ import io.rsocket.kotlin.exceptions.ApplicationException
2725
import io.rsocket.kotlin.internal.frame.FrameHeaderFlyweight.FLAGS_C
2826
import io.rsocket.kotlin.internal.frame.FrameHeaderFlyweight.FLAGS_M
2927
import io.rsocket.kotlin.DefaultPayload
28+
import io.rsocket.kotlin.internal.util.reactiveStreamsRequestN
3029
import org.reactivestreams.Publisher
3130
import org.reactivestreams.Subscriber
3231
import org.reactivestreams.Subscription
@@ -57,8 +56,7 @@ internal class RSocketResponder(
5756

5857
receiveDisposable = connection
5958
.receive()
60-
.concatMap { frame -> handleFrame(frame) }
61-
.subscribe({}, { completion.error(it) })
59+
.subscribe({ handleFrame(it) }, { completion.error(it) })
6260

6361
connection
6462
.onClose()
@@ -111,8 +109,8 @@ internal class RSocketResponder(
111109

112110
override fun onClose(): Completable = connection.onClose()
113111

114-
private fun handleFrame(frame: Frame): Flowable<Void> {
115-
return try {
112+
private fun handleFrame(frame: Frame) {
113+
try {
116114
val streamId = frame.streamId
117115
when (frame.type) {
118116
FrameType.FIRE_AND_FORGET -> handleFireAndForget(streamId, fireAndForget(DefaultPayload(frame)))
@@ -121,96 +119,126 @@ internal class RSocketResponder(
121119
FrameType.REQUEST_N -> handleRequestN(streamId, frame)
122120
FrameType.REQUEST_STREAM -> handleStream(streamId, requestStream(DefaultPayload(frame)), initialRequestN(frame))
123121
FrameType.REQUEST_CHANNEL -> handleChannel(streamId, frame)
124-
FrameType.METADATA_PUSH -> metadataPush(DefaultPayload(frame))
122+
FrameType.METADATA_PUSH -> handleMetadataPush(metadataPush(DefaultPayload(frame)))
125123
FrameType.NEXT -> handleNext(streamId, frame)
126124
FrameType.COMPLETE -> handleComplete(streamId)
127125
FrameType.ERROR -> handleError(streamId, frame)
128126
FrameType.NEXT_COMPLETE -> handleNextComplete(streamId, frame)
129127
else -> handleUnsupportedFrame(frame)
130-
}.toFlowable()
128+
}
131129
} finally {
132130
frame.release()
133131
}
134132
}
135133

136-
private fun handleUnsupportedFrame(frame: Frame): Completable {
134+
private fun handleUnsupportedFrame(frame: Frame) {
137135
errorConsumer(IllegalArgumentException("Unsupported frame: $frame"))
138-
return Completable.complete()
139136
}
140137

141-
private fun handleNextComplete(streamId: Int, frame: Frame): Completable {
138+
private fun handleNextComplete(streamId: Int, frame: Frame) {
142139
val receiver = channelReceivers[streamId]
143140
receiver?.onNext(DefaultPayload(frame))
144141
receiver?.onComplete()
145-
return Completable.complete()
146142
}
147143

148-
private fun handleError(streamId: Int, frame: Frame): Completable {
144+
private fun handleError(streamId: Int, frame: Frame) {
149145
val receiver = channelReceivers[streamId]
150146
receiver?.onError(ApplicationException(Frame.Error.message(frame)))
151-
return Completable.complete()
152147
}
153148

154-
private fun handleComplete(streamId: Int): Completable {
149+
private fun handleComplete(streamId: Int) {
155150
val receiver = channelReceivers[streamId]
156151
receiver?.onComplete()
157-
return Completable.complete()
158152
}
159153

160-
private fun handleNext(streamId: Int, frame: Frame): Completable {
154+
private fun handleNext(streamId: Int, frame: Frame) {
161155
val receiver = channelReceivers[streamId]
162156
receiver?.onNext(DefaultPayload(frame))
163-
return Completable.complete()
164157
}
165158

166159
private fun handleFireAndForget(streamId: Int,
167-
result: Completable): Completable {
168-
return result
169-
.doOnSubscribe { d -> sendingSubscriptions[streamId] = subscription(d) }
170-
.doOnError(errorConsumer)
171-
.doFinally { sendingSubscriptions -= streamId }
160+
result: Completable) {
161+
result.subscribe(object : CompletableObserver {
162+
override fun onComplete() {
163+
sendingSubscriptions -= streamId
164+
}
165+
166+
override fun onSubscribe(d: Disposable) {
167+
sendingSubscriptions[streamId] = subscription(d)
168+
}
169+
170+
override fun onError(e: Throwable) {
171+
sendingSubscriptions -= streamId
172+
errorConsumer(e)
173+
}
174+
})
172175
}
173176

174177
private fun handleRequestResponse(streamId: Int,
175-
response: Single<Payload>): Completable {
176-
return response
177-
.doOnSubscribe { d -> sendingSubscriptions[streamId] = subscription(d) }
178-
.map { payload ->
179-
var flags = FLAGS_C
180-
if (payload.hasMetadata) {
181-
flags = Frame.setFlag(flags, FLAGS_M)
182-
}
183-
Frame.PayloadFrame.from(
184-
streamId,
185-
FrameType.NEXT_COMPLETE,
186-
payload,
187-
flags)
178+
response: Single<Payload>) {
179+
response.subscribe(object : SingleObserver<Payload> {
180+
181+
override fun onSuccess(payload: Payload) {
182+
sendingSubscriptions -= streamId
183+
var flags = FLAGS_C
184+
if (payload.hasMetadata) {
185+
flags = Frame.setFlag(flags, FLAGS_M)
188186
}
189-
.onErrorResumeNext { t -> Single.just(Frame.Error.from(streamId, t)) }
190-
.doOnSuccess { frameSender.send(it) }
191-
.doFinally { sendingSubscriptions -= streamId }
192-
.ignoreElement()
187+
frameSender.send(Frame.PayloadFrame.from(
188+
streamId,
189+
FrameType.NEXT_COMPLETE,
190+
payload,
191+
flags))
192+
}
193+
194+
override fun onSubscribe(d: Disposable) {
195+
sendingSubscriptions[streamId] = subscription(d)
196+
}
197+
198+
override fun onError(e: Throwable) {
199+
sendingSubscriptions -= streamId
200+
val frame = when (e) {
201+
is NoSuchElementException -> Frame.PayloadFrame.from(streamId, FrameType.COMPLETE)
202+
else -> Frame.Error.from(streamId, e)
203+
}
204+
frameSender.send(frame)
205+
}
206+
})
193207
}
194208

195209
private fun handleStream(streamId: Int,
196210
response: Flowable<Payload>,
197-
initialRequestN: Int): Completable {
211+
initialRequestN: Int) {
198212
response
199-
.map { payload -> Frame.PayloadFrame.from(streamId, FrameType.NEXT, payload) }
200213
.compose { frameFlux ->
201214
val frames = RequestingPublisher.wrap(frameFlux)
202215
sendingSubscriptions[streamId] = frames
203-
frames.request(initialRequestN.toLong())
216+
frames.request(reactiveStreamsRequestN(initialRequestN))
204217
frames
205218
}
206-
.concatWith(Flowable.just(Frame.PayloadFrame.from(streamId, FrameType.COMPLETE)))
207-
.onErrorResumeNext { t: Throwable -> Flowable.just(Frame.Error.from(streamId, t)) }
208-
.doFinally { sendingSubscriptions -= streamId }
209-
.subscribe { frameSender.send(it) }
210-
return Completable.complete()
219+
.subscribe(object : Subscriber<Payload> {
220+
221+
override fun onSubscribe(s: Subscription) {
222+
s.request(Long.MAX_VALUE)
223+
}
224+
225+
override fun onNext(payload: Payload) {
226+
frameSender.send(Frame.PayloadFrame.from(streamId, FrameType.NEXT, payload))
227+
}
228+
229+
override fun onComplete() {
230+
sendingSubscriptions -= streamId
231+
frameSender.send(Frame.PayloadFrame.from(streamId, FrameType.COMPLETE))
232+
}
233+
234+
override fun onError(t: Throwable) {
235+
sendingSubscriptions -= streamId
236+
frameSender.send(Frame.Error.from(streamId, t))
237+
}
238+
})
211239
}
212240

213-
private fun handleChannel(streamId: Int, firstFrame: Frame): Completable {
241+
private fun handleChannel(streamId: Int, firstFrame: Frame) {
214242
val receiver = StreamReceiver.create()
215243
channelReceivers[streamId] = receiver
216244

@@ -222,25 +250,32 @@ internal class RSocketResponder(
222250

223251
receiver.onNext(DefaultPayload(firstFrame))
224252

225-
return handleStream(
253+
handleStream(
226254
streamId,
227255
requestChannel(request),
228256
initialRequestN(firstFrame))
229257
}
230258

231-
private fun handleCancel(streamId: Int): Completable {
259+
private fun handleMetadataPush(result: Completable) {
260+
result.subscribe(object : CompletableObserver {
261+
override fun onComplete() {
262+
}
263+
264+
override fun onSubscribe(d: Disposable) {
265+
}
266+
267+
override fun onError(e: Throwable) = errorConsumer(e)
268+
})
269+
}
270+
271+
private fun handleCancel(streamId: Int) {
232272
val subscription = sendingSubscriptions.remove(streamId)
233273
subscription?.cancel()
234-
return Completable.complete()
235274
}
236275

237-
private fun handleRequestN(streamId: Int, frame: Frame): Completable {
276+
private fun handleRequestN(streamId: Int, frame: Frame) {
238277
val subscription = sendingSubscriptions[streamId]
239-
subscription?.let {
240-
val n = Frame.RequestN.requestN(frame).toLong()
241-
it.request(if (n >= Integer.MAX_VALUE) Long.MAX_VALUE else n)
242-
}
243-
return Completable.complete()
278+
subscription?.request(reactiveStreamsRequestN(Frame.RequestN.requestN(frame)))
244279
}
245280

246281
private inner class Lifecycle {
@@ -261,8 +296,8 @@ internal class RSocketResponder(
261296
.close()
262297
.subscribe({}, errorConsumer)
263298

264-
cleanUp(sendingSubscriptions, { it.cancel() })
265-
cleanUp(channelReceivers, { it.onError(err) })
299+
cleanUp(sendingSubscriptions) { it.cancel() }
300+
cleanUp(channelReceivers) { it.onError(err) }
266301
}
267302
}
268303

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.rsocket.kotlin.internal.util
2+
3+
internal fun reactiveStreamsRequestN(initialRequestN: Int) =
4+
if (initialRequestN == Int.MAX_VALUE) {
5+
Long.MAX_VALUE
6+
} else {
7+
initialRequestN.toLong()
8+
}

0 commit comments

Comments
 (0)