Use opaque memory ordering for cached packets

This commit is contained in:
themode 2022-01-01 03:40:42 +01:00 committed by TheMode
parent 4b89ce33ee
commit 10d40dd19d

View File

@ -5,9 +5,10 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
@ -19,12 +20,17 @@ import java.util.function.Supplier;
*/ */
@ApiStatus.Internal @ApiStatus.Internal
public final class CachedPacket implements SendablePacket { public final class CachedPacket implements SendablePacket {
private static final AtomicIntegerFieldUpdater<CachedPacket> UPDATER = private static final VarHandle PACKET;
AtomicIntegerFieldUpdater.newUpdater(CachedPacket.class, "updated");
static {
try {
PACKET = MethodHandles.lookup().findVarHandle(CachedPacket.class, "packet", SoftReference.class);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
private final Supplier<ServerPacket> packetSupplier; private final Supplier<ServerPacket> packetSupplier;
// 0 means that the reference needs to be updated
// Anything else (currently 1) means that the packet is up-to-date
private volatile int updated = 0;
private SoftReference<FramedPacket> packet; private SoftReference<FramedPacket> packet;
public CachedPacket(@NotNull Supplier<@NotNull ServerPacket> packetSupplier) { public CachedPacket(@NotNull Supplier<@NotNull ServerPacket> packetSupplier) {
@ -36,12 +42,14 @@ public final class CachedPacket implements SendablePacket {
} }
public void invalidate() { public void invalidate() {
this.updated = 0; PACKET.setOpaque(this, null);
} }
public @NotNull ServerPacket packet() { public @NotNull ServerPacket packet() {
@SuppressWarnings("unchecked")
SoftReference<FramedPacket> ref = (SoftReference<FramedPacket>) PACKET.getOpaque(this);
FramedPacket cache; FramedPacket cache;
if (updated == 1 && (cache = packet.get()) != null) if (ref != null && (cache = ref.get()) != null)
return cache.packet(); // Avoid potential packet allocation return cache.packet(); // Avoid potential packet allocation
return packetSupplier.get(); return packetSupplier.get();
} }
@ -54,12 +62,12 @@ public final class CachedPacket implements SendablePacket {
private @Nullable FramedPacket updatedCache() { private @Nullable FramedPacket updatedCache() {
if (!PacketUtils.CACHED_PACKET) if (!PacketUtils.CACHED_PACKET)
return null; return null;
SoftReference<FramedPacket> ref; @SuppressWarnings("unchecked")
SoftReference<FramedPacket> ref = (SoftReference<FramedPacket>) PACKET.getOpaque(this);
FramedPacket cache; FramedPacket cache;
if (updated == 0 || ((ref = packet) == null || (cache = ref.get()) == null)) { if (ref == null || (cache = ref.get()) == null) {
cache = PacketUtils.allocateTrimmedPacket(packetSupplier.get()); cache = PacketUtils.allocateTrimmedPacket(packetSupplier.get());
this.packet = new SoftReference<>(cache); PACKET.setOpaque(this, new SoftReference<>(cache));
UPDATER.compareAndSet(this, 0, 1);
} }
return cache; return cache;
} }