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.StringComparison;
import com.plotsquared.core.util.WorldUtil;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
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.BlockTypes;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
@ -96,11 +94,11 @@ import org.bukkit.entity.Snowman;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle;
import org.bukkit.entity.WaterMob;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@ -423,14 +421,18 @@ import java.util.stream.Stream;
@Override @Nullable public String[] getSignSynchronous(@Nonnull final Location location) {
Block block = getWorld(location.getWorldName())
.getBlockAt(location.getX(), location.getY(), location.getZ());
return TaskManager.getImplementation().sync(new RunnableVal<String[]>() {
@Override public void run(String[] value) {
try {
return TaskManager.getImplementation().sync(() -> {
if (block.getState() instanceof Sign) {
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) {

View File

@ -31,8 +31,12 @@ import com.plotsquared.bukkit.BukkitPlatform;
import com.plotsquared.core.util.task.PlotSquaredTask;
import com.plotsquared.core.util.task.TaskManager;
import com.plotsquared.core.util.task.TaskTime;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
/**
* 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) {
new BukkitPlotSquaredTask(runnable).runTaskAsynchronously(this.bukkitMain);
}

View File

@ -147,13 +147,17 @@ public class Auto extends SubCommand {
* @param start
* @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) {
player.setMeta(Auto.class.getName(), true);
autoClaimFromDatabase(player, area, start, new RunnableVal<Plot>() {
@Override public void run(final Plot plot) {
TaskManager.getImplementation().sync(new AutoClaimFinishTask(player, plot, area, schematic,
PlotSquared.get().getEventDispatcher()));
try {
TaskManager.getImplementation().sync(new AutoClaimFinishTask(player, plot, area, schematic,
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.inject.Inject;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.CaptionUtility;
import com.plotsquared.core.configuration.Captions;
import com.plotsquared.core.configuration.Settings;
@ -44,29 +43,24 @@ import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.Expression;
import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@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")
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@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")
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 EconHandler econHandler;
@Inject public Claim(@Nonnull final EventDispatcher eventDispatcher,
@Nullable final EconHandler econHandler) {
@Nullable final EconHandler econHandler) {
this.eventDispatcher = eventDispatcher;
this.econHandler = econHandler;
}
@ -146,24 +140,29 @@ public class Claim extends SubCommand {
}
plot.setOwnerAbs(player.getUUID());
final String finalSchematic = schematic;
DBFunc.createPlotSafe(plot, () -> TaskManager.getImplementation().sync(new RunnableVal<Object>() {
@Override public void run(Object value) {
if (!plot.claim(player, true, finalSchematic, false)) {
logger.info(Captions.PREFIX.getTranslated() + String
.format("Failed to claim plot %s", plot.getId().toCommaSeparatedString()));
sendMessage(player, Captions.PLOT_NOT_CLAIMED);
plot.setOwnerAbs(null);
} else if (area.isAutoMerge()) {
PlotMergeEvent event = Claim.this.eventDispatcher
.callMerge(plot, Direction.ALL, Integer.MAX_VALUE, player);
if (event.getEventResult() == Result.DENY) {
sendMessage(player, Captions.EVENT_DENIED, "Auto merge on claim");
} else {
plot.autoMerge(event.getDir(), event.getMax(), player.getUUID(), true);
DBFunc.createPlotSafe(plot, () -> {
try {
TaskManager.getImplementation().sync(() -> {
if (!plot.claim(player, true, finalSchematic, false)) {
logger.info(Captions.PREFIX.getTranslated() + String
.format("Failed to claim plot %s", plot.getId().toCommaSeparatedString()));
sendMessage(player, Captions.PLOT_NOT_CLAIMED);
plot.setOwnerAbs(null);
} else if (area.isAutoMerge()) {
PlotMergeEvent mergeEvent = Claim.this.eventDispatcher
.callMerge(plot, Direction.ALL, Integer.MAX_VALUE, player);
if (mergeEvent.getEventResult() == Result.DENY) {
sendMessage(player, Captions.EVENT_DENIED, "Auto merge on claim");
} else {
plot.autoMerge(mergeEvent.getDir(), mergeEvent.getMax(), player.getUUID(), true);
}
}
}
return null;
});
} catch (final Exception e) {
e.printStackTrace();
}
}), () -> {
}, () -> {
logger.info(Captions.PREFIX.getTranslated() + String
.format("Failed to add plot %s to the database",
plot.getId().toCommaSeparatedString()));

View File

@ -479,21 +479,20 @@ public class HybridUtils {
}
}
if (!chunks.isEmpty()) {
TaskManager.getImplementation().sync(new RunnableVal<Object>() {
@Override public void run(Object value) {
long start = System.currentTimeMillis();
Iterator<BlockVector2> iterator = chunks.iterator();
while (System.currentTimeMillis() - start < 20 && !chunks
.isEmpty()) {
final BlockVector2 chunk = iterator.next();
iterator.remove();
boolean regenedRoads =
regenerateRoad(area, chunk, extend);
if (!regenedRoads && Settings.DEBUG) {
logger.info("[P2] Failed to regenerate road");
}
TaskManager.getImplementation().sync(() -> {
long start = System.currentTimeMillis();
Iterator<BlockVector2> iterator = chunks.iterator();
while (System.currentTimeMillis() - start < 20 && !chunks
.isEmpty()) {
final BlockVector2 chunk = iterator.next();
iterator.remove();
boolean regenedRoads =
regenerateRoad(area, chunk, extend);
if (!regenedRoads && Settings.DEBUG) {
logger.info("[P2] Failed to regenerate road");
}
}
return null;
});
}
} 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.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@ -141,15 +140,18 @@ public class SinglePlotArea extends GridPlotWorld {
}
}
TaskManager.getImplementation().sync(new RunnableVal<Object>() {
@Override public void run(Object value) {
String worldName = id.getX() + "." + id.getY();
if (PlotSquared.platform().getWorldUtil().isWorld(worldName)) {
return;
try {
TaskManager.getImplementation().sync(() -> {
final String name = id.getX() + "." + id.getY();
if (!PlotSquared.platform().getWorldUtil().isWorld(name)) {
PlotSquared.platform().getSetupUtils().setupWorld(builder);
}
PlotSquared.platform().getSetupUtils().setupWorld(builder);
}
});
return null;
});
} catch (final Exception e) {
e.printStackTrace();
}
// String worldName = plot.getWorldName();
// World world = Bukkit.getWorld(worldName);
// 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.MathMan;
import com.plotsquared.core.util.PatternUtil;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import javax.annotation.Nonnull;
import javax.annotation.Nonnull;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutionException;
@ -185,12 +184,15 @@ public abstract class BasicLocalBlockQueue extends LocalBlockQueue {
@Override public void flush() {
this.globalBlockQueue.dequeue(this);
TaskManager.getImplementation().sync(new RunnableVal<Object>() {
@Override public void run(Object value) {
try {
TaskManager.getImplementation().sync(() -> {
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 lombok.RequiredArgsConstructor;
import java.util.concurrent.Callable;
import static com.plotsquared.core.util.MainUtil.sendMessage;
@RequiredArgsConstructor
public final class AutoClaimFinishTask extends RunnableVal<Object> {
public final class AutoClaimFinishTask implements Callable<Boolean> {
private final PlotPlayer player;
private final Plot plot;
@ -47,11 +49,11 @@ public final class AutoClaimFinishTask extends RunnableVal<Object> {
private final String schematic;
private final EventDispatcher eventDispatcher;
@Override public void run(Object value) {
@Override public Boolean call() {
player.deleteMeta(Auto.class.getName());
if (plot == null) {
sendMessage(player, Captions.NO_FREE_PLOTS);
return;
return false;
}
plot.claim(player, true, schematic, false);
if (area.isAutoMerge()) {
@ -62,5 +64,7 @@ public final class AutoClaimFinishTask extends RunnableVal<Object> {
plot.autoMerge(event.getDir(), event.getMax(), player.getUUID(), true);
}
}
return true;
}
}

View File

@ -26,20 +26,30 @@
package com.plotsquared.core.util.task;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.util.RuntimeExceptionRunnableVal;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
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;
/**
* 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 static final HashSet<String> TELEPORT_QUEUE = new HashSet<>();
@ -57,7 +67,7 @@ public abstract class TaskManager {
* @return Created task object, can be used to cancel the task
*/
@Nonnull public static PlotSquaredTask runTaskRepeat(@Nullable final Runnable runnable,
@Nonnull final TaskTime taskTime) {
@Nonnull final TaskTime taskTime) {
if (runnable != null) {
if (getImplementation() == null) {
throw new IllegalArgumentException("disabled");
@ -67,25 +77,6 @@ public abstract class TaskManager {
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
*
@ -125,7 +116,7 @@ public abstract class TaskManager {
* @param taskTime Task delay
*/
public static void runTaskLater(@Nullable final Runnable runnable,
@Nonnull final TaskTime taskTime) {
@Nonnull final TaskTime taskTime) {
if (runnable != null) {
if (getImplementation() == null) {
runnable.run();
@ -143,7 +134,7 @@ public abstract class TaskManager {
* @param taskTime Task delay
*/
public static void runTaskLaterAsync(@Nullable final Runnable runnable,
@Nonnull final TaskTime taskTime) {
@Nonnull final TaskTime taskTime) {
if (runnable != null) {
if (getImplementation() == null) {
runnable.run();
@ -162,34 +153,44 @@ public abstract class TaskManager {
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);
}
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())) {
function.run();
return function.value;
return function.call();
}
final AtomicBoolean running = new AtomicBoolean(true);
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;
return this.callMethodSync(function).get(timeout, TimeUnit.MILLISECONDS);
}
/**
* 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,
* this is guaranteed to run on the server thread
@ -199,7 +200,7 @@ public abstract class TaskManager {
* @return Created task object, can be used to cancel the task
*/
public abstract PlotSquaredTask taskRepeat(@Nonnull Runnable runnable,
@Nonnull TaskTime taskTime);
@Nonnull TaskTime taskTime);
/**
* Run a repeating asynchronous task. This will never run on the
@ -210,7 +211,7 @@ public abstract class TaskManager {
* @return Created task object, can be used to cancel the task
*/
public abstract PlotSquaredTask taskRepeatAsync(@Nonnull Runnable runnable,
@Nonnull TaskTime taskTime);
@Nonnull TaskTime taskTime);
/**
* Run an asynchronous task. This will never run on the server thread
@ -234,8 +235,7 @@ public abstract class TaskManager {
* @param runnable Task to run
* @param taskTime Task delay
*/
public abstract void taskLater(@Nonnull Runnable runnable,
@Nonnull TaskTime taskTime);
public abstract void taskLater(@Nonnull Runnable runnable, @Nonnull TaskTime taskTime);
/**
* 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 taskTime Task delay
*/
public abstract void taskLaterAsync(@Nonnull Runnable runnable,
@Nonnull TaskTime taskTime);
public abstract void taskLaterAsync(@Nonnull Runnable runnable, @Nonnull TaskTime taskTime);
}