mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 01:37:37 +00:00
Implement async notify queue that submits to a KeyQueuedExecutorService (#2334)
This commit is contained in:
parent
18df87a4e8
commit
9543adc776
@ -27,6 +27,7 @@ import java.util.Queue;
|
|||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
import java.util.concurrent.ForkJoinTask;
|
import java.util.concurrent.ForkJoinTask;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
@ -52,6 +53,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
|||||||
null,
|
null,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Secondary queue should be used for "cleanup" tasks that are likely to be shorter in life than those submitted to the
|
* Secondary queue should be used for "cleanup" tasks that are likely to be shorter in life than those submitted to the
|
||||||
* primary queue. They may be IO-bound tasks.
|
* primary queue. They may be IO-bound tasks.
|
||||||
@ -508,4 +510,28 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Primary queue should be used for tasks that are unlikely to wait on other tasks, IO, etc. (i.e. spend most of their
|
||||||
|
* time utilising CPU.
|
||||||
|
* <p>
|
||||||
|
* Internal API usage only.
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public ExecutorService getForkJoinPoolPrimary() {
|
||||||
|
return forkJoinPoolPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secondary queue should be used for "cleanup" tasks that are likely to be shorter in life than those submitted to the
|
||||||
|
* primary queue. They may be IO-bound tasks.
|
||||||
|
* <p>
|
||||||
|
* Internal API usage only.
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public ExecutorService getForkJoinPoolSecondary() {
|
||||||
|
return forkJoinPoolSecondary;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.fastasyncworldedit.core.util.task;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* async queue that accepts a {@link Thread.UncaughtExceptionHandler} for exception handling per instance, delegating to a
|
||||||
|
* parent {@link KeyQueuedExecutorService}.
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public class AsyncNotifyKeyedQueue implements Closeable {
|
||||||
|
|
||||||
|
private static final KeyQueuedExecutorService<UUID> QUEUE_SUBMISSIONS = new KeyQueuedExecutorService<>(new ForkJoinPool(
|
||||||
|
Settings.settings().QUEUE.PARALLEL_THREADS,
|
||||||
|
new FaweForkJoinWorkerThreadFactory("AsyncNotifyKeyedQueue - %s"),
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
));
|
||||||
|
|
||||||
|
private final Thread.UncaughtExceptionHandler handler;
|
||||||
|
private final Supplier<UUID> key;
|
||||||
|
private volatile boolean closed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New instance
|
||||||
|
*
|
||||||
|
* @param handler exception handler
|
||||||
|
* @param key supplier of UUID key
|
||||||
|
*/
|
||||||
|
public AsyncNotifyKeyedQueue(Thread.UncaughtExceptionHandler handler, Supplier<UUID> key) {
|
||||||
|
this.handler = handler;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thread.UncaughtExceptionHandler getHandler() {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Future<T> run(Runnable task) {
|
||||||
|
return call(() -> {
|
||||||
|
task.run();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Future<T> call(Callable<T> task) {
|
||||||
|
Future[] self = new Future[1];
|
||||||
|
Callable<T> wrapped = () -> {
|
||||||
|
if (!closed) {
|
||||||
|
try {
|
||||||
|
return task.call();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
handler.uncaughtException(Thread.currentThread(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self[0] != null) {
|
||||||
|
self[0].cancel(true);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
self[0] = QUEUE_SUBMISSIONS.submit(key.get(), wrapped);
|
||||||
|
return self[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,13 +1,9 @@
|
|||||||
package com.fastasyncworldedit.core.util.task;
|
package com.fastasyncworldedit.core.util.task;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ForkJoinPool;
|
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
@ -15,13 +11,6 @@ import java.util.function.Supplier;
|
|||||||
|
|
||||||
public class AsyncNotifyQueue implements Closeable {
|
public class AsyncNotifyQueue implements Closeable {
|
||||||
|
|
||||||
private static final ForkJoinPool QUEUE_SUBMISSIONS = new ForkJoinPool(
|
|
||||||
Settings.settings().QUEUE.PARALLEL_THREADS,
|
|
||||||
new FaweForkJoinWorkerThreadFactory("AsyncNotifyQueue - %s"),
|
|
||||||
null,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
private final Lock lock = new ReentrantLock(true);
|
private final Lock lock = new ReentrantLock(true);
|
||||||
private final Thread.UncaughtExceptionHandler handler;
|
private final Thread.UncaughtExceptionHandler handler;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
@ -56,9 +45,6 @@ public class AsyncNotifyQueue implements Closeable {
|
|||||||
return task.call();
|
return task.call();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
handler.uncaughtException(Thread.currentThread(), e);
|
handler.uncaughtException(Thread.currentThread(), e);
|
||||||
if (self[0] != null) {
|
|
||||||
self[0].cancel(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -70,7 +56,7 @@ public class AsyncNotifyQueue implements Closeable {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
self[0] = QUEUE_SUBMISSIONS.submit(wrapped);
|
self[0] = Fawe.instance().getQueueHandler().async(wrapped);
|
||||||
return self[0];
|
return self[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,10 +19,9 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.extension.platform;
|
package com.sk89q.worldedit.extension.platform;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.configuration.Caption;
|
|
||||||
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.fastasyncworldedit.core.util.task.AsyncNotifyQueue;
|
import com.fastasyncworldedit.core.util.task.AsyncNotifyKeyedQueue;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
||||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||||
@ -68,7 +67,7 @@ public abstract class AbstractNonPlayerActor implements Actor {
|
|||||||
|
|
||||||
// Queue for async tasks
|
// Queue for async tasks
|
||||||
private final AtomicInteger runningCount = new AtomicInteger();
|
private final AtomicInteger runningCount = new AtomicInteger();
|
||||||
private final AsyncNotifyQueue asyncNotifyQueue = new AsyncNotifyQueue((thread, throwable) -> {
|
private final AsyncNotifyKeyedQueue asyncNotifyQueue = new AsyncNotifyKeyedQueue((thread, throwable) -> {
|
||||||
while (throwable.getCause() != null) {
|
while (throwable.getCause() != null) {
|
||||||
throwable = throwable.getCause();
|
throwable = throwable.getCause();
|
||||||
}
|
}
|
||||||
@ -82,7 +81,7 @@ public abstract class AbstractNonPlayerActor implements Actor {
|
|||||||
throwable.printStackTrace();
|
throwable.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}, this::getUniqueId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run a task either async, or on the current thread.
|
* Run a task either async, or on the current thread.
|
||||||
|
@ -25,7 +25,7 @@ import com.fastasyncworldedit.core.math.MutableBlockVector3;
|
|||||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.fastasyncworldedit.core.util.WEManager;
|
import com.fastasyncworldedit.core.util.WEManager;
|
||||||
import com.fastasyncworldedit.core.util.task.AsyncNotifyQueue;
|
import com.fastasyncworldedit.core.util.task.AsyncNotifyKeyedQueue;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
@ -81,7 +81,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
|||||||
|
|
||||||
// Queue for async tasks
|
// Queue for async tasks
|
||||||
private final AtomicInteger runningCount = new AtomicInteger();
|
private final AtomicInteger runningCount = new AtomicInteger();
|
||||||
private final AsyncNotifyQueue asyncNotifyQueue = new AsyncNotifyQueue(
|
private final AsyncNotifyKeyedQueue asyncNotifyQueue = new AsyncNotifyKeyedQueue(
|
||||||
(thread, throwable) -> {
|
(thread, throwable) -> {
|
||||||
while (throwable.getCause() != null) {
|
while (throwable.getCause() != null) {
|
||||||
throwable = throwable.getCause();
|
throwable = throwable.getCause();
|
||||||
@ -96,7 +96,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
|||||||
throwable.printStackTrace();
|
throwable.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}, this::getUniqueId);
|
||||||
|
|
||||||
public AbstractPlayerActor(Map<String, Object> meta) {
|
public AbstractPlayerActor(Map<String, Object> meta) {
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
|
Loading…
Reference in New Issue
Block a user