Replace method synchronization logic

This commit is contained in:
Alexander Söderberg 2020-07-17 16:25:57 +02:00 committed by Alexander Söderberg
parent 7f412f5472
commit 5a3eacde0b
9 changed files with 144 additions and 125 deletions

View File

@ -42,7 +42,6 @@ import com.plotsquared.core.util.PlayerManager;
import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.RegionManager;
import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.StringComparison;
import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.WorldUtil;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskManager;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.BukkitWorld;
@ -54,7 +53,6 @@ import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Material; import org.bukkit.Material;
@ -96,11 +94,11 @@ import org.bukkit.entity.Snowman;
import org.bukkit.entity.Tameable; import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle; import org.bukkit.entity.Vehicle;
import org.bukkit.entity.WaterMob; import org.bukkit.entity.WaterMob;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@ -423,14 +421,18 @@ import java.util.stream.Stream;
@Override @Nullable public String[] getSignSynchronous(@Nonnull final Location location) { @Override @Nullable public String[] getSignSynchronous(@Nonnull final Location location) {
Block block = getWorld(location.getWorldName()) Block block = getWorld(location.getWorldName())
.getBlockAt(location.getX(), location.getY(), location.getZ()); .getBlockAt(location.getX(), location.getY(), location.getZ());
return TaskManager.getImplementation().sync(new RunnableVal<String[]>() { try {
@Override public void run(String[] value) { return TaskManager.getImplementation().sync(() -> {
if (block.getState() instanceof Sign) { if (block.getState() instanceof Sign) {
Sign sign = (Sign) block.getState(); Sign sign = (Sign) block.getState();
this.value = sign.getLines(); return sign.getLines();
}
} }
return new String[0];
}); });
} catch (final Exception e) {
e.printStackTrace();
}
return new String[0];
} }
@Override public Location getSpawn(@Nonnull final String world) { @Override public Location getSpawn(@Nonnull final String world) {

View File

@ -31,8 +31,12 @@ import com.plotsquared.bukkit.BukkitPlatform;
import com.plotsquared.core.util.task.PlotSquaredTask; import com.plotsquared.core.util.task.PlotSquaredTask;
import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskManager;
import com.plotsquared.core.util.task.TaskTime; import com.plotsquared.core.util.task.TaskTime;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
/** /**
* Bukkit implementation of {@link TaskManager} using * Bukkit implementation of {@link TaskManager} using
@ -75,6 +79,10 @@ import javax.annotation.Nonnull;
} }
} }
@Override public <T> Future<T> callMethodSync(@NotNull final Callable<T> method) {
return Bukkit.getScheduler().callSyncMethod(this.bukkitMain, method);
}
@Override public void task(@Nonnull final Runnable runnable) { @Override public void task(@Nonnull final Runnable runnable) {
new BukkitPlotSquaredTask(runnable).runTaskAsynchronously(this.bukkitMain); new BukkitPlotSquaredTask(runnable).runTaskAsynchronously(this.bukkitMain);
} }

View File

@ -147,13 +147,17 @@ public class Auto extends SubCommand {
* @param start * @param start
* @param schematic * @param schematic
*/ */
public static void autoClaimSafe(final PlotPlayer player, final PlotArea area, PlotId start, public static void autoClaimSafe(final PlotPlayer<?> player, final PlotArea area, PlotId start,
final String schematic) { final String schematic) {
player.setMeta(Auto.class.getName(), true); player.setMeta(Auto.class.getName(), true);
autoClaimFromDatabase(player, area, start, new RunnableVal<Plot>() { autoClaimFromDatabase(player, area, start, new RunnableVal<Plot>() {
@Override public void run(final Plot plot) { @Override public void run(final Plot plot) {
try {
TaskManager.getImplementation().sync(new AutoClaimFinishTask(player, plot, area, schematic, TaskManager.getImplementation().sync(new AutoClaimFinishTask(player, plot, area, schematic,
PlotSquared.get().getEventDispatcher())); PlotSquared.get().getEventDispatcher()));
} catch (final Exception e) {
e.printStackTrace();
}
} }
}); });
} }

View File

@ -27,7 +27,6 @@ package com.plotsquared.core.command;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.CaptionUtility; import com.plotsquared.core.configuration.CaptionUtility;
import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Captions;
import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.Settings;
@ -44,23 +43,18 @@ import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.Expression; import com.plotsquared.core.util.Expression;
import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskManager;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@CommandDeclaration(command = "claim", import javax.annotation.Nonnull;
aliases = "c", import javax.annotation.Nullable;
description = "Claim the current plot you're standing on",
category = CommandCategory.CLAIMING, @CommandDeclaration(command = "claim", aliases = "c", description = "Claim the current plot you're standing on", category = CommandCategory.CLAIMING, requiredType = RequiredType.PLAYER, permission = "plots.claim", usage = "/plot claim")
requiredType = RequiredType.PLAYER,
permission = "plots.claim",
usage = "/plot claim")
public class Claim extends SubCommand { public class Claim extends SubCommand {
private static final Logger logger = LoggerFactory.getLogger("P2/" + Claim.class.getSimpleName()); private static final Logger logger =
LoggerFactory.getLogger("P2/" + Claim.class.getSimpleName());
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final EconHandler econHandler; private final EconHandler econHandler;
@ -146,24 +140,29 @@ public class Claim extends SubCommand {
} }
plot.setOwnerAbs(player.getUUID()); plot.setOwnerAbs(player.getUUID());
final String finalSchematic = schematic; final String finalSchematic = schematic;
DBFunc.createPlotSafe(plot, () -> TaskManager.getImplementation().sync(new RunnableVal<Object>() { DBFunc.createPlotSafe(plot, () -> {
@Override public void run(Object value) { try {
TaskManager.getImplementation().sync(() -> {
if (!plot.claim(player, true, finalSchematic, false)) { if (!plot.claim(player, true, finalSchematic, false)) {
logger.info(Captions.PREFIX.getTranslated() + String logger.info(Captions.PREFIX.getTranslated() + String
.format("Failed to claim plot %s", plot.getId().toCommaSeparatedString())); .format("Failed to claim plot %s", plot.getId().toCommaSeparatedString()));
sendMessage(player, Captions.PLOT_NOT_CLAIMED); sendMessage(player, Captions.PLOT_NOT_CLAIMED);
plot.setOwnerAbs(null); plot.setOwnerAbs(null);
} else if (area.isAutoMerge()) { } else if (area.isAutoMerge()) {
PlotMergeEvent event = Claim.this.eventDispatcher PlotMergeEvent mergeEvent = Claim.this.eventDispatcher
.callMerge(plot, Direction.ALL, Integer.MAX_VALUE, player); .callMerge(plot, Direction.ALL, Integer.MAX_VALUE, player);
if (event.getEventResult() == Result.DENY) { if (mergeEvent.getEventResult() == Result.DENY) {
sendMessage(player, Captions.EVENT_DENIED, "Auto merge on claim"); sendMessage(player, Captions.EVENT_DENIED, "Auto merge on claim");
} else { } else {
plot.autoMerge(event.getDir(), event.getMax(), player.getUUID(), true); plot.autoMerge(mergeEvent.getDir(), mergeEvent.getMax(), player.getUUID(), true);
} }
} }
return null;
});
} catch (final Exception e) {
e.printStackTrace();
} }
}), () -> { }, () -> {
logger.info(Captions.PREFIX.getTranslated() + String logger.info(Captions.PREFIX.getTranslated() + String
.format("Failed to add plot %s to the database", .format("Failed to add plot %s to the database",
plot.getId().toCommaSeparatedString())); plot.getId().toCommaSeparatedString()));

View File

@ -479,8 +479,7 @@ public class HybridUtils {
} }
} }
if (!chunks.isEmpty()) { if (!chunks.isEmpty()) {
TaskManager.getImplementation().sync(new RunnableVal<Object>() { TaskManager.getImplementation().sync(() -> {
@Override public void run(Object value) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Iterator<BlockVector2> iterator = chunks.iterator(); Iterator<BlockVector2> iterator = chunks.iterator();
while (System.currentTimeMillis() - start < 20 && !chunks while (System.currentTimeMillis() - start < 20 && !chunks
@ -493,7 +492,7 @@ public class HybridUtils {
logger.info("[P2] Failed to regenerate road"); logger.info("[P2] Failed to regenerate road");
} }
} }
} return null;
}); });
} }
} catch (Exception e) { } catch (Exception e) {

View File

@ -47,11 +47,10 @@ import com.plotsquared.core.setup.PlotAreaBuilder;
import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.setup.SettingsNodesWrapper;
import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskManager;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -141,15 +140,18 @@ public class SinglePlotArea extends GridPlotWorld {
} }
} }
TaskManager.getImplementation().sync(new RunnableVal<Object>() { try {
@Override public void run(Object value) { TaskManager.getImplementation().sync(() -> {
String worldName = id.getX() + "." + id.getY(); final String name = id.getX() + "." + id.getY();
if (PlotSquared.platform().getWorldUtil().isWorld(worldName)) { if (!PlotSquared.platform().getWorldUtil().isWorld(name)) {
return;
}
PlotSquared.platform().getSetupUtils().setupWorld(builder); PlotSquared.platform().getSetupUtils().setupWorld(builder);
} }
return null;
}); });
} catch (final Exception e) {
e.printStackTrace();
}
// String worldName = plot.getWorldName(); // String worldName = plot.getWorldName();
// World world = Bukkit.getWorld(worldName); // World world = Bukkit.getWorld(worldName);
// if (world != null) { // if (world != null) {

View File

@ -28,14 +28,13 @@ package com.plotsquared.core.queue;
import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.MainUtil;
import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.MathMan;
import com.plotsquared.core.util.PatternUtil; import com.plotsquared.core.util.PatternUtil;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskManager;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import javax.annotation.Nonnull;
import javax.annotation.Nonnull;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -185,12 +184,15 @@ public abstract class BasicLocalBlockQueue extends LocalBlockQueue {
@Override public void flush() { @Override public void flush() {
this.globalBlockQueue.dequeue(this); this.globalBlockQueue.dequeue(this);
TaskManager.getImplementation().sync(new RunnableVal<Object>() { try {
@Override public void run(Object value) { TaskManager.getImplementation().sync(() -> {
while (next()) { while (next()) {
} }
} return null;
}); });
} catch (final Exception e) {
e.printStackTrace();
}
} }

View File

@ -36,10 +36,12 @@ import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.EventDispatcher;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import java.util.concurrent.Callable;
import static com.plotsquared.core.util.MainUtil.sendMessage; import static com.plotsquared.core.util.MainUtil.sendMessage;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class AutoClaimFinishTask extends RunnableVal<Object> { public final class AutoClaimFinishTask implements Callable<Boolean> {
private final PlotPlayer player; private final PlotPlayer player;
private final Plot plot; private final Plot plot;
@ -47,11 +49,11 @@ public final class AutoClaimFinishTask extends RunnableVal<Object> {
private final String schematic; private final String schematic;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
@Override public void run(Object value) { @Override public Boolean call() {
player.deleteMeta(Auto.class.getName()); player.deleteMeta(Auto.class.getName());
if (plot == null) { if (plot == null) {
sendMessage(player, Captions.NO_FREE_PLOTS); sendMessage(player, Captions.NO_FREE_PLOTS);
return; return false;
} }
plot.claim(player, true, schematic, false); plot.claim(player, true, schematic, false);
if (area.isAutoMerge()) { if (area.isAutoMerge()) {
@ -62,5 +64,7 @@ public final class AutoClaimFinishTask extends RunnableVal<Object> {
plot.autoMerge(event.getDir(), event.getMax(), player.getUUID(), true); plot.autoMerge(event.getDir(), event.getMax(), player.getUUID(), true);
} }
} }
return true;
} }
} }

View File

@ -26,20 +26,30 @@
package com.plotsquared.core.util.task; package com.plotsquared.core.util.task;
import com.plotsquared.core.PlotSquared; import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.util.RuntimeExceptionRunnableVal;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/**
* Task manager that handles scheduling of tasks.
* Synchronous methods make no guarantee of being scheduled on the
* server thread, instead they guarantee that no two synchronous
* operations happen at the same time. Implementations of
* the task manager might make other guarantees. All asynchronous
* operations will happen on another thread, no matter where
* they're scheduled from.
*/
public abstract class TaskManager { public abstract class TaskManager {
public static final HashSet<String> TELEPORT_QUEUE = new HashSet<>(); public static final HashSet<String> TELEPORT_QUEUE = new HashSet<>();
@ -67,25 +77,6 @@ public abstract class TaskManager {
return PlotSquaredTask.nullTask(); return PlotSquaredTask.nullTask();
} }
/**
* Run a repeating asynchronous task. This will never run on the
* server thread
*
* @param runnable Task to run
* @param taskTime Task interval
* @return Created task object, can be used to cancel the task
*/
@Nonnull public static PlotSquaredTask runTaskRepeatAsync(@Nullable final Runnable runnable,
@NotNull final TaskTime taskTime) {
if (runnable != null) {
if (getImplementation() == null) {
throw new IllegalArgumentException("disabled");
}
return getImplementation().taskRepeatAsync(runnable, taskTime);
}
return PlotSquaredTask.nullTask();
}
/** /**
* Run an asynchronous task. This will never run on the server thread * Run an asynchronous task. This will never run on the server thread
* *
@ -162,34 +153,44 @@ public abstract class TaskManager {
TaskManager.runTask(new ObjectTaskRunnable<>(iterator, task, whenDone)); TaskManager.runTask(new ObjectTaskRunnable<>(iterator, task, whenDone));
} }
public <T> T sync(final RunnableVal<T> function) { /**
* Make a synchronous method call and return the result
*
* @param function Method to call
* @param <T> Return type
* @return Method result
* @throws Exception If the call fails
*/
public <T> T sync(final Callable<T> function) throws Exception {
return sync(function, Integer.MAX_VALUE); return sync(function, Integer.MAX_VALUE);
} }
public <T> T sync(final RunnableVal<T> function, int timeout) { /**
* Make a synchronous method call and return the result
*
* @param function Method to call
* @param timeout Timeout (ms)
* @param <T> Return type
* @return Method result
* @throws Exception If the call fails
*/
public <T> T sync(final Callable<T> function, int timeout) throws Exception {
if (PlotSquared.get().isMainThread(Thread.currentThread())) { if (PlotSquared.get().isMainThread(Thread.currentThread())) {
function.run(); return function.call();
return function.value;
} }
final AtomicBoolean running = new AtomicBoolean(true); return this.callMethodSync(function).get(timeout, TimeUnit.MILLISECONDS);
final RuntimeExceptionRunnableVal<T> run =
new RuntimeExceptionRunnableVal<>(function, running);
TaskManager.getImplementation().task(run);
try {
synchronized (function) {
while (running.get()) {
function.wait(timeout);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
if (run.value != null) {
throw run.value;
}
return function.value;
} }
/**
* Call a method synchronously and return a future with
* the result of the result
*
* @param method Method to be ran synchronously
* @param <T> Return type
* @return Future completing with the result
*/
public abstract <T> Future<T> callMethodSync(@Nonnegative final Callable<T> method);
/** /**
* Run a repeating synchronous task. If using a platform scheduler, * Run a repeating synchronous task. If using a platform scheduler,
* this is guaranteed to run on the server thread * this is guaranteed to run on the server thread
@ -234,8 +235,7 @@ public abstract class TaskManager {
* @param runnable Task to run * @param runnable Task to run
* @param taskTime Task delay * @param taskTime Task delay
*/ */
public abstract void taskLater(@Nonnull Runnable runnable, public abstract void taskLater(@Nonnull Runnable runnable, @Nonnull TaskTime taskTime);
@Nonnull TaskTime taskTime);
/** /**
* Run an asynchronous task after a given delay. This will never * Run an asynchronous task after a given delay. This will never
@ -244,7 +244,6 @@ public abstract class TaskManager {
* @param runnable Task to run * @param runnable Task to run
* @param taskTime Task delay * @param taskTime Task delay
*/ */
public abstract void taskLaterAsync(@Nonnull Runnable runnable, public abstract void taskLaterAsync(@Nonnull Runnable runnable, @Nonnull TaskTime taskTime);
@Nonnull TaskTime taskTime);
} }