@@ -31,16 +31,23 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
3131 * non-composite copy of the buffer.
3232 */
3333 private static final int MAX_CAPACITY = Integer .MAX_VALUE - 8 ;
34- private static final Drop <CompositeBuffer > COMPOSITE_DROP = buf -> {
35- for (Buffer b : buf .bufs ) {
36- b .close ();
34+ private static final Drop <CompositeBuffer > COMPOSITE_DROP = new Drop <CompositeBuffer >() {
35+ @ Override
36+ public void drop (CompositeBuffer buf ) {
37+ for (Buffer b : buf .bufs ) {
38+ b .close ();
39+ }
40+ buf .makeInaccessible ();
41+ }
42+
43+ @ Override
44+ public String toString () {
45+ return "COMPOSITE_DROP" ;
3746 }
38- buf .makeInaccessible ();
3947 };
4048
4149 private final BufferAllocator allocator ;
4250 private final TornBufferAccessors tornBufAccessors ;
43- private final boolean isSendable ;
4451 private Buffer [] bufs ;
4552 private int [] offsets ; // The offset, for the composite buffer, where each constituent buffer starts.
4653 private int capacity ;
@@ -52,7 +59,7 @@ final class CompositeBuffer extends RcSupport<Buffer, CompositeBuffer> implement
5259 private boolean readOnly ;
5360
5461 CompositeBuffer (BufferAllocator allocator , Deref <Buffer >[] refs ) {
55- this (allocator , true , filterExternalBufs (refs ), COMPOSITE_DROP , false );
62+ this (allocator , filterExternalBufs (refs ), COMPOSITE_DROP , false );
5663 }
5764
5865 private static Buffer [] filterExternalBufs (Deref <Buffer >[] refs ) {
@@ -106,11 +113,10 @@ private static Stream<Buffer> flattenBuffer(Buffer buf) {
106113 return Stream .of (buf );
107114 }
108115
109- private CompositeBuffer (BufferAllocator allocator , boolean isSendable , Buffer [] bufs , Drop <CompositeBuffer > drop ,
116+ private CompositeBuffer (BufferAllocator allocator , Buffer [] bufs , Drop <CompositeBuffer > drop ,
110117 boolean acquireBufs ) {
111118 super (drop );
112119 this .allocator = allocator ;
113- this .isSendable = isSendable ;
114120 if (acquireBufs ) {
115121 for (Buffer buf : bufs ) {
116122 buf .acquire ();
@@ -297,46 +303,31 @@ public Buffer slice(int offset, int length) {
297303 offset + ", and length was " + length + '.' );
298304 }
299305 Buffer choice = (Buffer ) chooseBuffer (offset , 0 );
300- Buffer [] slices = null ;
301- acquire (); // Increase reference count of the original composite buffer.
302- Drop <CompositeBuffer > drop = obj -> {
303- close (); // Decrement the reference count of the original composite buffer.
304- COMPOSITE_DROP .drop (obj );
305- };
306-
307- try {
308- if (length > 0 ) {
309- slices = new Buffer [bufs .length ];
310- int off = subOffset ;
311- int cap = length ;
312- int i ;
313- for (i = searchOffsets (offset ); cap > 0 ; i ++) {
314- var buf = bufs [i ];
315- int avail = buf .capacity () - off ;
316- slices [i ] = buf .slice (off , Math .min (cap , avail ));
317- cap -= avail ;
318- off = 0 ;
319- }
320- slices = Arrays .copyOf (slices , i );
321- } else {
322- // Specialize for length == 0, since we must slice from at least one constituent buffer.
323- slices = new Buffer [] { choice .slice (subOffset , 0 ) };
324- }
325-
326- return new CompositeBuffer (allocator , false , slices , drop , true );
327- } catch (Throwable throwable ) {
328- // We called acquire prior to the try-clause. We need to undo that if we're not creating a composite buffer:
329- close ();
330- throw throwable ;
331- } finally {
332- if (slices != null ) {
333- for (Buffer slice : slices ) {
334- if (slice != null ) {
335- slice .close (); // Ownership now transfers to the composite buffer.
336- }
337- }
338- }
306+ Buffer [] slices ;
307+
308+ if (length > 0 ) {
309+ slices = new Buffer [bufs .length ];
310+ int off = subOffset ;
311+ int cap = length ;
312+ int i ;
313+ for (i = searchOffsets (offset ); cap > 0 ; i ++) {
314+ var buf = bufs [i ];
315+ int avail = buf .capacity () - off ;
316+ slices [i ] = buf .slice (off , Math .min (cap , avail ));
317+ cap -= avail ;
318+ off = 0 ;
319+ }
320+ slices = Arrays .copyOf (slices , i );
321+ } else {
322+ // Specialize for length == 0, since we must slice from at least one constituent buffer.
323+ slices = new Buffer [] { choice .slice (subOffset , 0 ) };
339324 }
325+
326+ // Use the constructor that skips filtering out empty buffers, and skips acquiring on the buffers.
327+ // This is important because 1) slice() already acquired the buffers, and 2) if this slice is empty
328+ // then we need to keep holding on to it to prevent this originating composite buffer from getting
329+ // ownership. If it did, its behaviour would be inconsistent with that of a non-composite buffer.
330+ return new CompositeBuffer (allocator , slices , COMPOSITE_DROP , false );
340331 }
341332
342333 @ Override
@@ -749,7 +740,7 @@ public Buffer bifurcate() {
749740 }
750741 if (bufs .length == 0 ) {
751742 // Bifurcating a zero-length buffer is trivial.
752- return new CompositeBuffer (allocator , true , bufs , unsafeGetDrop (), true ).order (order );
743+ return new CompositeBuffer (allocator , bufs , unsafeGetDrop (), true ).order (order );
753744 }
754745
755746 int i = searchOffsets (woff );
@@ -761,7 +752,7 @@ public Buffer bifurcate() {
761752 }
762753 computeBufferOffsets ();
763754 try {
764- var compositeBuf = new CompositeBuffer (allocator , true , bifs , unsafeGetDrop (), true );
755+ var compositeBuf = new CompositeBuffer (allocator , bifs , unsafeGetDrop (), true );
765756 compositeBuf .order = order ; // Preserve byte order even if bifs array is empty.
766757 return compositeBuf ;
767758 } finally {
@@ -1164,7 +1155,7 @@ public CompositeBuffer transferOwnership(Drop<CompositeBuffer> drop) {
11641155 for (int i = 0 ; i < sends .length ; i ++) {
11651156 received [i ] = sends [i ].receive ();
11661157 }
1167- var composite = new CompositeBuffer (allocator , true , received , drop , true );
1158+ var composite = new CompositeBuffer (allocator , received , drop , true );
11681159 composite .readOnly = readOnly ;
11691160 drop .attach (composite );
11701161 return composite ;
@@ -1179,18 +1170,9 @@ void makeInaccessible() {
11791170 closed = true ;
11801171 }
11811172
1182- @ Override
1183- protected IllegalStateException notSendableException () {
1184- if (!isSendable ) {
1185- return new IllegalStateException (
1186- "Cannot send() this buffer. This buffer might be a slice of another buffer." );
1187- }
1188- return super .notSendableException ();
1189- }
1190-
11911173 @ Override
11921174 public boolean isOwned () {
1193- return isSendable && super .isOwned () && allConstituentsAreOwned ();
1175+ return super .isOwned () && allConstituentsAreOwned ();
11941176 }
11951177
11961178 private boolean allConstituentsAreOwned () {
0 commit comments