|
|
|
@ -57,6 +57,12 @@ public abstract class DataBufferUtils { |
|
|
|
|
|
|
|
|
|
|
|
private static final Consumer<DataBuffer> RELEASE_CONSUMER = DataBufferUtils::release; |
|
|
|
private static final Consumer<DataBuffer> RELEASE_CONSUMER = DataBufferUtils::release; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Workaround to disable use of pooled buffers: |
|
|
|
|
|
|
|
* https://github.com/reactor/reactor-core/issues/1634
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static final DataBufferFactory defaultDataBufferFactory = new DefaultDataBufferFactory(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
// Reading
|
|
|
|
// Reading
|
|
|
|
@ -132,16 +138,21 @@ public abstract class DataBufferUtils { |
|
|
|
Assert.isTrue(position >= 0, "'position' must be >= 0"); |
|
|
|
Assert.isTrue(position >= 0, "'position' must be >= 0"); |
|
|
|
Assert.isTrue(bufferSize > 0, "'bufferSize' must be > 0"); |
|
|
|
Assert.isTrue(bufferSize > 0, "'bufferSize' must be > 0"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DataBufferFactory bufferFactoryToUse = defaultDataBufferFactory; |
|
|
|
|
|
|
|
|
|
|
|
Flux<DataBuffer> flux = Flux.using(channelSupplier, |
|
|
|
Flux<DataBuffer> flux = Flux.using(channelSupplier, |
|
|
|
channel -> Flux.create(sink -> { |
|
|
|
channel -> Flux.create(sink -> { |
|
|
|
ReadCompletionHandler handler = |
|
|
|
ReadCompletionHandler handler = |
|
|
|
new ReadCompletionHandler(channel, sink, position, bufferFactory, bufferSize); |
|
|
|
new ReadCompletionHandler(channel, sink, position, bufferFactoryToUse, bufferSize); |
|
|
|
DataBuffer dataBuffer = bufferFactory.allocateBuffer(bufferSize); |
|
|
|
DataBuffer dataBuffer = bufferFactoryToUse.allocateBuffer(bufferSize); |
|
|
|
ByteBuffer byteBuffer = dataBuffer.asByteBuffer(0, bufferSize); |
|
|
|
ByteBuffer byteBuffer = dataBuffer.asByteBuffer(0, bufferSize); |
|
|
|
channel.read(byteBuffer, position, dataBuffer, handler); |
|
|
|
channel.read(byteBuffer, position, dataBuffer, handler); |
|
|
|
sink.onDispose(handler::dispose); |
|
|
|
sink.onDispose(handler::dispose); |
|
|
|
}), |
|
|
|
}), |
|
|
|
DataBufferUtils::closeChannel); |
|
|
|
channel -> { |
|
|
|
|
|
|
|
// Do not close channel from here, rather wait for the current read callback
|
|
|
|
|
|
|
|
// and then complete after releasing the DataBuffer.
|
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
return flux.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release); |
|
|
|
return flux.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -505,26 +516,40 @@ public abstract class DataBufferUtils { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void completed(Integer read, DataBuffer dataBuffer) { |
|
|
|
public void completed(Integer read, DataBuffer dataBuffer) { |
|
|
|
if (read != -1) { |
|
|
|
if (read != -1 && !this.disposed.get()) { |
|
|
|
long pos = this.position.addAndGet(read); |
|
|
|
long pos = this.position.addAndGet(read); |
|
|
|
dataBuffer.writePosition(read); |
|
|
|
dataBuffer.writePosition(read); |
|
|
|
this.sink.next(dataBuffer); |
|
|
|
this.sink.next(dataBuffer); |
|
|
|
if (!this.disposed.get()) { |
|
|
|
// It's possible for cancellation to happen right before the push into the sink
|
|
|
|
|
|
|
|
if (this.disposed.get()) { |
|
|
|
|
|
|
|
// TODO:
|
|
|
|
|
|
|
|
// This is not ideal since we already passed the buffer into the sink and
|
|
|
|
|
|
|
|
// releasing may cause something reading to fail. Maybe we won't have to
|
|
|
|
|
|
|
|
// do this after https://github.com/reactor/reactor-core/issues/1634
|
|
|
|
|
|
|
|
complete(dataBuffer); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
DataBuffer newDataBuffer = this.dataBufferFactory.allocateBuffer(this.bufferSize); |
|
|
|
DataBuffer newDataBuffer = this.dataBufferFactory.allocateBuffer(this.bufferSize); |
|
|
|
ByteBuffer newByteBuffer = newDataBuffer.asByteBuffer(0, this.bufferSize); |
|
|
|
ByteBuffer newByteBuffer = newDataBuffer.asByteBuffer(0, this.bufferSize); |
|
|
|
this.channel.read(newByteBuffer, pos, newDataBuffer, this); |
|
|
|
this.channel.read(newByteBuffer, pos, newDataBuffer, this); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
release(dataBuffer); |
|
|
|
complete(dataBuffer); |
|
|
|
this.sink.complete(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void complete(DataBuffer dataBuffer) { |
|
|
|
|
|
|
|
release(dataBuffer); |
|
|
|
|
|
|
|
this.sink.complete(); |
|
|
|
|
|
|
|
closeChannel(this.channel); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void failed(Throwable exc, DataBuffer dataBuffer) { |
|
|
|
public void failed(Throwable exc, DataBuffer dataBuffer) { |
|
|
|
release(dataBuffer); |
|
|
|
release(dataBuffer); |
|
|
|
this.sink.error(exc); |
|
|
|
this.sink.error(exc); |
|
|
|
|
|
|
|
closeChannel(this.channel); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void dispose() { |
|
|
|
public void dispose() { |
|
|
|
|