final AtomicReference<Exception> exception = new AtomicReference<Exception>();
try {
final ExecutorService executor = Executors.newFixedThreadPool(concurrencyLevel, new ThreadFactoryBuilder()
.setDaemon(true).setNameFormat("ChunkWriter-" + objectName + "-%d").build());
final BlockingConcurrentWindowCounter chunkCounter = new BlockingConcurrentWindowCounter(concurrencyLevel);
final AutoAllocatingLinkedBlockingQueue<ByteBuffer> blocks = new AutoAllocatingLinkedBlockingQueue<ByteBuffer>(
concurrencyLevel);
try {
// Write file data one block at a time
boolean done = false;
while (!done && exception.get() == null) {
// This throttles us so we don't get too far ahead of
// ourselves if one of the threads is stuck
final int chunkNumber = chunkCounter.incrementAndGet();
// Get a block or allocate a new one
final ByteBuffer bb = blocks.poll(new Supplier<ByteBuffer>() {
@Override
public ByteBuffer get() {
return ByteBuffer.allocate(chunkSize);
}
});
// Reset the array and copy some data
bb.position(0);
int nBytesRead = readFully(is, bb.array(), 0, chunkSize);
if (nBytesRead > 0) {
bb.limit(nBytesRead);
// Send data in a worker thread
executor.submit(new Runnable() {
@Override
public void run() {
try {
if (exception.get() == null) {
LOG.debug("WRITE " + chunkNumber + " size=" + bb.limit());
provider.writeChunk(objectName, chunkNumber, bb, ttl);
callback.onChunk(chunkNumber, bb.limit());
nBytesWritten.addAndGet(bb.limit());
nChunksWritten.incrementAndGet();
}
}
catch (Exception e) {
LOG.error(e.getMessage());
exception.compareAndSet(null, e);
callback.onChunkException(chunkNumber, e);
}
finally {
blocks.add(bb);
chunkCounter.release(chunkNumber);
}
}
});
}
else {