Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-12-25 18:40:05 +01:00
feat: alter clipboard thread to move all clipboard loading from main thread (#2867)
Dieser Commit ist enthalten in:
Ursprung
e55e8fabe8
Commit
eb0f07af81
@ -564,17 +564,17 @@ public class WorldEditPlugin extends JavaPlugin {
|
||||
public BukkitPlayer wrapPlayer(Player player) {
|
||||
//FAWE start - Use cache over returning a direct BukkitPlayer
|
||||
BukkitPlayer wePlayer = getCachedPlayer(player);
|
||||
if (wePlayer == null) {
|
||||
synchronized (player) {
|
||||
wePlayer = getCachedPlayer(player);
|
||||
if (wePlayer == null) {
|
||||
wePlayer = new BukkitPlayer(this, player);
|
||||
player.setMetadata("WE", new FixedMetadataValue(this, wePlayer));
|
||||
return wePlayer;
|
||||
}
|
||||
}
|
||||
if (wePlayer != null) {
|
||||
return wePlayer;
|
||||
}
|
||||
synchronized (player) {
|
||||
BukkitPlayer bukkitPlayer = getCachedPlayer(player);
|
||||
if (bukkitPlayer == null) {
|
||||
bukkitPlayer = new BukkitPlayer(this, player);
|
||||
player.setMetadata("WE", new FixedMetadataValue(this, bukkitPlayer));
|
||||
}
|
||||
return bukkitPlayer;
|
||||
}
|
||||
return wePlayer;
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,8 @@ import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.TextureUtil;
|
||||
import com.fastasyncworldedit.core.util.WEManager;
|
||||
import com.fastasyncworldedit.core.util.task.KeyQueuedExecutorService;
|
||||
import com.fastasyncworldedit.core.util.task.UUIDKeyQueuedThreadFactory;
|
||||
import com.github.luben.zstd.Zstd;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
@ -37,6 +37,9 @@ import java.lang.management.MemoryUsage;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -92,7 +95,7 @@ public class Fawe {
|
||||
* The platform specific implementation.
|
||||
*/
|
||||
private final IFawe implementation;
|
||||
private final KeyQueuedExecutorService<UUID> clipboardExecutor;
|
||||
private final KeyQueuedExecutorService<UUID> uuidKeyQueuedExecutorService;
|
||||
private FaweVersion version;
|
||||
private TextureUtil textures;
|
||||
private QueueHandler queueHandler;
|
||||
@ -140,14 +143,13 @@ public class Fawe {
|
||||
}, 0);
|
||||
|
||||
TaskManager.taskManager().repeat(timer, 1);
|
||||
|
||||
clipboardExecutor = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
|
||||
uuidKeyQueuedExecutorService = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
|
||||
1,
|
||||
Settings.settings().QUEUE.PARALLEL_THREADS,
|
||||
0L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<>(),
|
||||
new ThreadFactoryBuilder().setNameFormat("FAWE Clipboard - %d").build()
|
||||
new UUIDKeyQueuedThreadFactory()
|
||||
));
|
||||
}
|
||||
|
||||
@ -463,9 +465,58 @@ public class Fawe {
|
||||
*
|
||||
* @return Executor used for clipboard IO if clipboard on disk is enabled or null
|
||||
* @since 2.6.2
|
||||
* @deprecated Use any of {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable)},
|
||||
* {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable, Object), {@link Fawe#submitUUIDKeyQueuedTask(UUID, Callable)}
|
||||
* to ensure if a thread is already a UUID-queued thread, the task is immediately run
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "TODO")
|
||||
public KeyQueuedExecutorService<UUID> getClipboardExecutor() {
|
||||
return this.clipboardExecutor;
|
||||
return this.uuidKeyQueuedExecutorService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a task to the UUID key-queued executor
|
||||
*
|
||||
* @return Future representing the tank
|
||||
* @since TODO
|
||||
*/
|
||||
public Future<?> submitUUIDKeyQueuedTask(UUID uuid, Runnable runnable) {
|
||||
if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) {
|
||||
runnable.run();
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
return this.uuidKeyQueuedExecutorService.submit(uuid, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a task to the UUID key-queued executor
|
||||
*
|
||||
* @return Future representing the tank
|
||||
* @since TODO
|
||||
*/
|
||||
public <T> Future<T> submitUUIDKeyQueuedTask(UUID uuid, Runnable runnable, T result) {
|
||||
if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) {
|
||||
runnable.run();
|
||||
return CompletableFuture.completedFuture(result);
|
||||
}
|
||||
return this.uuidKeyQueuedExecutorService.submit(uuid, runnable, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a task to the UUID key-queued executor
|
||||
*
|
||||
* @return Future representing the tank
|
||||
* @since TODO
|
||||
*/
|
||||
public <T> Future<T> submitUUIDKeyQueuedTask(UUID uuid, Callable<T> callable) {
|
||||
if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) {
|
||||
try {
|
||||
return CompletableFuture.completedFuture(callable.call());
|
||||
} catch (Throwable t) {
|
||||
return CompletableFuture.failedFuture(t);
|
||||
}
|
||||
}
|
||||
return this.uuidKeyQueuedExecutorService.submit(uuid, callable);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
package com.fastasyncworldedit.core.util.task;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class UUIDKeyQueuedThreadFactory implements ThreadFactory {
|
||||
|
||||
private final ThreadGroup group;
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
private final String namePrefix;
|
||||
|
||||
public UUIDKeyQueuedThreadFactory() {
|
||||
group = new ThreadGroup("UUIDKeyQueuedThreadGroup");
|
||||
namePrefix = "FAWE UUID-key-queued - ";
|
||||
}
|
||||
|
||||
public Thread newThread(@Nonnull Runnable r) {
|
||||
Thread t = new UUIDKeyQueuedThread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
|
||||
if (t.isDaemon()) {
|
||||
t.setDaemon(false);
|
||||
}
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public static final class UUIDKeyQueuedThread extends Thread {
|
||||
|
||||
public UUIDKeyQueuedThread(@Nullable ThreadGroup group, Runnable task, @Nonnull String name, long stackSize) {
|
||||
super(group, task, name, stackSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -930,7 +930,7 @@ public class LocalSession implements TextureHolder {
|
||||
}
|
||||
} catch (EmptyClipboardException ignored) {
|
||||
}
|
||||
DiskOptimizedClipboard doc = Fawe.instance().getClipboardExecutor().submit(
|
||||
DiskOptimizedClipboard doc = Fawe.instance().submitUUIDKeyQueuedTask(
|
||||
uuid,
|
||||
() -> DiskOptimizedClipboard.loadFromFile(file)
|
||||
).get();
|
||||
@ -954,7 +954,7 @@ public class LocalSession implements TextureHolder {
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
Fawe.instance().getClipboardExecutor().submit(uuid, () -> {
|
||||
Fawe.instance().submitUUIDKeyQueuedTask(uuid, () -> {
|
||||
doc.close(); // Ensure closed before deletion
|
||||
doc.getFile().delete();
|
||||
});
|
||||
|
@ -325,7 +325,7 @@ public class ClipboardCommands {
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
Fawe.instance().getClipboardExecutor().submit(actor.getUniqueId(), () -> {
|
||||
Fawe.instance().submitUUIDKeyQueuedTask(actor.getUniqueId(), () -> {
|
||||
clipboard.close();
|
||||
doc.getFile().delete();
|
||||
});
|
||||
|
@ -423,7 +423,7 @@ public interface Player extends Entity, Actor {
|
||||
if (Settings.settings().CLIPBOARD.USE_DISK && Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) {
|
||||
session.deleteClipboardOnDisk();
|
||||
} else if (Settings.settings().CLIPBOARD.USE_DISK) {
|
||||
Fawe.instance().getClipboardExecutor().submit(getUniqueId(), () -> session.setClipboard(null));
|
||||
Fawe.instance().submitUUIDKeyQueuedTask(getUniqueId(), () -> session.setClipboard(null));
|
||||
} else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) {
|
||||
session.setClipboard(null);
|
||||
}
|
||||
@ -436,32 +436,8 @@ public interface Player extends Entity, Actor {
|
||||
void sendTitle(Component title, Component sub);
|
||||
|
||||
/**
|
||||
* Loads any history items from disk: - Should already be called if history on disk is enabled.
|
||||
* Loads clipboard file from disk if it exists
|
||||
*/
|
||||
default void loadClipboardFromDisk() {
|
||||
File file = MainUtil.getFile(
|
||||
Fawe.platform().getDirectory(),
|
||||
Settings.settings().PATHS.CLIPBOARD + File.separator + getUniqueId() + ".bd"
|
||||
);
|
||||
try {
|
||||
getSession().loadClipboardFromDisk(file);
|
||||
} catch (FaweClipboardVersionMismatchException e) {
|
||||
print(e.getComponent());
|
||||
} catch (RuntimeException e) {
|
||||
print(Caption.of("fawe.error.clipboard.invalid"));
|
||||
e.printStackTrace();
|
||||
print(Caption.of("fawe.error.stacktrace"));
|
||||
print(Caption.of("fawe.error.clipboard.load.failure"));
|
||||
print(Caption.of("fawe.error.clipboard.invalid.info", file.getName(), file.length()));
|
||||
print(Caption.of("fawe.error.stacktrace"));
|
||||
} catch (Exception e) {
|
||||
print(Caption.of("fawe.error.clipboard.invalid"));
|
||||
e.printStackTrace();
|
||||
print(Caption.of("fawe.error.stacktrace"));
|
||||
print(Caption.of("fawe.error.no-failure"));
|
||||
print(Caption.of("fawe.error.clipboard.invalid.info", file.getName(), file.length()));
|
||||
print(Caption.of("fawe.error.stacktrace"));
|
||||
}
|
||||
}
|
||||
void loadClipboardFromDisk();
|
||||
//FAWE end
|
||||
}
|
||||
|
@ -19,10 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.extension.platform;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismatchException;
|
||||
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||
import com.fastasyncworldedit.core.math.MutableBlockVector3;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.util.MainUtil;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.WEManager;
|
||||
import com.fastasyncworldedit.core.util.task.AsyncNotifyKeyedQueue;
|
||||
@ -69,6 +73,8 @@ import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
@ -82,6 +88,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
|
||||
//FAWE start
|
||||
private final Map<String, Object> meta;
|
||||
private final Semaphore clipboardLoading = new Semaphore(1);
|
||||
|
||||
// Queue for async tasks
|
||||
private final AtomicInteger runningCount = new AtomicInteger();
|
||||
@ -524,22 +531,68 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
|
||||
@Override
|
||||
public void setSelection(Region region) {
|
||||
RegionSelector selector;
|
||||
if (region instanceof ConvexPolyhedralRegion) {
|
||||
selector = new ConvexPolyhedralRegionSelector((ConvexPolyhedralRegion) region);
|
||||
} else if (region instanceof CylinderRegion) {
|
||||
selector = new CylinderRegionSelector((CylinderRegion) region);
|
||||
} else if (region instanceof Polygonal2DRegion) {
|
||||
selector = new Polygonal2DRegionSelector((Polygonal2DRegion) region);
|
||||
} else {
|
||||
selector = new CuboidRegionSelector(null, region.getMinimumPoint(),
|
||||
region.getMaximumPoint()
|
||||
);
|
||||
}
|
||||
RegionSelector selector = switch (region) {
|
||||
case ConvexPolyhedralRegion blockVector3s -> new ConvexPolyhedralRegionSelector(blockVector3s);
|
||||
case CylinderRegion blockVector3s -> new CylinderRegionSelector(blockVector3s);
|
||||
case Polygonal2DRegion blockVector3s -> new Polygonal2DRegionSelector(blockVector3s);
|
||||
default -> new CuboidRegionSelector(null, region.getMinimumPoint(), region.getMaximumPoint());
|
||||
};
|
||||
selector.setWorld(region.getWorld());
|
||||
|
||||
getSession().setRegionSelector(getWorld(), selector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadClipboardFromDisk() {
|
||||
if (!clipboardLoading.tryAcquire()) {
|
||||
if (!Fawe.isMainThread()) {
|
||||
try {
|
||||
clipboardLoading.acquire();
|
||||
clipboardLoading.release();
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("Error waiting for clipboard-on-disk loading for player {}", getName(), e);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
File file = MainUtil.getFile(
|
||||
Fawe.platform().getDirectory(),
|
||||
Settings.settings().PATHS.CLIPBOARD + File.separator + getUniqueId() + ".bd"
|
||||
);
|
||||
try {
|
||||
Future<?> fut = Fawe.instance().submitUUIDKeyQueuedTask(getUniqueId(), () -> {
|
||||
try {
|
||||
getSession().loadClipboardFromDisk(file);
|
||||
} catch (FaweClipboardVersionMismatchException e) {
|
||||
print(e.getComponent());
|
||||
} catch (RuntimeException e) {
|
||||
print(Caption.of("fawe.error.clipboard.invalid"));
|
||||
LOGGER.error("Error loading clipboard from disk", e);
|
||||
print(Caption.of("fawe.error.stacktrace"));
|
||||
print(Caption.of("fawe.error.clipboard.load.failure"));
|
||||
print(Caption.of("fawe.error.clipboard.invalid.info", file.getName(), file.length()));
|
||||
print(Caption.of("fawe.error.stacktrace"));
|
||||
} catch (Exception e) {
|
||||
print(Caption.of("fawe.error.clipboard.invalid"));
|
||||
LOGGER.error("Error loading clipboard from disk", e);
|
||||
print(Caption.of("fawe.error.stacktrace"));
|
||||
print(Caption.of("fawe.error.no-failure"));
|
||||
print(Caption.of("fawe.error.clipboard.invalid.info", file.getName(), file.length()));
|
||||
print(Caption.of("fawe.error.stacktrace"));
|
||||
} finally {
|
||||
clipboardLoading.release();
|
||||
}
|
||||
});
|
||||
if (Fawe.isMainThread()) {
|
||||
return;
|
||||
}
|
||||
fut.get();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error loading clipboard from disk", e);
|
||||
print(Caption.of("fawe.error.clipboard.load.failure"));
|
||||
}
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
@Override
|
||||
@ -698,10 +751,9 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Player)) {
|
||||
if (!(other instanceof Player other2)) {
|
||||
return false;
|
||||
}
|
||||
Player other2 = (Player) other;
|
||||
return other2.getName().equals(getName());
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@
|
||||
"fawe.error.parse.no-clipboard-source": "No clipboards found at given source: {0}",
|
||||
"fawe.error.clipboard.invalid": "====== INVALID CLIPBOARD ======",
|
||||
"fawe.error.clipboard.invalid.info": "File: {0} (len: {1})",
|
||||
"fawe.error.clipboard.load.failure": "Could not load clipboard. Possible that the clipboard is still being written to from another server?!",
|
||||
"fawe.error.clipboard.load.failure": "Unexpected failure loading clipboard from disk!",
|
||||
"fawe.error.clipboard.on.disk.version.mismatch": "Clipboard version mismatch: expected {0} but got {1}. It is recommended you delete the clipboard folder and restart the server.\nYour clipboard folder is located at {2}.",
|
||||
"fawe.error.limit.disallowed-block": "Your limit disallows use of block '{0}'",
|
||||
"fawe.error.limit.disallowed-property": "Your limit disallows use of property '{0}'",
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren