@@ -5,8 +5,13 @@ import java.io.*
5
5
import java.nio.ByteBuffer
6
6
import java.nio.CharBuffer
7
7
import java.util.*
8
+ import kotlin.NoSuchElementException
9
+
10
+ internal class ByteWritePacketImpl (private var headerSizeHint : Int , private val pool : ObjectPool <ByteBuffer >) : ByteWritePacket {
11
+ init {
12
+ require(headerSizeHint >= 0 ) { " shouldn't be negative: headerSizeHint = $headerSizeHint " }
13
+ }
8
14
9
- internal class ByteWritePacketImpl (private val pool : ObjectPool <ByteBuffer >) : ByteWritePacket {
10
15
override var size: Int = 0
11
16
private set
12
17
private var buffers: Any? = null
@@ -86,22 +91,72 @@ internal class ByteWritePacketImpl(private val pool: ObjectPool<ByteBuffer>) : B
86
91
override fun writePacket (p : ByteReadPacket ) {
87
92
when (p) {
88
93
is ByteReadPacketEmpty -> {}
89
- is ByteReadPacketSingle -> {
90
- if (p.remaining > 0 ) {
91
- size + = p.remaining
92
- last(p.steal().also { it.compact() })
94
+ is ByteReadPacketSingle -> writePacketSingle(p)
95
+ is ByteReadPacketImpl -> writePacketMultiple(p)
96
+ else -> writeFully(p.readBytes())
97
+ }
98
+ }
99
+
100
+ private fun reverseCopyToForeignBuffer (count : Int , last : ByteBuffer , buffer : ByteBuffer ) {
101
+ val startOffset = buffer.position() - count
102
+ val l = buffer.limit()
103
+ buffer.position(startOffset)
104
+ buffer.limit(startOffset + count)
105
+
106
+ last.flip()
107
+ last.position(last.limit() - count)
108
+ buffer.put(last)
109
+
110
+ recycleLast()
111
+ headerSizeHint = startOffset
112
+ buffer.limit(buffer.capacity())
113
+ buffer.position(l)
114
+ last(buffer)
115
+ }
116
+
117
+ private fun writePacketSingle (p : ByteReadPacketSingle ) {
118
+ val initialRemaining = p.remaining
119
+ if (initialRemaining > 0 ) {
120
+ size + = initialRemaining
121
+ writePacketBuffer(p.steal())
122
+ }
123
+ }
124
+
125
+ private fun writePacketMultiple (p : ByteReadPacketImpl ) {
126
+ val initialRemaining = p.remaining
127
+ if (initialRemaining > 0 ) {
128
+ size + = initialRemaining
129
+
130
+ do {
131
+ writePacketBuffer(p.steal())
132
+ } while (p.remaining > 0 )
133
+ }
134
+ }
135
+
136
+ private fun writePacketBuffer (buffer : ByteBuffer ) {
137
+ val last = last()
138
+
139
+ if (buffer.position() > 0 && last != null ) {
140
+ if (last == = buffers || buffersCount() == 1 ) {
141
+ val count = last.position() - headerSizeHint
142
+ if (count < PACKET_MAX_COPY_SIZE && count <= buffer.position()) {
143
+ reverseCopyToForeignBuffer(count, last, buffer)
144
+ return
93
145
}
94
- }
95
- is ByteReadPacketImpl -> {
96
- size + = p.remaining
97
- while (p.remaining > 0 ) {
98
- last(p.steal(). also { it.compact() })
146
+ } else {
147
+ val count = last.position()
148
+ if (count < PACKET_MAX_COPY_SIZE && count == buffer.position()) {
149
+ reverseCopyToForeignBuffer(count, last, buffer)
150
+ return
99
151
}
100
152
}
101
- else -> {
102
- writeFully(p.readBytes())
103
- }
153
+ } else if (last != null && last.remaining() <= buffer.remaining() && buffer.remaining() < PACKET_MAX_COPY_SIZE ) {
154
+ last.put(buffer)
155
+ recycle(buffer)
156
+ return
104
157
}
158
+
159
+ last(buffer.also { it.compact() })
105
160
}
106
161
107
162
override fun writePacketUnconsumed (p : ByteReadPacket ) {
@@ -264,22 +319,43 @@ internal class ByteWritePacketImpl(private val pool: ObjectPool<ByteBuffer>) : B
264
319
}
265
320
266
321
override fun build (): ByteReadPacket {
267
- val bs = buffers ? : return ByteReadPacketEmpty
322
+ val bs = buffers
268
323
buffers = null
324
+ size = 0
269
325
270
- return if (bs is ArrayDeque <* >) {
271
- @Suppress(" UNCHECKED_CAST" )
272
- when {
273
- bs.isEmpty() -> ByteReadPacketEmpty
274
- bs.size == 1 -> ByteReadPacketSingle ((bs.first as ByteBuffer ).also { it.flip() }, pool)
275
- else -> ByteReadPacketImpl ((bs as ArrayDeque <ByteBuffer >).also {
276
- for (b in bs) {
277
- b.flip()
278
- }
279
- }, pool)
326
+ return when (bs) {
327
+ null -> ByteReadPacketEmpty
328
+ is ArrayDeque <* > -> {
329
+ @Suppress(" UNCHECKED_CAST" ) buildMultiBufferPacket(bs as ArrayDeque <ByteBuffer >)
330
+ }
331
+ else -> ByteReadPacketSingle ((bs as ByteBuffer ).also { switchBufferToRead(true , it) }, pool)
332
+ }
333
+ }
334
+
335
+ private fun buildMultiBufferPacket (buffers : ArrayDeque <ByteBuffer >): ByteReadPacket {
336
+ return when (buffers.size) {
337
+ 0 -> ByteReadPacketEmpty
338
+ 1 -> ByteReadPacketSingle (buffers.first.also { switchBufferToRead(true , it) }, pool)
339
+ else -> {
340
+ val it = buffers.iterator()
341
+ switchBufferToRead(true , it.next())
342
+ do {
343
+ switchBufferToRead(false , it.next())
344
+ } while (it.hasNext())
345
+
346
+ ByteReadPacketImpl (buffers, pool)
347
+ }
348
+ }
349
+ }
350
+
351
+ private fun switchBufferToRead (first : Boolean , bb : ByteBuffer ) {
352
+ bb.flip()
353
+
354
+ if (first) {
355
+ val skip = headerSizeHint
356
+ if (skip > 0 ) {
357
+ bb.position(bb.position() + skip)
280
358
}
281
- } else {
282
- ByteReadPacketSingle ((bs as ByteBuffer ).also { it.flip() }, pool)
283
359
}
284
360
}
285
361
@@ -297,6 +373,10 @@ internal class ByteWritePacketImpl(private val pool: ObjectPool<ByteBuffer>) : B
297
373
}
298
374
}
299
375
376
+ override fun reset () {
377
+ release()
378
+ }
379
+
300
380
private inline fun write (size : Int , block : (ByteBuffer ) -> Unit ) {
301
381
val buffer = last()?.takeIf { it.remaining() >= size }
302
382
@@ -313,6 +393,9 @@ internal class ByteWritePacketImpl(private val pool: ObjectPool<ByteBuffer>) : B
313
393
val new = pool.borrow()
314
394
new.clear()
315
395
last(new)
396
+ if (buffers == = new) {
397
+ new.position(headerSizeHint)
398
+ }
316
399
return new
317
400
}
318
401
@@ -328,15 +411,44 @@ internal class ByteWritePacketImpl(private val pool: ObjectPool<ByteBuffer>) : B
328
411
private fun last (new : ByteBuffer ) {
329
412
@Suppress(" UNCHECKED_CAST" )
330
413
if (buffers is ArrayDeque <* >) (buffers as ArrayDeque <ByteBuffer >).addLast(new)
331
- else if (buffers == null ) buffers = new
332
- else {
414
+ else if (buffers == null ) {
415
+ buffers = new
416
+ } else {
333
417
val dq = ArrayDeque <ByteBuffer >()
334
418
dq.addFirst(buffers as ByteBuffer )
335
419
dq.addLast(new)
336
420
buffers = dq
337
421
}
338
422
}
339
423
424
+ private fun recycleLast () {
425
+ val b = buffers
426
+ when (b) {
427
+ is ArrayDeque <* > -> {
428
+ recycle(b.pollLast() as ByteBuffer )
429
+ if (b.isEmpty()) {
430
+ buffers = null
431
+ }
432
+ }
433
+ is ByteBuffer -> {
434
+ buffers = null
435
+ recycle(b)
436
+ }
437
+ else -> throw NoSuchElementException (" Unable to recycle last buffer: buffers chain is empty" )
438
+ }
439
+ }
440
+
441
+ private fun buffersCount (): Int {
442
+ val bb = buffers
443
+
444
+ return when (bb) {
445
+ null -> 0
446
+ is ByteBuffer -> 1
447
+ is ArrayDeque <* > -> bb.size
448
+ else -> 0
449
+ }
450
+ }
451
+
340
452
private fun recycle (buffer : ByteBuffer ) {
341
453
pool.recycle(buffer)
342
454
}
0 commit comments