Merge "Cache least recently used output buffer."

This commit is contained in:
TreeHugger Robot
2021-09-16 21:02:58 +00:00
committed by Android (Google) Code Review
3 changed files with 64 additions and 8 deletions

View File

@@ -64,9 +64,13 @@ public class FastDataPerfTest {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
os.reset();
final FastDataOutput out = new FastDataOutput(os, BUFFER_SIZE);
doWrite(out);
out.flush();
final FastDataOutput out = FastDataOutput.obtain(os);
try {
doWrite(out);
out.flush();
} finally {
out.release();
}
}
}

View File

@@ -124,7 +124,7 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer {
throw new UnsupportedOperationException();
}
mOut = new FastDataOutput(os, BUFFER_SIZE);
mOut = FastDataOutput.obtain(os);
mOut.write(PROTOCOL_MAGIC_VERSION_0);
mTagCount = 0;
@@ -138,7 +138,9 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer {
@Override
public void flush() throws IOException {
mOut.flush();
if (mOut != null) {
mOut.flush();
}
}
@Override
@@ -157,6 +159,9 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer {
public void endDocument() throws IOException {
mOut.writeByte(END_DOCUMENT | TYPE_NULL);
flush();
mOut.release();
mOut = null;
}
@Override

View File

@@ -30,6 +30,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
* Optimized implementation of {@link DataOutput} which buffers data in memory
@@ -41,23 +42,26 @@ import java.util.Objects;
public class FastDataOutput implements DataOutput, Flushable, Closeable {
private static final int MAX_UNSIGNED_SHORT = 65_535;
private static final int BUFFER_SIZE = 32_768;
private static AtomicReference<FastDataOutput> sOutCache = new AtomicReference<>();
private final VMRuntime mRuntime;
private final OutputStream mOut;
private final byte[] mBuffer;
private final long mBufferPtr;
private final int mBufferCap;
private OutputStream mOut;
private int mBufferPos;
/**
* Values that have been "interned" by {@link #writeInternedUTF(String)}.
*/
private HashMap<String, Short> mStringRefs = new HashMap<>();
private final HashMap<String, Short> mStringRefs = new HashMap<>();
public FastDataOutput(@NonNull OutputStream out, int bufferSize) {
mRuntime = VMRuntime.getRuntime();
mOut = Objects.requireNonNull(out);
if (bufferSize < 8) {
throw new IllegalArgumentException();
}
@@ -65,6 +69,48 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable {
mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize);
mBufferPtr = mRuntime.addressOf(mBuffer);
mBufferCap = mBuffer.length;
setOutput(out);
}
/**
* Create a new FastDataOutput object or retrieve one from cache.
*/
public static FastDataOutput obtain(@NonNull OutputStream out) {
FastDataOutput instance = sOutCache.getAndSet(null);
if (instance != null) {
instance.setOutput(out);
return instance;
}
return new FastDataOutput(out, BUFFER_SIZE);
}
/**
* Put a FastDataOutput object back into the cache.
* You must not touch the object after this call.
*/
public void release() {
if (mBufferPos > 0) {
throw new IllegalStateException("Lingering data, call flush() before releasing.");
}
mOut = null;
mBufferPos = 0;
mStringRefs.clear();
if (mBufferCap == BUFFER_SIZE) {
// Try to return to the cache.
sOutCache.compareAndSet(null, this);
}
}
/**
* Re-initializes the object for the new output.
*/
private void setOutput(@NonNull OutputStream out) {
mOut = Objects.requireNonNull(out);
mBufferPos = 0;
mStringRefs.clear();
}
private void drain() throws IOException {
@@ -83,6 +129,7 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable {
@Override
public void close() throws IOException {
mOut.close();
release();
}
@Override