3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-09-29 02:21:06 +02:00

feat: alter clipboard thread to move all clipboard loading from main thread

Dieser Commit ist enthalten in:
dordsor21 2024-08-01 21:24:42 +01:00
Ursprung f93ad596c6
Commit 203948d4bb
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 1E53E88969FFCF0B
6 geänderte Dateien mit 167 neuen und 59 gelöschten Zeilen

Datei anzeigen

@ -21,6 +21,7 @@ package com.sk89q.worldedit.bukkit;
import com.fastasyncworldedit.bukkit.BukkitPermissionAttachmentManager; import com.fastasyncworldedit.bukkit.BukkitPermissionAttachmentManager;
import com.fastasyncworldedit.bukkit.FaweBukkit; import com.fastasyncworldedit.bukkit.FaweBukkit;
import com.fastasyncworldedit.core.util.TaskManager;
import com.fastasyncworldedit.core.util.UpdateNotification; import com.fastasyncworldedit.core.util.UpdateNotification;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.util.WEManager; import com.fastasyncworldedit.core.util.WEManager;
@ -91,6 +92,7 @@ import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
@ -565,14 +567,15 @@ public class WorldEditPlugin extends JavaPlugin {
//FAWE start - Use cache over returning a direct BukkitPlayer //FAWE start - Use cache over returning a direct BukkitPlayer
BukkitPlayer wePlayer = getCachedPlayer(player); BukkitPlayer wePlayer = getCachedPlayer(player);
if (wePlayer == null) { if (wePlayer == null) {
synchronized (player) { Supplier<BukkitPlayer> task = () -> {
wePlayer = getCachedPlayer(player); BukkitPlayer bukkitPlayer = getCachedPlayer(player);
if (wePlayer == null) { if (bukkitPlayer == null) {
wePlayer = new BukkitPlayer(this, player); bukkitPlayer = new BukkitPlayer(this, player);
player.setMetadata("WE", new FixedMetadataValue(this, wePlayer)); player.setMetadata("WE", new FixedMetadataValue(this, bukkitPlayer));
return wePlayer;
} }
} return bukkitPlayer;
};
TaskManager.taskManager().sync(task);
} }
return wePlayer; return wePlayer;
//FAWE end //FAWE end
@ -588,11 +591,12 @@ public class WorldEditPlugin extends JavaPlugin {
} }
BukkitPlayer reCachePlayer(Player player) { BukkitPlayer reCachePlayer(Player player) {
synchronized (player) { Supplier<BukkitPlayer> task = () -> {
BukkitPlayer wePlayer = new BukkitPlayer(this, player); BukkitPlayer wePlayer = new BukkitPlayer(this, player);
player.setMetadata("WE", new FixedMetadataValue(this, wePlayer)); player.setMetadata("WE", new FixedMetadataValue(this, wePlayer));
return wePlayer; return wePlayer;
} };
return TaskManager.taskManager().sync(task);
} }
//FAWE end //FAWE end

Datei anzeigen

@ -21,6 +21,7 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat;
import net.jpountz.lz4.LZ4Factory; import net.jpountz.lz4.LZ4Factory;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceAlreadyExistsException;
import javax.management.NotificationEmitter; import javax.management.NotificationEmitter;
@ -37,7 +38,12 @@ import java.lang.management.MemoryUsage;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -81,6 +87,7 @@ import java.util.concurrent.TimeUnit;
public class Fawe { public class Fawe {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final ThreadLocal<Boolean> IS_UUID_KEYED_EXECUTOR_THREAD = ThreadLocal.withInitial(() -> false);
private static Fawe instance; private static Fawe instance;
@ -92,7 +99,7 @@ public class Fawe {
* The platform specific implementation. * The platform specific implementation.
*/ */
private final IFawe implementation; private final IFawe implementation;
private final KeyQueuedExecutorService<UUID> clipboardExecutor; private final KeyQueuedExecutorService<UUID> uuidKeyQueuedExecutorService;
private FaweVersion version; private FaweVersion version;
private TextureUtil textures; private TextureUtil textures;
private QueueHandler queueHandler; private QueueHandler queueHandler;
@ -140,14 +147,27 @@ public class Fawe {
}, 0); }, 0);
TaskManager.taskManager().repeat(timer, 1); TaskManager.taskManager().repeat(timer, 1);
uuidKeyQueuedExecutorService = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
clipboardExecutor = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
1, 1,
Settings.settings().QUEUE.PARALLEL_THREADS, Settings.settings().QUEUE.PARALLEL_THREADS,
0L, 0L,
TimeUnit.MILLISECONDS, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(), new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder().setNameFormat("FAWE Clipboard - %d").build() new ThreadFactoryBuilder().setNameFormat("FAWE UUID-key-queued - %d").setThreadFactory(new ThreadFactory() {
private final ThreadFactory defaultFactory = Executors.defaultThreadFactory();
@Override
public Thread newThread(@Nonnull Runnable r) {
return defaultFactory.newThread(() -> {
IS_UUID_KEYED_EXECUTOR_THREAD.set(true);
try {
r.run();
} finally {
IS_UUID_KEYED_EXECUTOR_THREAD.set(false); // Clear the mark after execution
}
});
}
}).build()
)); ));
} }
@ -451,9 +471,58 @@ public class Fawe {
* *
* @return Executor used for clipboard IO if clipboard on disk is enabled or null * @return Executor used for clipboard IO if clipboard on disk is enabled or null
* @since 2.6.2 * @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() { 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 (IS_UUID_KEYED_EXECUTOR_THREAD.get()) {
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 (IS_UUID_KEYED_EXECUTOR_THREAD.get()) {
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 (IS_UUID_KEYED_EXECUTOR_THREAD.get()) {
try {
CompletableFuture.completedFuture(callable.call());
} catch (Throwable t) {
CompletableFuture.failedFuture(t);
}
}
return this.uuidKeyQueuedExecutorService.submit(uuid, callable);
} }
} }

Datei anzeigen

@ -930,7 +930,7 @@ public class LocalSession implements TextureHolder {
} }
} catch (EmptyClipboardException ignored) { } catch (EmptyClipboardException ignored) {
} }
DiskOptimizedClipboard doc = Fawe.instance().getClipboardExecutor().submit( DiskOptimizedClipboard doc = Fawe.instance().submitUUIDKeyQueuedTask(
uuid, uuid,
() -> DiskOptimizedClipboard.loadFromFile(file) () -> DiskOptimizedClipboard.loadFromFile(file)
).get(); ).get();
@ -954,7 +954,7 @@ public class LocalSession implements TextureHolder {
} else { } else {
continue; continue;
} }
Fawe.instance().getClipboardExecutor().submit(uuid, () -> { Fawe.instance().submitUUIDKeyQueuedTask(uuid, () -> {
doc.close(); // Ensure closed before deletion doc.close(); // Ensure closed before deletion
doc.getFile().delete(); doc.getFile().delete();
}); });

Datei anzeigen

@ -324,7 +324,7 @@ public class ClipboardCommands {
} else { } else {
throw e; throw e;
} }
Fawe.instance().getClipboardExecutor().submit(actor.getUniqueId(), () -> { Fawe.instance().submitUUIDKeyQueuedTask(actor.getUniqueId(), () -> {
clipboard.close(); clipboard.close();
doc.getFile().delete(); doc.getFile().delete();
}); });

Datei anzeigen

@ -423,7 +423,7 @@ public interface Player extends Entity, Actor {
if (Settings.settings().CLIPBOARD.USE_DISK && Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) { if (Settings.settings().CLIPBOARD.USE_DISK && Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) {
session.deleteClipboardOnDisk(); session.deleteClipboardOnDisk();
} else if (Settings.settings().CLIPBOARD.USE_DISK) { } 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) { } else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) {
session.setClipboard(null); session.setClipboard(null);
} }
@ -436,32 +436,8 @@ public interface Player extends Entity, Actor {
void sendTitle(Component title, Component sub); 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() { 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"));
}
}
//FAWE end //FAWE end
} }

Datei anzeigen

@ -19,10 +19,14 @@
package com.sk89q.worldedit.extension.platform; package com.sk89q.worldedit.extension.platform;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.configuration.Caption; 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.internal.exception.FaweException;
import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.fastasyncworldedit.core.math.MutableBlockVector3;
import com.fastasyncworldedit.core.regions.FaweMaskManager; import com.fastasyncworldedit.core.regions.FaweMaskManager;
import com.fastasyncworldedit.core.util.MainUtil;
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.AsyncNotifyKeyedQueue; import com.fastasyncworldedit.core.util.task.AsyncNotifyKeyedQueue;
@ -34,6 +38,7 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; import com.sk89q.worldedit.regions.ConvexPolyhedralRegion;
@ -62,12 +67,15 @@ import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.gamemode.GameModes;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.item.ItemTypes;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.StampedLock;
/** /**
* An abstract implementation of both a {@link Actor} and a {@link Player} * An abstract implementation of both a {@link Actor} and a {@link Player}
@ -76,8 +84,11 @@ import java.util.concurrent.atomic.AtomicInteger;
*/ */
public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
private static final Logger LOGGER = LogManagerCompat.getLogger();
//FAWE start //FAWE start
private final Map<String, Object> meta; private final Map<String, Object> meta;
private final StampedLock clipboardLoading = new StampedLock();
// Queue for async tasks // Queue for async tasks
private final AtomicInteger runningCount = new AtomicInteger(); private final AtomicInteger runningCount = new AtomicInteger();
@ -93,7 +104,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
if (fe != null) { if (fe != null) {
printError(fe.getComponent()); printError(fe.getComponent());
} else { } else {
throwable.printStackTrace(); LOGGER.error("Error in asyncNotifyQueue", throwable);
} }
} }
}, this::getUniqueId); }, this::getUniqueId);
@ -520,22 +531,71 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override @Override
public void setSelection(Region region) { public void setSelection(Region region) {
RegionSelector selector; RegionSelector selector = switch (region) {
if (region instanceof ConvexPolyhedralRegion) { case ConvexPolyhedralRegion blockVector3s -> new ConvexPolyhedralRegionSelector(blockVector3s);
selector = new ConvexPolyhedralRegionSelector((ConvexPolyhedralRegion) region); case CylinderRegion blockVector3s -> new CylinderRegionSelector(blockVector3s);
} else if (region instanceof CylinderRegion) { case Polygonal2DRegion blockVector3s -> new Polygonal2DRegionSelector(blockVector3s);
selector = new CylinderRegionSelector((CylinderRegion) region); default -> new CuboidRegionSelector(null, region.getMinimumPoint(), region.getMaximumPoint());
} else if (region instanceof Polygonal2DRegion) { };
selector = new Polygonal2DRegionSelector((Polygonal2DRegion) region);
} else {
selector = new CuboidRegionSelector(null, region.getMinimumPoint(),
region.getMaximumPoint()
);
}
selector.setWorld(region.getWorld()); selector.setWorld(region.getWorld());
getSession().setRegionSelector(getWorld(), selector); getSession().setRegionSelector(getWorld(), selector);
} }
@Override
public void loadClipboardFromDisk() {
if (clipboardLoading.isWriteLocked()) {
if (!Fawe.isMainThread()) {
long stamp = clipboardLoading.writeLock();
clipboardLoading.unlockWrite(stamp);
}
return;
}
final long stamp = clipboardLoading.writeLock();
File file = MainUtil.getFile(
Fawe.platform().getDirectory(),
Settings.settings().PATHS.CLIPBOARD + File.separator + getUniqueId() + ".bd"
);
Future<?> fut = Fawe.instance().submitUUIDKeyQueuedTask(getUniqueId(), () -> {
try {
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 form 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 form 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.unlockWrite(stamp);
}
});
if (Fawe.isMainThread()) {
return;
}
try {
fut.get();
} catch (Exception e) {
print(Caption.of("fawe.error.clipboard.invalid"));
LOGGER.error("Error loading clipboard form 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"));
}
}
//FAWE end //FAWE end
@Override @Override
@ -694,10 +754,9 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (!(other instanceof Player)) { if (!(other instanceof Player other2)) {
return false; return false;
} }
Player other2 = (Player) other;
return other2.getName().equals(getName()); return other2.getName().equals(getName());
} }