mirror of
https://github.com/PaperMC/Waterfall.git
synced 2025-01-14 19:51:36 +01:00
Remove LowMemorySet (Fixes #394)
This set, while aiming to save memory, has heavy implications on performance with larger sets This set
This commit is contained in:
parent
0766f50f5b
commit
9cdf9ddbfd
@ -1,4 +1,4 @@
|
||||
From eeaf6ec7c4ce8b15447399baffe5b63675ea7358 Mon Sep 17 00:00:00 2001
|
||||
From a584905bd02b9c01d14a04a69666bb41a80ae1ba Mon Sep 17 00:00:00 2001
|
||||
From: Techcable <Techcable@techcable.net>
|
||||
Date: Mon, 25 Apr 2016 23:46:00 -0700
|
||||
Subject: [PATCH] Reduce the overhead of lots and lots of teams with the same
|
||||
@ -7,195 +7,12 @@ Subject: [PATCH] Reduce the overhead of lots and lots of teams with the same
|
||||
Featherboard (and other bad plugins) use persistent scoreboards (scoreboard.dat), causing every team ever to be sent to waterfall. This is bad, and takes tons of memory.
|
||||
|
||||
Uses String.intern() to avoid duplicating strings
|
||||
Uses a sorted array to avoid the overhead of the hashset in a team.
|
||||
|
||||
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/utils/LowMemorySet.java b/api/src/main/java/io/github/waterfallmc/waterfall/utils/LowMemorySet.java
|
||||
new file mode 100644
|
||||
index 00000000..6c006923
|
||||
--- /dev/null
|
||||
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/utils/LowMemorySet.java
|
||||
@@ -0,0 +1,151 @@
|
||||
+package io.github.waterfallmc.waterfall.utils;
|
||||
+
|
||||
+import java.util.AbstractSet;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Collection;
|
||||
+import java.util.Collections;
|
||||
+import java.util.Iterator;
|
||||
+import java.util.List;
|
||||
+import java.util.Set;
|
||||
+import java.util.function.Consumer;
|
||||
+import java.util.function.Predicate;
|
||||
+import java.util.stream.Stream;
|
||||
+
|
||||
+import static com.google.common.base.Preconditions.checkNotNull;
|
||||
+
|
||||
+/**
|
||||
+ * A set that uses a <a href=https://en.wikipedia.org/wiki/Binary_search_algorithm>binary search</a> to find objects in a <a href=https://en.wikipedia.org/wiki/Sorted_array>sorted array</a>.
|
||||
+ * Avoids the memory cost of {@link java.util.HashSet}, while maintaining reasonable {@link Set#contains}
|
||||
+ * <b>Insertions are O(N)!</b>
|
||||
+ */
|
||||
+public class LowMemorySet<T extends Comparable<T>> extends AbstractSet<T> implements Set<T> {
|
||||
+ private final List<T> backing;
|
||||
+
|
||||
+ private LowMemorySet(List<T> list) {
|
||||
+ this.backing = checkNotNull(list, "Null list");
|
||||
+ this.sort(); // We have to sort any initial elements
|
||||
+ }
|
||||
+
|
||||
+ public static <T extends Comparable<T>> LowMemorySet<T> create() {
|
||||
+ return new LowMemorySet<>(new ArrayList<T>());
|
||||
+ }
|
||||
+
|
||||
+ public static <T extends Comparable<T>> LowMemorySet<T> copyOf(Collection<T> c) {
|
||||
+ return new LowMemorySet<>(new ArrayList<>(c));
|
||||
+ }
|
||||
+
|
||||
+ @SuppressWarnings({"unchecked", "rawtypes"})
|
||||
+ private int indexOf(Object o) {
|
||||
+ return Collections.binarySearch((List) backing, o);
|
||||
+ }
|
||||
+
|
||||
+ private void sort() {
|
||||
+ backing.sort(null);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int size() {
|
||||
+ return backing.size();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean contains(Object o) {
|
||||
+ return indexOf(o) >= 0;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Iterator<T> iterator() {
|
||||
+ Iterator<T> backing = this.backing.iterator();
|
||||
+ return new Iterator<T>() {
|
||||
+ @Override
|
||||
+ public boolean hasNext() {
|
||||
+ return backing.hasNext();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public T next() {
|
||||
+ return backing.next();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void remove() {
|
||||
+ backing.remove();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void forEachRemaining(Consumer<? super T> action) {
|
||||
+ backing.forEachRemaining(action);
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Object[] toArray() {
|
||||
+ return backing.toArray();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T1> T1[] toArray(T1[] a) {
|
||||
+ return backing.toArray(a);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean add(T t) {
|
||||
+ if (contains(t)) return false;
|
||||
+ backing.add(t);
|
||||
+ this.sort();
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean remove(Object o) {
|
||||
+ int index = indexOf(o);
|
||||
+ if (index < 0) return false;
|
||||
+ T old = backing.remove(index);
|
||||
+ assert old == o;
|
||||
+ return old != null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean removeAll(Collection<?> c) {
|
||||
+ return backing.removeIf(c::contains);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean retainAll(Collection<?> c) {
|
||||
+ return backing.removeIf((o) -> !c.contains(o));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean addAll(Collection<? extends T> c) {
|
||||
+ if (containsAll(c)) return false;
|
||||
+ backing.addAll(c);
|
||||
+ this.sort();
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void clear() {
|
||||
+ backing.clear();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void forEach(Consumer<? super T> action) {
|
||||
+ backing.forEach(action);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Stream<T> stream() {
|
||||
+ return backing.stream();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Stream<T> parallelStream() {
|
||||
+ return backing.parallelStream();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean removeIf(Predicate<? super T> filter) {
|
||||
+ return backing.removeIf(filter);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/api/src/main/java/net/md_5/bungee/api/score/Team.java b/api/src/main/java/net/md_5/bungee/api/score/Team.java
|
||||
index 849ba1cf..25526320 100644
|
||||
index 849ba1cf..39f81fd1 100644
|
||||
--- a/api/src/main/java/net/md_5/bungee/api/score/Team.java
|
||||
+++ b/api/src/main/java/net/md_5/bungee/api/score/Team.java
|
||||
@@ -1,11 +1,12 @@
|
||||
package net.md_5.bungee.api.score;
|
||||
|
||||
+import lombok.*;
|
||||
+
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
-import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
-import lombok.Data;
|
||||
-import lombok.NonNull;
|
||||
+
|
||||
+import io.github.waterfallmc.waterfall.utils.LowMemorySet;
|
||||
|
||||
@Data
|
||||
public class Team
|
||||
@@ -20,7 +21,7 @@ public class Team
|
||||
private String nameTagVisibility;
|
||||
private String collisionRule;
|
||||
private int color;
|
||||
- private Set<String> players = new HashSet<>();
|
||||
+ private Set<String> players = LowMemorySet.create();
|
||||
|
||||
public Collection<String> getPlayers()
|
||||
{
|
||||
@@ -29,7 +30,7 @@ public class Team
|
||||
@@ -29,7 +29,7 @@ public class Team
|
||||
|
||||
public void addPlayer(String name)
|
||||
{
|
||||
@ -204,68 +21,6 @@ index 849ba1cf..25526320 100644
|
||||
}
|
||||
|
||||
public void removePlayer(String name)
|
||||
diff --git a/api/src/test/java/io/github/waterfallmc/waterfall/utils/LowMemorySetTest.java b/api/src/test/java/io/github/waterfallmc/waterfall/utils/LowMemorySetTest.java
|
||||
new file mode 100644
|
||||
index 00000000..5aa306a1
|
||||
--- /dev/null
|
||||
+++ b/api/src/test/java/io/github/waterfallmc/waterfall/utils/LowMemorySetTest.java
|
||||
@@ -0,0 +1,56 @@
|
||||
+package io.github.waterfallmc.waterfall.utils;
|
||||
+
|
||||
+import com.google.common.collect.ImmutableList;
|
||||
+import com.google.common.collect.ImmutableMap;
|
||||
+
|
||||
+import org.junit.Test;
|
||||
+
|
||||
+import static org.junit.Assert.*;
|
||||
+
|
||||
+public class LowMemorySetTest {
|
||||
+
|
||||
+ private static final ImmutableList<String> ELEMENTS = ImmutableList.of("test", "bob", "road", "food", "sleep", "sore-thought", "pain");
|
||||
+
|
||||
+ @Test
|
||||
+ public void testContains() {
|
||||
+ LowMemorySet<String> set = LowMemorySet.copyOf(ELEMENTS);
|
||||
+ assertTrue(set.contains("test"));
|
||||
+ assertTrue(set.contains("bob"));
|
||||
+ assertFalse(set.contains("stupid"));
|
||||
+ assertFalse(set.contains("head"));
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testRemove() {
|
||||
+ LowMemorySet<String> set = LowMemorySet.copyOf(ELEMENTS);
|
||||
+ assertTrue(set.contains("test"));
|
||||
+ set.remove("test");
|
||||
+ assertFalse(set.contains("test"));
|
||||
+ assertTrue(set.contains("bob"));
|
||||
+ set.remove("bob");
|
||||
+ assertFalse(set.contains("bob"));
|
||||
+ assertTrue(ELEMENTS.size() - set.size() == 2);
|
||||
+ assertTrue(set.contains("road"));
|
||||
+ assertTrue(set.contains("food"));
|
||||
+ assertTrue(set.contains("pain"));
|
||||
+ set.removeAll(ImmutableList.of("road", "food", "pain"));
|
||||
+ assertFalse(set.contains("road"));
|
||||
+ assertFalse(set.contains("food"));
|
||||
+ assertFalse(set.contains("pain"));
|
||||
+ assertTrue(ELEMENTS.size() - set.size() == 5);
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testAdd() {
|
||||
+ LowMemorySet<String> set = LowMemorySet.copyOf(ELEMENTS);
|
||||
+ assertFalse(set.contains("Techcable"));
|
||||
+ set.add("Techcable");
|
||||
+ assertTrue(set.contains("Techcable"));
|
||||
+ set.addAll(ImmutableList.of("Techcable", "PhanaticD", "Dragonslayer293", "Aikar"));
|
||||
+ assertTrue(set.contains("Techcable"));
|
||||
+ assertTrue(set.contains("PhanaticD"));
|
||||
+ assertTrue(set.contains("Aikar"));
|
||||
+ assertFalse(set.contains("md_5"));
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
--
|
||||
2.21.0
|
||||
2.22.0
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user