diff --git a/src/main/java/net/minecraft/world/chunk/storage/RegionFileCache.java b/src/main/java/net/minecraft/world/chunk/storage/RegionFileCache.java index 851d88d..902d8ad 100644 --- a/src/main/java/net/minecraft/world/chunk/storage/RegionFileCache.java +++ b/src/main/java/net/minecraft/world/chunk/storage/RegionFileCache.java @@ -8,11 +8,16 @@ import java.util.Iterator; import java.util.Map; +import com.google.common.collect.Maps; import net.minecraft.world.storage.ThreadedFileIOBase; +import org.ultramine.server.internal.LambdaHolder; +import org.ultramine.server.util.CachedEntry; +import org.ultramine.server.util.CollectionUtil; public class RegionFileCache { - private static final Map regionsByFilename = new HashMap(); + private static final Map> regionsByFilenameUM = new HashMap<>(); + private static final Map regionsByFilename = Maps.transformValues(regionsByFilenameUM, LambdaHolder.cachedEntryGetValueGuavaFunc()); private static final String __OBFID = "CL_00000383"; public static synchronized RegionFile createOrLoadRegionFile(File p_76550_0_, int p_76550_1_, int p_76550_2_) @@ -34,11 +39,21 @@ if (regionsByFilename.size() >= 256) { - clearRegionFileReferences(); + for(CachedEntry entry : CollectionUtil.retainNewestEntries(regionsByFilenameUM.values(), 128)) + { + try + { + entry.getValueAndUpdateTime().close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } } RegionFile regionfile1 = new RegionFile(file3); - regionsByFilename.put(file3, regionfile1); + regionsByFilenameUM.put(file3, CachedEntry.of(regionfile1)); return regionfile1; } } diff --git a/src/main/java/org/ultramine/server/internal/LambdaHolder.java b/src/main/java/org/ultramine/server/internal/LambdaHolder.java index d34b795..2d14247 100644 --- a/src/main/java/org/ultramine/server/internal/LambdaHolder.java +++ b/src/main/java/org/ultramine/server/internal/LambdaHolder.java @@ -4,6 +4,7 @@ import net.minecraft.tileentity.TileEntity; import net.openhft.koloboke.collect.map.ShortObjMap; import net.openhft.koloboke.collect.map.hash.HashShortObjMaps; +import org.ultramine.server.util.CachedEntry; import java.util.TreeSet; import java.util.function.Predicate; @@ -15,18 +16,19 @@ public static final Predicate ENTITY_REMOVAL_PREDICATE = o -> ((Entity)o).removeThisTick; public static final Predicate TILE_ENTITY_REMOVAL_PREDICATE = o -> ((TileEntity)o).removeThisTick; - private static final Supplier> NEW_TREE_SET = TreeSet::new; - private static final Supplier> NEW_SHORT_OBJ_MAP = HashShortObjMaps::newMutableMap; - - @SuppressWarnings("unchecked") public static Supplier> newTreeSet() { - return (Supplier>) (Object) NEW_TREE_SET; + return TreeSet::new; } - @SuppressWarnings("unchecked") public static Supplier> newShortObjMap() { - return (Supplier>) (Object) NEW_SHORT_OBJ_MAP; + return HashShortObjMaps::newMutableMap; + } + + @SuppressWarnings({"Guava"}) + public static com.google.common.base.Function, T> cachedEntryGetValueGuavaFunc() + { + return CachedEntry::getValueAndUpdateTime; } } diff --git a/src/main/java/org/ultramine/server/util/CachedEntry.java b/src/main/java/org/ultramine/server/util/CachedEntry.java new file mode 100644 index 0000000..2816ea1 --- /dev/null +++ b/src/main/java/org/ultramine/server/util/CachedEntry.java @@ -0,0 +1,65 @@ +package org.ultramine.server.util; + +public class CachedEntry implements Comparable> +{ + private final T value; + private long time; + + private CachedEntry(T value, long time) + { + this.value = value; + this.time = time; + } + + private CachedEntry(T value) + { + this(value, System.nanoTime()); + } + + public static CachedEntry of(T val) + { + return new CachedEntry<>(val); + } + + public T getValueAndUpdateTime() + { + this.time = System.nanoTime(); + return value; + } + + public long getTime() + { + return time; + } + + @Override + public int compareTo(CachedEntry o) + { + return Long.compare(time, o.time); + } + + @Override + public boolean equals(Object o) + { + if(this == o) return true; + if(o == null || getClass() != o.getClass()) return false; + + CachedEntry that = (CachedEntry) o; + + return value != null ? value.equals(that.value) : that.value == null; + } + + @Override + public int hashCode() + { + return value != null ? value.hashCode() : 0; + } + + @Override + public String toString() + { + return "CachedEntry{" + + "value=" + value + + '}'; + } +} diff --git a/src/main/java/org/ultramine/server/util/CollectionUtil.java b/src/main/java/org/ultramine/server/util/CollectionUtil.java index f907b27..c1a1d2e 100644 --- a/src/main/java/org/ultramine/server/util/CollectionUtil.java +++ b/src/main/java/org/ultramine/server/util/CollectionUtil.java @@ -1,5 +1,12 @@ package org.ultramine.server.util; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + public class CollectionUtil { private static final int INSERTIONSORT_THRESHOLD = 7; @@ -62,4 +69,34 @@ x[a] = x[b]; x[b] = t; } + + /** @return removed entries */ + public static > List removeOldestEntries(Collection collection, int entriesToRemove) + { + if(entriesToRemove <= 0) + throw new IllegalArgumentException(); + List list = new ArrayList<>(collection); + Collections.sort(list); + + if(entriesToRemove >= collection.size()) + { + collection.clear(); + return list; + } + + List listToRemove = list.subList(0, entriesToRemove); + if(collection instanceof Set) + collection.removeAll(listToRemove); + else + collection.removeAll(new HashSet<>(listToRemove)); + return listToRemove; + } + + /** @return removed entries */ + public static > List retainNewestEntries(Collection collection, int entriesToRetain) + { + if(entriesToRetain >= collection.size()) + return Collections.emptyList(); + return removeOldestEntries(collection, collection.size() - entriesToRetain); + } }