@@ -4,9 +4,11 @@ package kotlinx.coroutines.experimental.io
4
4
5
5
import kotlinx.coroutines.experimental.CancellableContinuation
6
6
import kotlinx.coroutines.experimental.channels.ClosedReceiveChannelException
7
+ import kotlinx.coroutines.experimental.io.buffers.*
7
8
import kotlinx.coroutines.experimental.io.internal.*
8
9
import kotlinx.coroutines.experimental.io.packet.*
9
10
import kotlinx.coroutines.experimental.suspendCancellableCoroutine
11
+ import java.io.*
10
12
import java.nio.BufferOverflowException
11
13
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
12
14
@@ -370,26 +372,60 @@ internal class ByteBufferChannel(
370
372
suspend override fun readPacket (size : Int , headerSizeHint : Int ): ByteReadPacket {
371
373
closed?.cause?.let { throw it }
372
374
373
- if (size == 0 ) return ByteReadPacketEmpty
375
+ if (size == 0 ) return ByteReadPacketViewBased . Empty
374
376
375
- val builder = ByteWritePacketImpl (headerSizeHint, BufferPool )
377
+ val builder = ByteWritePacketImpl (headerSizeHint, BufferView . Pool )
376
378
val buffer = BufferPool .borrow()
379
+ var remaining = size
380
+
381
+ try {
382
+ while (remaining > 0 ) {
383
+ buffer.clear()
384
+ if (buffer.remaining() > remaining) {
385
+ buffer.limit(remaining)
386
+ }
387
+
388
+ val rc = readAsMuchAsPossible(buffer)
389
+ if (rc == 0 ) break
390
+
391
+ buffer.flip()
392
+ builder.writeFully(buffer)
393
+
394
+ remaining - = rc
395
+ }
396
+ } catch (t: Throwable ) {
397
+ BufferPool .recycle(buffer)
398
+ builder.release()
399
+ throw t
400
+ }
401
+
402
+ return if (remaining == 0 ) {
403
+ BufferPool .recycle(buffer)
404
+ builder.build()
405
+ } else {
406
+ readPacketSuspend(remaining, builder, buffer)
407
+ }
408
+ }
409
+
410
+ private suspend fun readPacketSuspend (size : Int , builder : ByteWritePacketImpl , buffer : ByteBuffer ): ByteReadPacket {
411
+ var remaining = size
377
412
378
413
try {
379
- var remaining = size
380
414
while (remaining > 0 ) {
381
415
buffer.clear()
382
416
if (buffer.remaining() > remaining) {
383
417
buffer.limit(remaining)
384
418
}
385
419
386
420
val rc = readFully(buffer)
421
+
387
422
buffer.flip()
388
423
builder.writeFully(buffer)
389
424
390
425
remaining - = rc
391
426
}
392
427
428
+
393
429
return builder.build()
394
430
} catch (t: Throwable ) {
395
431
builder.release()
@@ -837,82 +873,125 @@ internal class ByteBufferChannel(
837
873
closed?.sendException?.let { packet.release(); throw it }
838
874
839
875
when (packet) {
840
- is ByteReadPacketEmpty -> return
841
- is ByteReadPacketSingle -> writeSingleBufferPacket(packet)
842
- is ByteReadPacketImpl -> writeMultipleBufferPacket(packet)
876
+ ByteReadPacketEmpty -> return
877
+ is ByteReadPacketViewBased -> writeViewBasedPacket(packet)
843
878
else -> writeExternalPacket(packet)
844
879
}
845
880
}
846
881
847
- private suspend fun writeSingleBufferPacket (packet : ByteReadPacketSingle ) {
848
- val buffer = packet.steal()
849
- val t = try {
850
- writeAsMuchAsPossible(buffer)
851
- null
852
- } catch (t: Throwable ) {
853
- t
854
- }
882
+ override suspend fun write (min : Int , block : (ByteBuffer ) -> Unit ) {
883
+ require(min > 0 ) { " min should be positive" }
855
884
856
- if (t != null ) {
857
- packet.pool.recycle(buffer)
858
- throw t
885
+ var written = false
886
+
887
+ writing {
888
+ if (it.availableForWrite >= min) {
889
+ val position = this .position()
890
+ val l = this .limit()
891
+ block(this )
892
+ if (l != this .limit()) throw IllegalStateException (" buffer limit modified" )
893
+ val delta = position() - position
894
+ if (delta < 0 ) throw IllegalStateException (" position has been moved backward: pushback is not supported" )
895
+
896
+ if (! it.tryWriteExact(delta)) throw IllegalStateException ()
897
+ bytesWritten(it, delta)
898
+ written = true
899
+ }
859
900
}
860
901
861
- if (buffer.hasRemaining() ) {
862
- return writeSingleBufferPacketSuspend(buffer, packet )
902
+ if (! written ) {
903
+ return writeBlockSuspend(min, block )
863
904
}
905
+ }
864
906
865
- packet.pool.recycle(buffer)
907
+ private suspend fun writeBlockSuspend (min : Int , block : (ByteBuffer ) -> Unit ) {
908
+ writeSuspend(min)
909
+ write(min, block)
866
910
}
867
911
868
- private suspend fun writeMultipleBufferPacket ( packet : ByteReadPacketImpl ) {
869
- var buffer : ByteBuffer ? = null
912
+ override suspend fun read ( min : Int , block : ( ByteBuffer ) -> Unit ) {
913
+ require(min > 0 ) { " min should be positive " }
870
914
871
- val t = try {
872
- while (packet.remaining > 0 ) {
873
- buffer = packet.steal()
874
- writeAsMuchAsPossible(buffer)
875
- if (buffer.hasRemaining()) break
876
- packet.pool.recycle(buffer)
877
- buffer = null
878
- }
879
- null
880
- } catch (t: Throwable ) { t }
915
+ val read = reading {
916
+ if (it.availableForRead >= min) {
917
+ val position = this .position()
918
+ val l = this .limit()
919
+ block(this )
920
+ if (l != this .limit()) throw IllegalStateException (" buffer limit modified" )
921
+ val delta = position() - position
922
+ if (delta < 0 ) throw IllegalStateException (" position has been moved backward: pushback is not supported" )
881
923
882
- if (t != null ) {
883
- buffer?.let { packet.pool.recycle(it) }
884
- packet.release()
885
- throw t
924
+ if (! it.tryReadExact(delta)) throw IllegalStateException ()
925
+ bytesRead(it, delta)
926
+ true
927
+ }
928
+ else false
886
929
}
887
930
888
- if (buffer != null ) {
889
- return writeMultipleBufferPacketSuspend(buffer, packet )
931
+ if (! read ) {
932
+ readBlockSuspend(min, block )
890
933
}
934
+ }
891
935
892
- packet.release()
936
+ private suspend fun readBlockSuspend (min : Int , block : (ByteBuffer ) -> Unit ) {
937
+ if (! readSuspend(min)) throw EOFException (" Got EOF but at least $min bytes were expected" )
938
+ read(min, block)
893
939
}
894
940
895
- private suspend fun writeSingleBufferPacketSuspend (buffer : ByteBuffer , packet : ByteReadPacketSingle ) {
896
- try {
897
- writeFully(buffer)
898
- } finally {
899
- packet.pool.recycle(buffer)
941
+ private suspend fun writeViewBasedPacket (packet : ByteReadPacketViewBased ) {
942
+ while (! packet.isEmpty) {
943
+ val node = packet.steal() ? : break
944
+
945
+ var written: Int
946
+
947
+ while (node.readRemaining > 0 ) {
948
+ try {
949
+ written = 0
950
+ writing {
951
+ val size = minOf(remaining(), node.readRemaining)
952
+ if (! it.tryWriteExact(size)) throw IllegalStateException ()
953
+ written = node.read(this , size)
954
+ bytesWritten(it, size)
955
+ }
956
+ } catch (t: Throwable ) {
957
+ node.release()
958
+ packet.release()
959
+ throw t
960
+ }
961
+
962
+ if (written == 0 && node.readRemaining > 0 ) {
963
+ return writeViewBasedPacketSuspend(packet, node)
964
+ }
965
+ }
966
+
967
+ node.release()
900
968
}
901
969
}
902
970
903
- private suspend fun writeMultipleBufferPacketSuspend ( rem : ByteBuffer , packet : ByteReadPacketImpl ) {
904
- var buffer = rem
971
+ private suspend fun writeViewBasedPacketSuspend ( packet : ByteReadPacketViewBased , node0 : BufferView ) {
972
+ var node : BufferView ? = node0
905
973
906
974
try {
907
- do {
908
- writeFully(buffer)
909
- if (packet.remaining == 0 ) break
910
- packet.pool.recycle(buffer)
911
- buffer = packet.steal()
912
- } while (true )
913
- } finally {
914
- packet.pool.recycle(buffer)
975
+ while ((node != null && node.readRemaining > 0 ) || ! packet.isEmpty) {
976
+ while (node != null && node.readRemaining > 0 ) {
977
+ writeSuspend(1 )
978
+ writing {
979
+ val size = minOf(remaining(), node!! .readRemaining)
980
+ if (! it.tryWriteExact(size)) throw IllegalStateException ()
981
+ node!! .read(this , size)
982
+ bytesWritten(it, size)
983
+ }
984
+
985
+ if (node.readRemaining == 0 ) {
986
+ node.release()
987
+ node = packet.steal()
988
+ }
989
+ }
990
+ }
991
+ } catch (t: Throwable ) {
992
+ node?.release()
915
993
packet.release()
994
+ throw t
916
995
}
917
996
}
918
997
@@ -927,6 +1006,8 @@ internal class ByteBufferChannel(
927
1006
if (buffer.hasRemaining()) {
928
1007
buffer.compact()
929
1008
break
1009
+ } else {
1010
+ buffer.compact()
930
1011
}
931
1012
}
932
1013
@@ -935,15 +1016,19 @@ internal class ByteBufferChannel(
935
1016
t
936
1017
}
937
1018
1019
+ if (t != null ) {
1020
+ BufferPool .recycle(buffer)
1021
+ packet.release()
1022
+ throw t
1023
+ }
1024
+
938
1025
buffer.flip()
939
1026
if (buffer.hasRemaining()) {
940
1027
return writeExternalPacketSuspend(buffer, packet)
941
1028
}
942
1029
943
1030
BufferPool .recycle(buffer)
944
1031
packet.release()
945
-
946
- if (t != null ) throw t
947
1032
}
948
1033
949
1034
private suspend fun writeExternalPacketSuspend (buffer : ByteBuffer , packet : ByteReadPacket ) {
0 commit comments