|
|
@ -9,6 +9,7 @@ import org.apache.hadoop.fs.StreamCapabilities; |
|
|
|
import org.apache.hadoop.fs.Syncable; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import seaweedfs.client.ByteBufferPool; |
|
|
|
import seaweedfs.client.FilerGrpcClient; |
|
|
|
import seaweedfs.client.FilerProto; |
|
|
|
import seaweedfs.client.SeaweedWrite; |
|
|
@ -16,6 +17,7 @@ import seaweedfs.client.SeaweedWrite; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.InterruptedIOException; |
|
|
|
import java.io.OutputStream; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.Locale; |
|
|
|
import java.util.concurrent.*; |
|
|
@ -33,15 +35,15 @@ public class SeaweedOutputStream extends OutputStream implements Syncable, Strea |
|
|
|
private final ThreadPoolExecutor threadExecutor; |
|
|
|
private final ExecutorCompletionService<Void> completionService; |
|
|
|
private final FilerProto.Entry.Builder entry; |
|
|
|
private final boolean supportFlush = true; |
|
|
|
private final boolean supportFlush = false; // true; |
|
|
|
private final ConcurrentLinkedDeque<WriteOperation> writeOperations; |
|
|
|
private long position; |
|
|
|
private boolean closed; |
|
|
|
private volatile IOException lastError; |
|
|
|
private long lastFlushOffset; |
|
|
|
private long lastTotalAppendOffset = 0; |
|
|
|
private byte[] buffer; |
|
|
|
private int bufferIndex; |
|
|
|
private ByteBuffer buffer; |
|
|
|
private long outputIndex; |
|
|
|
private String replication = "000"; |
|
|
|
|
|
|
|
public SeaweedOutputStream(FilerGrpcClient filerGrpcClient, final Path path, FilerProto.Entry.Builder entry, |
|
|
@ -54,8 +56,8 @@ public class SeaweedOutputStream extends OutputStream implements Syncable, Strea |
|
|
|
this.lastError = null; |
|
|
|
this.lastFlushOffset = 0; |
|
|
|
this.bufferSize = bufferSize; |
|
|
|
// this.buffer = new byte[bufferSize]; |
|
|
|
this.bufferIndex = 0; |
|
|
|
this.buffer = ByteBufferPool.request(bufferSize); |
|
|
|
this.outputIndex = 0; |
|
|
|
this.writeOperations = new ConcurrentLinkedDeque<>(); |
|
|
|
|
|
|
|
this.maxConcurrentRequestCount = 4 * Runtime.getRuntime().availableProcessors(); |
|
|
@ -97,41 +99,29 @@ public class SeaweedOutputStream extends OutputStream implements Syncable, Strea |
|
|
|
throw new IndexOutOfBoundsException(); |
|
|
|
} |
|
|
|
|
|
|
|
// System.out.println(path + " write [" + (outputIndex + off) + "," + ((outputIndex + off) + length) + ")"); |
|
|
|
|
|
|
|
int currentOffset = off; |
|
|
|
int writableBytes = bufferSize - bufferIndex; |
|
|
|
int writableBytes = bufferSize - buffer.position(); |
|
|
|
int numberOfBytesToWrite = length; |
|
|
|
|
|
|
|
while (numberOfBytesToWrite > 0) { |
|
|
|
|
|
|
|
if (buffer == null) { |
|
|
|
buffer = new byte[32]; |
|
|
|
} |
|
|
|
// ensureCapacity |
|
|
|
if (numberOfBytesToWrite > buffer.length - bufferIndex) { |
|
|
|
int capacity = buffer.length; |
|
|
|
while (capacity - bufferIndex < numberOfBytesToWrite) { |
|
|
|
capacity = capacity << 1; |
|
|
|
} |
|
|
|
if (capacity < 0) { |
|
|
|
throw new OutOfMemoryError(); |
|
|
|
} |
|
|
|
buffer = Arrays.copyOf(buffer, capacity); |
|
|
|
} |
|
|
|
|
|
|
|
if (writableBytes <= numberOfBytesToWrite) { |
|
|
|
System.arraycopy(data, currentOffset, buffer, bufferIndex, writableBytes); |
|
|
|
bufferIndex += writableBytes; |
|
|
|
writeCurrentBufferToService(); |
|
|
|
currentOffset += writableBytes; |
|
|
|
numberOfBytesToWrite = numberOfBytesToWrite - writableBytes; |
|
|
|
} else { |
|
|
|
System.arraycopy(data, currentOffset, buffer, bufferIndex, numberOfBytesToWrite); |
|
|
|
bufferIndex += numberOfBytesToWrite; |
|
|
|
numberOfBytesToWrite = 0; |
|
|
|
if (numberOfBytesToWrite < writableBytes) { |
|
|
|
buffer.put(data, currentOffset, numberOfBytesToWrite); |
|
|
|
outputIndex += numberOfBytesToWrite; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
writableBytes = bufferSize - bufferIndex; |
|
|
|
// System.out.println(path + " [" + (outputIndex + currentOffset) + "," + ((outputIndex + currentOffset) + writableBytes) + ")"); |
|
|
|
buffer.put(data, currentOffset, writableBytes); |
|
|
|
outputIndex += writableBytes; |
|
|
|
currentOffset += writableBytes; |
|
|
|
writeCurrentBufferToService(); |
|
|
|
numberOfBytesToWrite = numberOfBytesToWrite - writableBytes; |
|
|
|
writableBytes = bufferSize - buffer.position(); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -210,8 +200,9 @@ public class SeaweedOutputStream extends OutputStream implements Syncable, Strea |
|
|
|
threadExecutor.shutdown(); |
|
|
|
} finally { |
|
|
|
lastError = new IOException(FSExceptionMessages.STREAM_IS_CLOSED); |
|
|
|
ByteBufferPool.release(buffer); |
|
|
|
buffer = null; |
|
|
|
bufferIndex = 0; |
|
|
|
outputIndex = 0; |
|
|
|
closed = true; |
|
|
|
writeOperations.clear(); |
|
|
|
if (!threadExecutor.isShutdown()) { |
|
|
@ -221,35 +212,17 @@ public class SeaweedOutputStream extends OutputStream implements Syncable, Strea |
|
|
|
} |
|
|
|
|
|
|
|
private synchronized void writeCurrentBufferToService() throws IOException { |
|
|
|
if (bufferIndex == 0) { |
|
|
|
if (buffer.position() == 0) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
final byte[] bytes = buffer; |
|
|
|
final int bytesLength = bufferIndex; |
|
|
|
|
|
|
|
buffer = null; // new byte[bufferSize]; |
|
|
|
bufferIndex = 0; |
|
|
|
final long offset = position; |
|
|
|
buffer.flip(); |
|
|
|
int bytesLength = buffer.limit() - buffer.position(); |
|
|
|
SeaweedWrite.writeData(entry, replication, filerGrpcClient, position, buffer.array(), buffer.position(), buffer.limit()); |
|
|
|
// System.out.println(path + " saved [" + (position) + "," + ((position) + bytesLength) + ")"); |
|
|
|
position += bytesLength; |
|
|
|
buffer.clear(); |
|
|
|
|
|
|
|
if (threadExecutor.getQueue().size() >= maxConcurrentRequestCount * 2) { |
|
|
|
waitForTaskToComplete(); |
|
|
|
} |
|
|
|
|
|
|
|
final Future<Void> job = completionService.submit(new Callable<Void>() { |
|
|
|
@Override |
|
|
|
public Void call() throws Exception { |
|
|
|
// originally: client.append(path, offset, bytes, 0, bytesLength); |
|
|
|
SeaweedWrite.writeData(entry, replication, filerGrpcClient, offset, bytes, 0, bytesLength); |
|
|
|
return null; |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
writeOperations.add(new WriteOperation(job, offset, bytesLength)); |
|
|
|
|
|
|
|
// Try to shrink the queue |
|
|
|
shrinkWriteOperationQueue(); |
|
|
|
} |
|
|
|
|
|
|
|
private void waitForTaskToComplete() throws IOException { |
|
|
|