Archiviert
13
0

Properly clean up after async listeners.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-09-29 23:21:09 +02:00
Ursprung 15b33925c0
Commit d58ff1c4c1
6 geänderte Dateien mit 96 neuen und 21 gelöschten Zeilen

Datei anzeigen

@ -24,7 +24,7 @@ public interface AsynchronousManager {
* @param listener - the packet listener that will recieve these asynchronous events. * @param listener - the packet listener that will recieve these asynchronous events.
* @return An asynchrouns handler. * @return An asynchrouns handler.
*/ */
public abstract AsyncListenerHandler registerAsyncHandler(Plugin plugin, PacketListener listener); public abstract AsyncListenerHandler registerAsyncHandler(PacketListener listener);
/** /**
* Unregisters and closes the given asynchronous handler. * Unregisters and closes the given asynchronous handler.
@ -32,6 +32,12 @@ public interface AsynchronousManager {
*/ */
public abstract void unregisterAsyncHandler(AsyncListenerHandler handler); public abstract void unregisterAsyncHandler(AsyncListenerHandler handler);
/**
* Unregisters every asynchronous handler associated with this plugin.
* @param plugin - the original plugin.
*/
public void unregisterAsyncHandlers(Plugin plugin);
/** /**
* Retrieves a immutable set containing the ID of the sent server packets that will be * Retrieves a immutable set containing the ID of the sent server packets that will be
* observed by the asynchronous listeners. * observed by the asynchronous listeners.

Datei anzeigen

@ -1,5 +1,6 @@
package com.comphenix.protocol.async; package com.comphenix.protocol.async;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -11,6 +12,9 @@ import com.comphenix.protocol.PacketStream;
import com.comphenix.protocol.events.ListeningWhitelist; import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.injector.PrioritizedListener;
import com.google.common.base.Objects;
/** /**
* Represents a filter manager for asynchronous packets. * Represents a filter manager for asynchronous packets.
@ -34,6 +38,9 @@ public class AsyncFilterManager implements AsynchronousManager {
// Current packet index // Current packet index
private AtomicInteger currentSendingIndex = new AtomicInteger(); private AtomicInteger currentSendingIndex = new AtomicInteger();
// Whether or not we're currently cleaning up
private volatile boolean cleaningUp;
public AsyncFilterManager(Logger logger, PacketStream packetStream) { public AsyncFilterManager(Logger logger, PacketStream packetStream) {
this.serverQueue = new PacketSendingQueue(); this.serverQueue = new PacketSendingQueue();
this.clientQueue = new PacketSendingQueue(); this.clientQueue = new PacketSendingQueue();
@ -46,14 +53,21 @@ public class AsyncFilterManager implements AsynchronousManager {
} }
@Override @Override
public AsyncListenerHandler registerAsyncHandler(Plugin plugin, PacketListener listener) { public AsyncListenerHandler registerAsyncHandler(PacketListener listener) {
AsyncListenerHandler handler = new AsyncListenerHandler(plugin, mainThread, this, listener); AsyncListenerHandler handler = new AsyncListenerHandler(mainThread, this, listener);
ListeningWhitelist sendingWhitelist = listener.getSendingWhitelist();
ListeningWhitelist receivingWhitelist = listener.getReceivingWhitelist();
// Add listener to either or both processing queue // Add listener to either or both processing queue
if (hasValidWhitelist(listener.getSendingWhitelist())) if (hasValidWhitelist(sendingWhitelist)) {
serverProcessingQueue.addListener(handler, listener.getSendingWhitelist()); PacketFilterManager.verifyWhitelist(listener, sendingWhitelist);
if (hasValidWhitelist(listener.getReceivingWhitelist())) serverProcessingQueue.addListener(handler, sendingWhitelist);
clientProcessingQueue.addListener(handler, listener.getReceivingWhitelist()); }
if (hasValidWhitelist(receivingWhitelist)) {
PacketFilterManager.verifyWhitelist(listener, receivingWhitelist);
clientProcessingQueue.addListener(handler, receivingWhitelist);
}
return handler; return handler;
} }
@ -76,10 +90,36 @@ public class AsyncFilterManager implements AsynchronousManager {
PacketListener listener = handler.getAsyncListener(); PacketListener listener = handler.getAsyncListener();
// Just remove it from the queue(s) // Just remove it from the queue(s)
if (hasValidWhitelist(listener.getSendingWhitelist())) if (hasValidWhitelist(listener.getSendingWhitelist())) {
serverProcessingQueue.removeListener(handler, listener.getSendingWhitelist()); List<Integer> removed = serverProcessingQueue.removeListener(handler, listener.getSendingWhitelist());
if (hasValidWhitelist(listener.getReceivingWhitelist()))
clientProcessingQueue.removeListener(handler, listener.getReceivingWhitelist()); // We're already taking care of this, so don't do anything
if (!cleaningUp)
serverQueue.signalPacketUpdate(removed);
}
if (hasValidWhitelist(listener.getReceivingWhitelist())) {
List<Integer> removed = clientProcessingQueue.removeListener(handler, listener.getReceivingWhitelist());
if (!cleaningUp)
clientQueue.signalPacketUpdate(removed);
}
}
@Override
public void unregisterAsyncHandlers(Plugin plugin) {
unregisterAsyncHandlers(serverProcessingQueue, plugin);
unregisterAsyncHandlers(clientProcessingQueue, plugin);
}
private void unregisterAsyncHandlers(PacketProcessingQueue processingQueue, Plugin plugin) {
// Iterate through every packet listener
for (PrioritizedListener<AsyncListenerHandler> listener : processingQueue.values()) {
// Remove the listener
if (Objects.equal(listener.getListener().getPlugin(), plugin)) {
unregisterAsyncHandler(listener.getListener());
}
}
} }
/** /**
@ -146,6 +186,7 @@ public class AsyncFilterManager implements AsynchronousManager {
@Override @Override
public void cleanupAll() { public void cleanupAll() {
cleaningUp = true;
serverProcessingQueue.cleanupAll(); serverProcessingQueue.cleanupAll();
serverQueue.cleanupAll(); serverQueue.cleanupAll();
} }

Datei anzeigen

@ -5,6 +5,7 @@ import java.util.logging.Level;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
@ -32,9 +33,6 @@ public class AsyncListenerHandler {
// The packet listener // The packet listener
private PacketListener listener; private PacketListener listener;
// The original plugin
private Plugin plugin;
// The filter manager // The filter manager
private AsyncFilterManager filterManager; private AsyncFilterManager filterManager;
@ -44,13 +42,12 @@ public class AsyncListenerHandler {
// Minecraft main thread // Minecraft main thread
private Thread mainThread; private Thread mainThread;
public AsyncListenerHandler(Plugin plugin, Thread mainThread, AsyncFilterManager filterManager, PacketListener listener) { public AsyncListenerHandler(Thread mainThread, AsyncFilterManager filterManager, PacketListener listener) {
if (filterManager == null) if (filterManager == null)
throw new IllegalArgumentException("filterManager cannot be NULL"); throw new IllegalArgumentException("filterManager cannot be NULL");
if (listener == null) if (listener == null)
throw new IllegalArgumentException("listener cannot be NULL"); throw new IllegalArgumentException("listener cannot be NULL");
this.plugin = plugin;
this.mainThread = mainThread; this.mainThread = mainThread;
this.filterManager = filterManager; this.filterManager = filterManager;
this.listener = listener; this.listener = listener;
@ -173,6 +170,14 @@ public class AsyncListenerHandler {
} }
private String getPluginName() { private String getPluginName() {
return plugin != null ? plugin.getName() : "UNKNOWN"; return PacketAdapter.getPluginName(listener);
}
/**
* Retrieve the plugin associated with this async listener.
* @return The plugin.
*/
public Plugin getPlugin() {
return listener != null ? listener.getPlugin() : null;
} }
} }

Datei anzeigen

@ -2,6 +2,9 @@ package com.comphenix.protocol.async;
import java.io.IOException; import java.io.IOException;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.PriorityBlockingQueue;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
@ -46,6 +49,21 @@ class PacketSendingQueue {
trySendPackets(); trySendPackets();
} }
public synchronized void signalPacketUpdate(List<Integer> packetsRemoved) {
Set<Integer> lookup = new HashSet<Integer>(packetsRemoved);
// Note that this is O(n), so it might be expensive
for (PacketEvent event : sendingQueue) {
if (lookup.contains(event.getPacketID())) {
event.getAsyncMarker().setProcessed(true);
}
}
// This is likely to have changed the situation a bit
trySendPackets();
}
/** /**
* Attempt to send any remaining packets. * Attempt to send any remaining packets.
*/ */

Datei anzeigen

@ -212,9 +212,11 @@ public final class PacketFilterManager implements ProtocolManager {
/** /**
* Determine if the packet IDs in a whitelist is valid. * Determine if the packet IDs in a whitelist is valid.
* @param listener - the listener that will be mentioned in the error.
* @param whitelist - whitelist of packet IDs. * @param whitelist - whitelist of packet IDs.
* @throws IllegalArgumentException If the whitelist is illegal.
*/ */
private void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist) { public static void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist) {
for (Integer id : whitelist.getWhitelist()) { for (Integer id : whitelist.getWhitelist()) {
if (id >= 256 || id < 0) { if (id >= 256 || id < 0) {
throw new IllegalArgumentException(String.format("Invalid packet id %s in listener %s.", throw new IllegalArgumentException(String.format("Invalid packet id %s in listener %s.",
@ -276,6 +278,9 @@ public final class PacketFilterManager implements ProtocolManager {
removePacketListener(listener); removePacketListener(listener);
} }
} }
// Do the same for the asynchronous events
asyncFilterManager.unregisterAsyncHandlers(plugin);
} }
/** /**

Datei anzeigen

@ -104,7 +104,7 @@ public final class StructureCompiler {
} }
// Used to load classes // Used to load classes
private static Method defineMethod; private volatile static Method defineMethod;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private Map<StructureKey, Class> compiledCache = new HashMap<StructureKey, Class>(); private Map<StructureKey, Class> compiledCache = new HashMap<StructureKey, Class>();