From 124a8b6213a9f3fcf9099f7d12ec7e48529f5709 Mon Sep 17 00:00:00 2001 From: Techcable Date: Sat, 17 Sep 2016 16:05:49 +0000 Subject: [PATCH] Fix ArrayIndexOutOfBoundsException in LowMemorySet Fixes #86 --- .../0004-Configurable-Waterfall-Metrics.patch | 304 +++--------------- ...ead-of-lots-and-lots-of-teams-with-t.patch | 25 +- 2 files changed, 48 insertions(+), 281 deletions(-) diff --git a/BungeeCord-Patches/0004-Configurable-Waterfall-Metrics.patch b/BungeeCord-Patches/0004-Configurable-Waterfall-Metrics.patch index b1d6906..ce2c8af 100644 --- a/BungeeCord-Patches/0004-Configurable-Waterfall-Metrics.patch +++ b/BungeeCord-Patches/0004-Configurable-Waterfall-Metrics.patch @@ -1,4 +1,4 @@ -From 84c2a7140f99bb3a77027e8c845772f021f7b7b7 Mon Sep 17 00:00:00 2001 +From c8a58f65efa67b17ee0c2e8b44411395e1bbcb40 Mon Sep 17 00:00:00 2001 From: Techcable Date: Thu, 19 May 2016 10:55:20 -0700 Subject: [PATCH] Configurable Waterfall Metrics @@ -17,143 +17,46 @@ index b30541b..293ec4e 100644 + */ + boolean isMetrics(); } -diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/Metrics.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/Metrics.java -new file mode 100644 -index 0000000..ae5a2a9 ---- /dev/null +diff --git a/proxy/src/main/java/net/md_5/bungee/Metrics.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/Metrics.java +similarity index 96% +rename from proxy/src/main/java/net/md_5/bungee/Metrics.java +rename to proxy/src/main/java/io/github/waterfallmc/waterfall/Metrics.java +index 9523987..ae5a2a9 100644 +--- a/proxy/src/main/java/net/md_5/bungee/Metrics.java +++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/Metrics.java -@@ -0,0 +1,131 @@ +@@ -1,4 +1,4 @@ +-package net.md_5.bungee; +package io.github.waterfallmc.waterfall; -+ -+import java.io.BufferedReader; -+import java.io.IOException; -+import java.io.InputStreamReader; -+import java.io.OutputStreamWriter; -+import java.io.UnsupportedEncodingException; -+import java.net.URL; -+import java.net.URLConnection; -+import java.net.URLEncoder; -+import java.util.TimerTask; + + import java.io.BufferedReader; + import java.io.IOException; +@@ -9,6 +9,8 @@ import java.net.URL; + import java.net.URLConnection; + import java.net.URLEncoder; + import java.util.TimerTask; + +import net.md_5.bungee.BungeeCord; -+import net.md_5.bungee.api.ProxyServer; -+ -+public class Metrics extends TimerTask -+{ -+ -+ /** -+ * The current revision number -+ */ -+ private final static int REVISION = 5; -+ /** -+ * The base url of the metrics domain -+ */ -+ private static final String BASE_URL = "http://mcstats.org"; -+ /** -+ * The url used to report a server's status -+ */ -+ private static final String REPORT_URL = "/report/%s"; -+ /** -+ * Interval of time to ping (in minutes) -+ */ + import net.md_5.bungee.api.ProxyServer; + + public class Metrics extends TimerTask +@@ -29,7 +31,7 @@ public class Metrics extends TimerTask + /** + * Interval of time to ping (in minutes) + */ +- final static int PING_INTERVAL = 10; + public final static int PING_INTERVAL = 10; -+ boolean firstPost = true; -+ -+ @Override -+ public void run() -+ { -+ try -+ { -+ // We use the inverse of firstPost because if it is the first time we are posting, -+ // it is not a interval ping, so it evaluates to FALSE -+ // Each time thereafter it will evaluate to TRUE, i.e PING! -+ postPlugin( !firstPost ); -+ -+ // After the first post we set firstPost to false -+ // Each post thereafter will be a ping -+ firstPost = false; -+ } catch ( IOException ex ) -+ { -+ // ProxyServer.getInstance().getLogger().info( "[Metrics] " + ex.getMessage() ); -+ } -+ } -+ -+ /** -+ * Generic method that posts a plugin to the metrics website -+ */ -+ private void postPlugin(boolean isPing) throws IOException -+ { -+ // Construct the post data -+ final StringBuilder data = new StringBuilder(); -+ data.append( encode( "guid" ) ).append( '=' ).append( encode( BungeeCord.getInstance().config.getUuid() ) ); -+ encodeDataPair( data, "version", ProxyServer.getInstance().getVersion() ); -+ encodeDataPair( data, "server", "0" ); -+ encodeDataPair( data, "players", Integer.toString( ProxyServer.getInstance().getOnlineCount() ) ); -+ encodeDataPair( data, "revision", String.valueOf( REVISION ) ); -+ -+ // If we're pinging, append it -+ if ( isPing ) -+ { -+ encodeDataPair( data, "ping", "true" ); -+ } -+ -+ // Create the url + boolean firstPost = true; + + @Override +@@ -71,7 +73,7 @@ public class Metrics extends TimerTask + } + + // Create the url +- URL url = new URL( BASE_URL + String.format( REPORT_URL, encode( "BungeeCord" ) ) ); + URL url = new URL( BASE_URL + String.format( REPORT_URL, encode( "Waterfall" ) ) ); -+ -+ // Connect to the website -+ URLConnection connection; -+ -+ connection = url.openConnection(); -+ -+ connection.setDoOutput( true ); -+ final BufferedReader reader; -+ final String response; -+ try ( OutputStreamWriter writer = new OutputStreamWriter( connection.getOutputStream() ) ) -+ { -+ writer.write( data.toString() ); -+ writer.flush(); -+ reader = new BufferedReader( new InputStreamReader( connection.getInputStream() ) ); -+ response = reader.readLine(); -+ } -+ reader.close(); -+ -+ if ( response == null || response.startsWith( "ERR" ) ) -+ { -+ throw new IOException( response ); //Throw the exception -+ } -+ } -+ -+ /** -+ *

-+ * Encode a key/value data pair to be used in a HTTP post request. This -+ * INCLUDES a & so the first key/value pair MUST be included manually, -+ * e.g:

-+ * -+ * StringBuffer data = new StringBuffer(); -+ * data.append(encode("guid")).append('=').append(encode(guid)); -+ * encodeDataPair(data, "version", description.getVersion()); -+ * -+ * -+ * @param buffer the StringBuilder to append the data pair onto -+ * @param key the key value -+ * @param value the value -+ */ -+ private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException -+ { -+ buffer.append( '&' ).append( encode( key ) ).append( '=' ).append( encode( value ) ); -+ } -+ -+ /** -+ * Encode text as UTF-8 -+ * -+ * @param text the text to encode -+ * @return the encoded text, as UTF-8 -+ */ -+ private static String encode(final String text) throws UnsupportedEncodingException -+ { -+ return URLEncoder.encode( text, "UTF-8" ); -+ } -+} + + // Connect to the website + URLConnection connection; diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java index 12c5859..692b83e 100644 --- a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java @@ -206,141 +109,6 @@ index 7bb0862..304a794 100644 } public void startListeners() -diff --git a/proxy/src/main/java/net/md_5/bungee/Metrics.java b/proxy/src/main/java/net/md_5/bungee/Metrics.java -deleted file mode 100644 -index 9523987..0000000 ---- a/proxy/src/main/java/net/md_5/bungee/Metrics.java -+++ /dev/null -@@ -1,129 +0,0 @@ --package net.md_5.bungee; -- --import java.io.BufferedReader; --import java.io.IOException; --import java.io.InputStreamReader; --import java.io.OutputStreamWriter; --import java.io.UnsupportedEncodingException; --import java.net.URL; --import java.net.URLConnection; --import java.net.URLEncoder; --import java.util.TimerTask; --import net.md_5.bungee.api.ProxyServer; -- --public class Metrics extends TimerTask --{ -- -- /** -- * The current revision number -- */ -- private final static int REVISION = 5; -- /** -- * The base url of the metrics domain -- */ -- private static final String BASE_URL = "http://mcstats.org"; -- /** -- * The url used to report a server's status -- */ -- private static final String REPORT_URL = "/report/%s"; -- /** -- * Interval of time to ping (in minutes) -- */ -- final static int PING_INTERVAL = 10; -- boolean firstPost = true; -- -- @Override -- public void run() -- { -- try -- { -- // We use the inverse of firstPost because if it is the first time we are posting, -- // it is not a interval ping, so it evaluates to FALSE -- // Each time thereafter it will evaluate to TRUE, i.e PING! -- postPlugin( !firstPost ); -- -- // After the first post we set firstPost to false -- // Each post thereafter will be a ping -- firstPost = false; -- } catch ( IOException ex ) -- { -- // ProxyServer.getInstance().getLogger().info( "[Metrics] " + ex.getMessage() ); -- } -- } -- -- /** -- * Generic method that posts a plugin to the metrics website -- */ -- private void postPlugin(boolean isPing) throws IOException -- { -- // Construct the post data -- final StringBuilder data = new StringBuilder(); -- data.append( encode( "guid" ) ).append( '=' ).append( encode( BungeeCord.getInstance().config.getUuid() ) ); -- encodeDataPair( data, "version", ProxyServer.getInstance().getVersion() ); -- encodeDataPair( data, "server", "0" ); -- encodeDataPair( data, "players", Integer.toString( ProxyServer.getInstance().getOnlineCount() ) ); -- encodeDataPair( data, "revision", String.valueOf( REVISION ) ); -- -- // If we're pinging, append it -- if ( isPing ) -- { -- encodeDataPair( data, "ping", "true" ); -- } -- -- // Create the url -- URL url = new URL( BASE_URL + String.format( REPORT_URL, encode( "BungeeCord" ) ) ); -- -- // Connect to the website -- URLConnection connection; -- -- connection = url.openConnection(); -- -- connection.setDoOutput( true ); -- final BufferedReader reader; -- final String response; -- try ( OutputStreamWriter writer = new OutputStreamWriter( connection.getOutputStream() ) ) -- { -- writer.write( data.toString() ); -- writer.flush(); -- reader = new BufferedReader( new InputStreamReader( connection.getInputStream() ) ); -- response = reader.readLine(); -- } -- reader.close(); -- -- if ( response == null || response.startsWith( "ERR" ) ) -- { -- throw new IOException( response ); //Throw the exception -- } -- } -- -- /** -- *

-- * Encode a key/value data pair to be used in a HTTP post request. This -- * INCLUDES a & so the first key/value pair MUST be included manually, -- * e.g:

-- * -- * StringBuffer data = new StringBuffer(); -- * data.append(encode("guid")).append('=').append(encode(guid)); -- * encodeDataPair(data, "version", description.getVersion()); -- * -- * -- * @param buffer the StringBuilder to append the data pair onto -- * @param key the key value -- * @param value the value -- */ -- private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException -- { -- buffer.append( '&' ).append( encode( key ) ).append( '=' ).append( encode( value ) ); -- } -- -- /** -- * Encode text as UTF-8 -- * -- * @param text the text to encode -- * @return the encoded text, as UTF-8 -- */ -- private static String encode(final String text) throws UnsupportedEncodingException -- { -- return URLEncoder.encode( text, "UTF-8" ); -- } --} -- -2.7.4 (Apple Git-66) +2.9.2 diff --git a/BungeeCord-Patches/0030-Reduce-the-overhead-of-lots-and-lots-of-teams-with-t.patch b/BungeeCord-Patches/0030-Reduce-the-overhead-of-lots-and-lots-of-teams-with-t.patch index 4976cb8..58448de 100644 --- a/BungeeCord-Patches/0030-Reduce-the-overhead-of-lots-and-lots-of-teams-with-t.patch +++ b/BungeeCord-Patches/0030-Reduce-the-overhead-of-lots-and-lots-of-teams-with-t.patch @@ -1,4 +1,4 @@ -From 775f2851f8552cf918192df5ec3516083d3cc4e3 Mon Sep 17 00:00:00 2001 +From 6228b5e5fbfe99d6c929f063c851ec948e543355 Mon Sep 17 00:00:00 2001 From: Techcable Date: Mon, 25 Apr 2016 23:46:00 -0700 Subject: [PATCH] Reduce the overhead of lots and lots of teams with the same @@ -11,10 +11,10 @@ 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 0000000..3a062b6 +index 0000000..c62e3d4 --- /dev/null +++ b/api/src/main/java/io/github/waterfallmc/waterfall/utils/LowMemorySet.java -@@ -0,0 +1,177 @@ +@@ -0,0 +1,176 @@ +package io.github.waterfallmc.waterfall.utils; + +import lombok.*; @@ -35,7 +35,7 @@ index 0000000..3a062b6 +/** + * A set that uses a binary search to find objects in a sorted array. + * Avoids the memory cost of {@link java.util.HashSet}, while maintaining reasonable {@link Set#contains} -+ * Insertions ma O(N)! ++ * Insertions are O(N)! + */ +public class LowMemorySet> extends AbstractSet implements Set { + private final List backing; @@ -56,7 +56,7 @@ index 0000000..3a062b6 + return new LowMemorySet<>(new ArrayList<>(c)); + } + -+ @SuppressWarnings("unchecked") // nope ++ @SuppressWarnings({"unchecked", "rawtypes"}) + private int indexOf(Object o) { + return Collections.binarySearch((List) backing, o); + } @@ -71,7 +71,7 @@ index 0000000..3a062b6 + } + + private void trim(boolean force) { -+ if (backing instanceof ArrayList && force || trimAggressively) ((ArrayList) backing).trimToSize(); ++ if (backing instanceof ArrayList && force || trimAggressively) ((ArrayList) backing).trimToSize(); + } + + @Override @@ -88,8 +88,6 @@ index 0000000..3a062b6 + public Iterator iterator() { + Iterator backing = this.backing.iterator(); + return new Iterator() { -+ private T last; -+ + @Override + public boolean hasNext() { + return backing.hasNext(); @@ -97,12 +95,12 @@ index 0000000..3a062b6 + + @Override + public T next() { -+ return (last = backing.next()); ++ return backing.next(); + } + + @Override + public void remove() { -+ LowMemorySet.this.remove(last); ++ backing.remove(); + } + + @Override @@ -132,7 +130,9 @@ index 0000000..3a062b6 + + @Override + public boolean remove(Object o) { -+ T old = backing.remove(indexOf(o)); ++ int index = indexOf(o); ++ if (index < 0) return false; ++ T old = backing.remove(index); + this.trim(); + assert old == o; + return old != null; @@ -155,7 +155,6 @@ index 0000000..3a062b6 + } + + @Override -+ @SuppressWarnings("unchecked") + public boolean addAll(Collection c) { + if (containsAll(c)) return false; + backing.addAll(c); @@ -293,5 +292,5 @@ index 0000000..5aa306a + +} -- -2.7.4 (Apple Git-66) +2.9.2