The single element `close` calls go through a very inefficient path that includes creating a one element list. `releaseOnce` is only with a single non-null input in production in two spots so no need for varargs and any complexity here. `ReleasableBytesStreamOutput` does not require any `releaseOnce` wrapping because we already have that kind of logic implemented in `org.elasticsearch.common.util.AbstractArray` (which we were wrapping here) already.
This commit is contained in:
parent
aa57bbd422
commit
43a6ff5eb1
|
@ -19,6 +19,8 @@
|
|||
|
||||
package org.elasticsearch.core.internal.io;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
@ -64,6 +66,15 @@ public final class IOUtils {
|
|||
close(null, Arrays.asList(objects));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #close(Closeable...)
|
||||
*/
|
||||
public static void close(@Nullable Closeable closeable) throws IOException {
|
||||
if (closeable != null) {
|
||||
closeable.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all given {@link Closeable}s. Some of the {@linkplain Closeable}s may be null; they are
|
||||
* ignored. After everything is closed, the method adds any exceptions as suppressed to the
|
||||
|
@ -102,9 +113,7 @@ public final class IOUtils {
|
|||
Exception firstException = ex;
|
||||
for (final Closeable object : objects) {
|
||||
try {
|
||||
if (object != null) {
|
||||
object.close();
|
||||
}
|
||||
close(object);
|
||||
} catch (final IOException | RuntimeException e) {
|
||||
if (firstException == null) {
|
||||
firstException = e;
|
||||
|
@ -142,14 +151,18 @@ public final class IOUtils {
|
|||
*/
|
||||
public static void closeWhileHandlingException(final Iterable<? extends Closeable> objects) {
|
||||
for (final Closeable object : objects) {
|
||||
// noinspection EmptyCatchBlock
|
||||
try {
|
||||
if (object != null) {
|
||||
object.close();
|
||||
}
|
||||
} catch (final IOException | RuntimeException e) {
|
||||
closeWhileHandlingException(object);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @see #closeWhileHandlingException(Closeable...)
|
||||
*/
|
||||
public static void closeWhileHandlingException(final Closeable closeable) {
|
||||
// noinspection EmptyCatchBlock
|
||||
try {
|
||||
close(closeable);
|
||||
} catch (final IOException | RuntimeException e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,7 @@ package org.elasticsearch.common.io.stream;
|
|||
|
||||
import org.elasticsearch.common.bytes.ReleasableBytesReference;
|
||||
import org.elasticsearch.common.lease.Releasable;
|
||||
import org.elasticsearch.common.lease.Releasables;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.common.util.ByteArray;
|
||||
import org.elasticsearch.common.util.PageCacheRecycler;
|
||||
|
||||
/**
|
||||
|
@ -35,10 +33,7 @@ import org.elasticsearch.common.util.PageCacheRecycler;
|
|||
* stream should only be closed after the bytes have been output or copied
|
||||
* elsewhere.
|
||||
*/
|
||||
public class ReleasableBytesStreamOutput extends BytesStreamOutput
|
||||
implements Releasable {
|
||||
|
||||
private Releasable releasable;
|
||||
public class ReleasableBytesStreamOutput extends BytesStreamOutput implements Releasable {
|
||||
|
||||
public ReleasableBytesStreamOutput(BigArrays bigarrays) {
|
||||
this(PageCacheRecycler.PAGE_SIZE_IN_BYTES, bigarrays);
|
||||
|
@ -46,31 +41,10 @@ public class ReleasableBytesStreamOutput extends BytesStreamOutput
|
|||
|
||||
public ReleasableBytesStreamOutput(int expectedSize, BigArrays bigArrays) {
|
||||
super(expectedSize, bigArrays);
|
||||
this.releasable = Releasables.releaseOnce(this.bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
Releasables.close(releasable);
|
||||
}
|
||||
|
||||
@Override
|
||||
void ensureCapacity(long offset) {
|
||||
final ByteArray prevBytes = this.bytes;
|
||||
super.ensureCapacity(offset);
|
||||
if (prevBytes != this.bytes) {
|
||||
// re-create the releasable with the new reference
|
||||
releasable = Releasables.releaseOnce(this.bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
final ByteArray prevBytes = this.bytes;
|
||||
super.reset();
|
||||
if (prevBytes != this.bytes) {
|
||||
// re-create the releasable with the new reference
|
||||
releasable = Releasables.releaseOnce(this.bytes);
|
||||
}
|
||||
bytes.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,13 +96,13 @@ public enum Releasables {
|
|||
}
|
||||
|
||||
/**
|
||||
* Equivalent to {@link #wrap(Releasable...)} but can be called multiple times without double releasing.
|
||||
* Wraps a {@link Releasable} such that its {@link Releasable#close()} method can be called multiple times without double releasing.
|
||||
*/
|
||||
public static Releasable releaseOnce(final Releasable... releasables) {
|
||||
public static Releasable releaseOnce(final Releasable releasable) {
|
||||
final AtomicBoolean released = new AtomicBoolean(false);
|
||||
return () -> {
|
||||
if (released.compareAndSet(false, true)) {
|
||||
close(releasables);
|
||||
releasable.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,11 +28,11 @@ public class ReleasablesTests extends ESTestCase {
|
|||
|
||||
public void testReleaseOnce() {
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
Releasable releasable = Releasables.releaseOnce(count::incrementAndGet, count::incrementAndGet);
|
||||
Releasable releasable = Releasables.releaseOnce(count::incrementAndGet);
|
||||
assertEquals(0, count.get());
|
||||
releasable.close();
|
||||
assertEquals(2, count.get());
|
||||
assertEquals(1, count.get());
|
||||
releasable.close();
|
||||
assertEquals(2, count.get());
|
||||
assertEquals(1, count.get());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue