Added CachedObject to access a single-object cache

This commit is contained in:
TheMode 2021-05-13 08:06:42 +02:00
parent 14b59d6a04
commit 1c39e06d55
3 changed files with 91 additions and 30 deletions

View File

@ -16,6 +16,7 @@ import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.block.CustomBlockUtils;
import net.minestom.server.utils.cache.CachedObject;
import net.minestom.server.utils.callback.OptionalCallback;
import net.minestom.server.utils.chunk.ChunkCallback;
import net.minestom.server.utils.chunk.ChunkUtils;
@ -26,7 +27,6 @@ import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.ref.SoftReference;
import java.util.Set;
/**
@ -60,8 +60,7 @@ public class DynamicChunk extends Chunk {
private long lastChangeTime;
private SoftReference<ChunkDataPacket> cachedPacket = new SoftReference<>(null);
private long cachedPacketTime;
private CachedObject<ChunkDataPacket> cachedPacket = new CachedObject<>();
public DynamicChunk(@NotNull Instance instance, @Nullable Biome[] biomes, int chunkX, int chunkZ,
@NotNull PaletteStorage blockPalette, @NotNull PaletteStorage customBlockPalette) {
@ -387,22 +386,17 @@ public class DynamicChunk extends Chunk {
@NotNull
@Override
protected ChunkDataPacket createFreshPacket() {
ChunkDataPacket packet = cachedPacket.get();
if (packet != null && cachedPacketTime == getLastChangeTime()) {
return packet;
}
packet = new ChunkDataPacket(getIdentifier(), getLastChangeTime());
packet.biomes = biomes;
packet.chunkX = chunkX;
packet.chunkZ = chunkZ;
packet.paletteStorage = blockPalette.clone();
packet.customBlockPaletteStorage = customBlockPalette.clone();
packet.blockEntities = blockEntities.clone();
packet.blocksData = blocksData.clone();
this.cachedPacketTime = getLastChangeTime();
this.cachedPacket = new SoftReference<>(packet);
return packet;
return cachedPacket.getUpdatedCache(() -> {
ChunkDataPacket chunkDataPacket = new ChunkDataPacket(getIdentifier(), getLastChangeTime());
chunkDataPacket.biomes = biomes;
chunkDataPacket.chunkX = chunkX;
chunkDataPacket.chunkZ = chunkZ;
chunkDataPacket.paletteStorage = blockPalette.clone();
chunkDataPacket.customBlockPaletteStorage = customBlockPalette.clone();
chunkDataPacket.blockEntities = blockEntities.clone();
chunkDataPacket.blocksData = blocksData.clone();
return chunkDataPacket;
}, getLastChangeTime());
}
@NotNull

View File

@ -6,6 +6,7 @@ import net.minestom.server.instance.block.Block;
import net.minestom.server.item.attribute.ItemAttribute;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.Writeable;
import net.minestom.server.utils.cache.CachedObject;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -33,8 +34,8 @@ public class ItemMeta implements Writeable {
private final NBTCompound nbt;
private final ItemMetaBuilder emptyBuilder;
private String cachedSNBT;
private ByteBuf cachedBuffer;
private CachedObject<String> cachedSNBT = new CachedObject<>();
private CachedObject<ByteBuf> cachedBuffer = new CachedObject<>();
protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) {
this.damage = metaBuilder.damage;
@ -128,10 +129,7 @@ public class ItemMeta implements Writeable {
}
public @NotNull String toSNBT() {
if (cachedSNBT == null) {
this.cachedSNBT = nbt.toSNBT();
}
return cachedSNBT;
return cachedSNBT.getCache(nbt::toSNBT);
}
@Override
@ -155,12 +153,12 @@ public class ItemMeta implements Writeable {
@Override
public synchronized void write(@NotNull BinaryWriter writer) {
if (cachedBuffer == null) {
final var buffer = cachedBuffer.getCache(() -> {
BinaryWriter w = new BinaryWriter();
w.writeNBT("", nbt);
this.cachedBuffer = w.getBuffer();
}
writer.write(cachedBuffer);
this.cachedBuffer.resetReaderIndex();
return w.getBuffer();
});
writer.write(buffer);
buffer.resetReaderIndex();
}
}

View File

@ -0,0 +1,69 @@
package net.minestom.server.utils.cache;
import com.google.common.annotations.Beta;
import org.jetbrains.annotations.NotNull;
import java.lang.ref.SoftReference;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
/**
* Represents a single that can be collected by the garbage collector
* depending on memory demand.
*
* @param <T> the object to cache
*/
@Beta
public class CachedObject<T> extends SoftReference<AtomicReference<T>> {
private long cacheTime;
public CachedObject() {
super(new AtomicReference<>());
}
/**
* Retrieves the cache.
*
* @param supplier supplier for the value if absent
* @return the cache
*/
public @NotNull T getCache(@NotNull Supplier<@NotNull T> supplier) {
var referent = get();
assert referent != null;
var value = referent.get();
if (value == null) {
value = supplier.get();
referent.set(value);
}
return value;
}
/**
* Retrieves the cache, and ensure that the value is up-to-date.
*
* @param supplier supplier for the value if absent or outdated
* @param lastUpdate the required internal timestamp, supplier will be called otherwise
* @return the cache
*/
public @NotNull T getUpdatedCache(@NotNull Supplier<@NotNull T> supplier, long lastUpdate) {
var referent = get();
assert referent != null;
var value = referent.get();
if (value == null || cacheTime != lastUpdate) {
value = supplier.get();
this.cacheTime = lastUpdate;
referent.set(value);
}
return value;
}
/**
* @deprecated use {@link #getCache(Supplier)}
*/
@Override
@Deprecated
public AtomicReference<T> get() {
return super.get();
}
}