From 863952b1204b349f63ac89ac0e6185aa8f3b5805 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 3 Feb 2023 12:31:51 +0100 Subject: [PATCH 01/10] Added periodic task (but unfinished), have to rework a bit AsyncTasks (add a scheduler to add cancellability) --- Database/build.gradle | 14 +----- Tasks/build.gradle | 36 ++++++++++++-- .../altarik/toolbox/task/AltarikRunnable.java | 18 +++++++ .../altarik/toolbox/task/PeriodicTaskI.java | 14 ++++++ .../java/fr/altarik/toolbox/task/Task.java | 18 +++++++ .../java/fr/altarik/toolbox/task/TaskI.java | 7 +++ .../asyncTasks}/AsyncTasks.java | 17 ++++--- .../task/syncTasks/PeriodicSyncTask.java | 47 +++++++++++++++++++ .../task/syncTasks/ServerTickListener.java | 19 ++++++++ Tasks/src/main/resources/Task.mixins.json | 15 ++++++ Tasks/src/main/resources/fabric.mod.json | 34 ++++++++++++++ .../fr/altarik/toolbox/AsyncTaskTest.java | 15 ++++-- build.gradle | 7 +++ gradle.properties | 8 ++++ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 11 +++++ 16 files changed, 253 insertions(+), 29 deletions(-) create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/Task.java create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java rename Tasks/src/main/java/fr/altarik/toolbox/{asynctasks => task/asyncTasks}/AsyncTasks.java (84%) create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/ServerTickListener.java create mode 100644 Tasks/src/main/resources/Task.mixins.json create mode 100644 Tasks/src/main/resources/fabric.mod.json diff --git a/Database/build.gradle b/Database/build.gradle index 03d3323..27285c6 100644 --- a/Database/build.gradle +++ b/Database/build.gradle @@ -1,18 +1,8 @@ -plugins { - id 'java' - id 'maven-publish' -} - dependencies { implementation 'org.postgresql:postgresql:42.5.0' testImplementation 'com.google.code.gson:gson:2.10' - testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.0" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.0" -} - -java { - withSourcesJar() - withJavadocJar() + testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}" } test { diff --git a/Tasks/build.gradle b/Tasks/build.gradle index a94536e..adcbbf1 100644 --- a/Tasks/build.gradle +++ b/Tasks/build.gradle @@ -1,18 +1,44 @@ plugins { - id 'java' - id 'maven-publish' + id 'fabric-loom' version '1.0-SNAPSHOT' + } dependencies { + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}" } -java { - withSourcesJar() - withJavadocJar() +processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } } +tasks.withType(JavaCompile).configureEach { + // ensure that the encoding is set to UTF-8, no matter what the system default is + // this fixes some edge cases with special characters not displaying correctly + // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html + // If Javadoc is generated, this must be specified in that task too. + it.options.encoding = "UTF-8" + + // The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too + // JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used. + // We'll use that if it's available, but otherwise we'll use the older option. + def targetVersion = 17 + if (JavaVersion.current().isJava9Compatible()) { + it.options.release = targetVersion + } +} + + test { useJUnitPlatform() } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java b/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java new file mode 100644 index 0000000..8941675 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java @@ -0,0 +1,18 @@ +package fr.altarik.toolbox.task; + +public abstract class AltarikRunnable implements Runnable { + + private boolean isCancelled = false; + + /** + * Warning: Some task cannot be cancelled (mostly async tasks like {@link fr.altarik.toolbox.task.asyncTasks.AsyncTasks} + * The result of this call is ignored in this case, you can still add a way to not execute its content (like if(isCancelled) return;) + */ + public void cancel() { + this.isCancelled = true; + } + + public boolean isCancelled() { + return isCancelled; + } +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java new file mode 100644 index 0000000..67ece7d --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java @@ -0,0 +1,14 @@ +package fr.altarik.toolbox.task; + +public interface PeriodicTaskI extends TaskI { + + /** + * Run a task periodically + * @param function the function to execute + * @param delay delay before starting the task + * @param period time to wait between runs + * @throws InterruptedException When executed asynchronously, task may be interrupted + * @see fr.altarik.toolbox.task.syncTasks.PeriodicSyncTask + */ + public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException; +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java b/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java new file mode 100644 index 0000000..f0a0ff4 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java @@ -0,0 +1,18 @@ +package fr.altarik.toolbox.task; + +import fr.altarik.toolbox.task.asyncTasks.AsyncTasks; +import net.fabricmc.api.ModInitializer; + +public class Task implements ModInitializer { + + public TaskI asyncWorkers = AsyncTasks.initialize(); + + @Override + public void onInitialize() { + + } + + public TaskI getAsyncWorkers() { + return asyncWorkers; + } +} \ No newline at end of file diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java new file mode 100644 index 0000000..8a45bec --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java @@ -0,0 +1,7 @@ +package fr.altarik.toolbox.task; + +public interface TaskI extends AutoCloseable { + + public void addTask(AltarikRunnable function) throws InterruptedException; + +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/asynctasks/AsyncTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java similarity index 84% rename from Tasks/src/main/java/fr/altarik/toolbox/asynctasks/AsyncTasks.java rename to Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java index 0372b01..e99a9e2 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/asynctasks/AsyncTasks.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java @@ -1,4 +1,7 @@ -package fr.altarik.toolbox.asynctasks; +package fr.altarik.toolbox.task.asyncTasks; + +import fr.altarik.toolbox.task.AltarikRunnable; +import fr.altarik.toolbox.task.TaskI; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -7,7 +10,7 @@ import java.util.concurrent.TimeUnit; /** * A non-blocking small sized time-consuming tasks to executed asynchronously. */ -public class AsyncTasks implements AutoCloseable { +public class AsyncTasks implements TaskI { private final ExecutorService worker; @@ -27,11 +30,11 @@ public class AsyncTasks implements AutoCloseable { * * @return an instance of AsyncTasks */ - public static AsyncTasks initialize(int numberOfWorker) { + public static TaskI initialize(int numberOfWorker) { return new AsyncTasks(numberOfWorker); } - public static AsyncTasks initialize() { + public static TaskI initialize() { return initialize(Runtime.getRuntime().availableProcessors()); } @@ -65,7 +68,7 @@ public class AsyncTasks implements AutoCloseable { * @param function task to be executed * @throws InterruptedException when worker thread or BlockQueue has been interrupted while waiting (which is anormal) */ - public void addTask(Runnable function) throws InterruptedException { + public void addTask(AltarikRunnable function) throws InterruptedException { if(worker.isTerminated() || worker.isShutdown()) { throw new InterruptedException("Worker has been terminated or shutdown, it's impossible to add new task"); } @@ -75,9 +78,11 @@ public class AsyncTasks implements AutoCloseable { /** * This method is call when you want to close workers and wait for waiting tasks to finish * + * @throws UnfinishedTasksException when all tasks cannot be terminated in 10 seconds + * @throws InterruptedException if interrupted while waiting for tasks to finish */ @Override - public void close() throws Exception { + public void close() throws UnfinishedTasksException, InterruptedException { worker.shutdown(); boolean result = worker.awaitTermination(10, TimeUnit.SECONDS); if(!result) { diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java new file mode 100644 index 0000000..9da0aa5 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java @@ -0,0 +1,47 @@ +package fr.altarik.toolbox.task.syncTasks; + +import fr.altarik.toolbox.task.AltarikRunnable; +import fr.altarik.toolbox.task.TaskI; + +import java.util.ArrayList; +import java.util.List; + +public class PeriodicSyncTask implements TaskI, Runnable { + + private ServerTickListener listener; + private List tasks; + + private PeriodicSyncTask() { + this.listener = new ServerTickListener(this); + this.tasks = new ArrayList<>(2); + } + + + public static TaskI initialize() { + return new PeriodicSyncTask(); + } + + @Override + public void addTask(AltarikRunnable function) throws InterruptedException { + tasks.add(function); + } + + @Override + public void close() throws Exception { + + } + + @Override + public void run() { + List removeList = new ArrayList<>(tasks.size()); + for(AltarikRunnable task : tasks) { + if(task.isCancelled()) { + removeList.add(task); + } else { + + task.run(); + } + } + tasks.removeAll(removeList); + } +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/ServerTickListener.java b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/ServerTickListener.java new file mode 100644 index 0000000..663114f --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/ServerTickListener.java @@ -0,0 +1,19 @@ +package fr.altarik.toolbox.task.syncTasks; + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.server.MinecraftServer; + +public class ServerTickListener { + + private final PeriodicSyncTask task; + + public ServerTickListener(PeriodicSyncTask syncTask) { + this.task = syncTask; + ServerTickEvents.START_SERVER_TICK.register(this::onServerTick); + } + + private void onServerTick(MinecraftServer minecraftServer) { + + } + +} diff --git a/Tasks/src/main/resources/Task.mixins.json b/Tasks/src/main/resources/Task.mixins.json new file mode 100644 index 0000000..b9c35e9 --- /dev/null +++ b/Tasks/src/main/resources/Task.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "fr.altarik.toolbox.task.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + ], + "client": [ + ], + "verbose": false, + "injectors": { + "defaultRequire": 1 + } + } + \ No newline at end of file diff --git a/Tasks/src/main/resources/fabric.mod.json b/Tasks/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..8f15e03 --- /dev/null +++ b/Tasks/src/main/resources/fabric.mod.json @@ -0,0 +1,34 @@ +{ + "schemaVersion": 1, + "id": "task", + "version": "${version}", + "name": "Task", + "description": "A mod to use as a dependency for others to schedule tasks", + "authors": [ + "Altarik" + ], + "contributors": [ + "Legot Quentin" + ], + "contact": { + "homepage": "https://altarik.fr" + }, + "license": "Altarik @ All-Rights-Reserved ", + "icon": "assets/quests/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "fr.altarik.toolbox.task.Task" + ] + }, + "mixins": [ + "Task.mixins.json" + ], + "depends": { + "fabricloader": ">=0.14.12", + "fabric": "*", + "minecraft": "1.19.3", + "npcs": "2.0.1-SNAPSHOT" + } + } + \ No newline at end of file diff --git a/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java index 6c73178..6dd8593 100644 --- a/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java +++ b/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java @@ -1,6 +1,8 @@ package fr.altarik.toolbox; -import fr.altarik.toolbox.asynctasks.AsyncTasks; +import fr.altarik.toolbox.task.AltarikRunnable; +import fr.altarik.toolbox.task.TaskI; +import fr.altarik.toolbox.task.asyncTasks.AsyncTasks; import org.junit.jupiter.api.Test; import java.util.Date; @@ -19,14 +21,17 @@ class AsyncTaskTest { void testAsyncOp() throws Exception { int numberOfTasks = 10000; System.out.println("Initializing async tasks worker"); - AsyncTasks worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want + TaskI worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want Stack results = new Stack<>(); for(int i = 0; i < numberOfTasks; i++) { System.out.println(log("sending task " + i)); AtomicInteger atomicInteger = new AtomicInteger(i); - worker.addTask(() -> { - System.out.println(log(" task " + atomicInteger.get())); - results.push(atomicInteger.get()); + worker.addTask(new AltarikRunnable() { + @Override + public void run() { + System.out.println(log(" task " + atomicInteger.get())); + results.push(atomicInteger.get()); + } }); } worker.close(); // wait until all worker terminated diff --git a/build.gradle b/build.gradle index 0eee5ab..f860cd0 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,13 @@ subprojects { } } + + java { + withSourcesJar() + withJavadocJar() + } + + repositories { maven { name 'altarik-snapshots' diff --git a/gradle.properties b/gradle.properties index 903ef89..335d1ed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,12 @@ +org.gradle.jvmargs=-Xmx5G + + junit_version=5.9.0 +minecraft_version=1.19.3 +yarn_mappings=1.19.3+build.5 +loader_version=0.14.12 +fabric_version=0.70.0+1.19.3 + maven_group=fr.altarik.toolbox maven_version=2.0.0-SNAPSHOT repo_username=Altarik diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb87..070cb70 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle index b871795..ea6151c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,13 @@ +pluginManagement { + repositories { + mavenCentral() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + gradlePluginPortal() + } +} + rootProject.name = 'Toolbox' include(':Tasks', ':Database') From b1ee9344b8d0b7a98989ddf3ff1037400f6d933f Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 3 Feb 2023 17:51:16 +0100 Subject: [PATCH 02/10] Added AsyncPeriodicTasks, improved a bit PeriodicSyncTask (still a bit of work to do) Signed-off-by: Quentin Legot --- .../fr/altarik/toolbox/task/AsyncTaskI.java | 4 + .../java/fr/altarik/toolbox/task/TaskI.java | 2 +- .../altarik/toolbox/task/TaskScheduler.java | 56 +++++++++++++ .../task/asyncTasks/AsyncPeriodicTasks.java | 83 +++++++++++++++++++ .../toolbox/task/asyncTasks/AsyncTasks.java | 4 +- .../task/syncTasks/PeriodicSyncTask.java | 13 +-- .../task/syncTasks/SchedulerTaskData.java | 39 +++++++++ 7 files changed, 192 insertions(+), 9 deletions(-) create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/AsyncTaskI.java create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/TaskScheduler.java create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncPeriodicTasks.java create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/SchedulerTaskData.java diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/AsyncTaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/AsyncTaskI.java new file mode 100644 index 0000000..c5b771d --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/AsyncTaskI.java @@ -0,0 +1,4 @@ +package fr.altarik.toolbox.task; + +public interface AsyncTaskI extends TaskI, AutoCloseable { +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java index 8a45bec..a98753c 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java @@ -1,6 +1,6 @@ package fr.altarik.toolbox.task; -public interface TaskI extends AutoCloseable { +public interface TaskI { public void addTask(AltarikRunnable function) throws InterruptedException; diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskScheduler.java b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskScheduler.java new file mode 100644 index 0000000..f990081 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskScheduler.java @@ -0,0 +1,56 @@ +package fr.altarik.toolbox.task; + +import fr.altarik.toolbox.task.syncTasks.SchedulerTaskData; + +import java.util.Vector; + +public class TaskScheduler { + private Vector asyncTasks; + private boolean stop = false; + + + public synchronized void sendAsyncTask(AltarikRunnable function, long delay, long period) throws InterruptedException { + asyncTasks.addElement(new SchedulerTaskData(function, delay, period)); + notify(); + } + + /** + * Function executed in asynchronous workers with periodic tasks + */ + public synchronized void asyncRunnerPeriodicTasks() throws InterruptedException { + loop: while(true) { + notify(); + while(asyncTasks.size() == 0) { + if(isStop()) { + break loop; + } + wait(); + } + SchedulerTaskData data = asyncTasks.firstElement(); + asyncTasks.remove(data); + if(!data.getFunction().isCancelled()) { + long currentDelay = data.getCurrentDelay(); + if(currentDelay != 0) { + data.setCurrentDelay(currentDelay - 1); + asyncTasks.addElement(data); + } else { + data.getFunction().run(); + data.setCurrentDelay(data.getPeriod()); + asyncTasks.addElement(data); + } + } + } + } + + public synchronized boolean isStop() { + return stop; + } + + public synchronized void setStop(boolean stop) { + this.stop = stop; + } + + public int getNumberOfTasks() { + return asyncTasks.size(); + } +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncPeriodicTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncPeriodicTasks.java new file mode 100644 index 0000000..de31e44 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncPeriodicTasks.java @@ -0,0 +1,83 @@ +package fr.altarik.toolbox.task.asyncTasks; + +import fr.altarik.toolbox.task.*; +import it.unimi.dsi.fastutil.ints.IntComparators; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI { + + private final ExecutorService worker; + private final List schedulers; + + private AsyncPeriodicTasks(int numberOfWorker) { + int size = 0; + if(numberOfWorker == 1) { + worker = Executors.newSingleThreadExecutor(); + size = 1; + } else if (numberOfWorker <= 0) { + worker = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + size = Runtime.getRuntime().availableProcessors(); + } else { + worker = Executors.newFixedThreadPool(numberOfWorker); + size = numberOfWorker; + } + this.schedulers = new ArrayList<>(size); + for(int i = 0; i < size; i++) { + TaskScheduler scheduler = new TaskScheduler(); + schedulers.add(scheduler); + worker.submit(() -> { + try { + scheduler.asyncRunnerPeriodicTasks(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + } + } + + /** + * Call this method at startup or before first use of {@link AsyncTasks#addTask(AltarikRunnable)}, cause without it, nothing will work + * This method declare worker thread and start it, without call it, by calling addTask(Runnable), it'll add your task to Queue, but tasks will never be consumed. + * + * @return an instance of AsyncTasks + */ + public static TaskI initialize(int numberOfWorker) { + return new AsyncPeriodicTasks(numberOfWorker); + } + + public static TaskI initialize() { + return initialize(Runtime.getRuntime().availableProcessors()); + } + + @Override + public void addTask(AltarikRunnable function) throws InterruptedException { + this.addTask(function, 0, 1); + } + + @Override + public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException { + if(worker.isTerminated() || worker.isShutdown()) { + throw new InterruptedException("Worker has been terminated or shutdown, it's impossible to add new task"); + } + schedulers.stream() + .min((o1, o2) -> IntComparators.NATURAL_COMPARATOR.compare(o1.getNumberOfTasks(), o2.getNumberOfTasks())) + .orElseThrow() + .sendAsyncTask(function, delay, period); + } + + @Override + public void close() throws Exception { + schedulers.forEach(s -> s.setStop(true)); + worker.shutdown(); + boolean result = worker.awaitTermination(10, TimeUnit.SECONDS); + if(!result) { + worker.shutdownNow(); + throw new AsyncTasks.UnfinishedTasksException("Tasks take too many time to finish, shutdown has been enforce"); + } + } +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java index e99a9e2..50fcc43 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java @@ -18,14 +18,14 @@ public class AsyncTasks implements TaskI { if(numberOfWorker == 1) { worker = Executors.newSingleThreadExecutor(); } else if (numberOfWorker <= 0) { - worker = Executors.newCachedThreadPool(); + worker = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); } else { worker = Executors.newFixedThreadPool(numberOfWorker); } } /** - * Call this method at startup or before first use of {@link AsyncTasks#addTask(Runnable)}, cause without it, nothing will work + * Call this method at startup or before first use of {@link AsyncTasks#addTask(AltarikRunnable)}, cause without it, nothing will work * This method declare worker thread and start it, without call it, by calling addTask(Runnable), it'll add your task to Queue, but tasks will never be consumed. * * @return an instance of AsyncTasks diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java index 9da0aa5..0c15f4e 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java @@ -1,12 +1,13 @@ package fr.altarik.toolbox.task.syncTasks; import fr.altarik.toolbox.task.AltarikRunnable; +import fr.altarik.toolbox.task.PeriodicTaskI; import fr.altarik.toolbox.task.TaskI; import java.util.ArrayList; import java.util.List; -public class PeriodicSyncTask implements TaskI, Runnable { +public class PeriodicSyncTask implements PeriodicTaskI, Runnable { private ServerTickListener listener; private List tasks; @@ -26,11 +27,6 @@ public class PeriodicSyncTask implements TaskI, Runnable { tasks.add(function); } - @Override - public void close() throws Exception { - - } - @Override public void run() { List removeList = new ArrayList<>(tasks.size()); @@ -44,4 +40,9 @@ public class PeriodicSyncTask implements TaskI, Runnable { } tasks.removeAll(removeList); } + + @Override + public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException { + + } } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/SchedulerTaskData.java b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/SchedulerTaskData.java new file mode 100644 index 0000000..2eb5ee8 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/SchedulerTaskData.java @@ -0,0 +1,39 @@ +package fr.altarik.toolbox.task.syncTasks; + +import fr.altarik.toolbox.task.AltarikRunnable; + +public class SchedulerTaskData { + + private final long delay; + private final long period; + private final AltarikRunnable function; + + private long currentDelay; + + public SchedulerTaskData(AltarikRunnable function, long delay, long period) { + this.function = function; + this.delay = delay; + this.period = period; + this.currentDelay = delay; + } + + public AltarikRunnable getFunction() { + return function; + } + + public long getCurrentDelay() { + return currentDelay; + } + + public void setCurrentDelay(long currentDelay) { + this.currentDelay = currentDelay; + } + + public long getDelay() { + return delay; + } + + public long getPeriod() { + return period; + } +} From e7178d44a9c868cdb3a542067fdf1fd6090c81d6 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 3 Feb 2023 23:40:01 +0100 Subject: [PATCH 03/10] PeriodicSyncTask and AsyncPeriodicTasks should work now (untested) Signed-off-by: Quentin Legot --- .../altarik/toolbox/task/AltarikRunnable.java | 2 +- .../fr/altarik/toolbox/task/AsyncTaskI.java | 4 -- .../altarik/toolbox/task/PeriodicTaskI.java | 2 +- .../{syncTasks => }/SchedulerTaskData.java | 22 ++++++- .../java/fr/altarik/toolbox/task/Task.java | 2 +- .../AsyncPeriodicTasks.java | 8 ++- .../toolbox/task/async/AsyncTaskI.java | 6 ++ .../{asyncTasks => async}/AsyncTasks.java | 2 +- .../task/{ => async}/TaskScheduler.java | 26 ++++++--- .../toolbox/task/sync/PeriodicSyncTask.java | 57 +++++++++++++++++++ .../ServerTickListener.java | 4 +- .../task/syncTasks/PeriodicSyncTask.java | 48 ---------------- .../fr/altarik/toolbox/AsyncTaskTest.java | 2 +- 13 files changed, 113 insertions(+), 72 deletions(-) delete mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/AsyncTaskI.java rename Tasks/src/main/java/fr/altarik/toolbox/task/{syncTasks => }/SchedulerTaskData.java (52%) rename Tasks/src/main/java/fr/altarik/toolbox/task/{asyncTasks => async}/AsyncPeriodicTasks.java (93%) create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTaskI.java rename Tasks/src/main/java/fr/altarik/toolbox/task/{asyncTasks => async}/AsyncTasks.java (98%) rename Tasks/src/main/java/fr/altarik/toolbox/task/{ => async}/TaskScheduler.java (57%) create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java rename Tasks/src/main/java/fr/altarik/toolbox/task/{syncTasks => sync}/ServerTickListener.java (88%) delete mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java b/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java index 8941675..bdc3470 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java @@ -5,7 +5,7 @@ public abstract class AltarikRunnable implements Runnable { private boolean isCancelled = false; /** - * Warning: Some task cannot be cancelled (mostly async tasks like {@link fr.altarik.toolbox.task.asyncTasks.AsyncTasks} + * Warning: Some task cannot be cancelled (mostly async tasks like {@link fr.altarik.toolbox.task.async.AsyncTasks} * The result of this call is ignored in this case, you can still add a way to not execute its content (like if(isCancelled) return;) */ public void cancel() { diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/AsyncTaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/AsyncTaskI.java deleted file mode 100644 index c5b771d..0000000 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/AsyncTaskI.java +++ /dev/null @@ -1,4 +0,0 @@ -package fr.altarik.toolbox.task; - -public interface AsyncTaskI extends TaskI, AutoCloseable { -} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java index 67ece7d..2a7cd48 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java @@ -8,7 +8,7 @@ public interface PeriodicTaskI extends TaskI { * @param delay delay before starting the task * @param period time to wait between runs * @throws InterruptedException When executed asynchronously, task may be interrupted - * @see fr.altarik.toolbox.task.syncTasks.PeriodicSyncTask + * @see fr.altarik.toolbox.task.sync.PeriodicSyncTask */ public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException; } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/SchedulerTaskData.java b/Tasks/src/main/java/fr/altarik/toolbox/task/SchedulerTaskData.java similarity index 52% rename from Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/SchedulerTaskData.java rename to Tasks/src/main/java/fr/altarik/toolbox/task/SchedulerTaskData.java index 2eb5ee8..7a11f15 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/SchedulerTaskData.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/SchedulerTaskData.java @@ -1,15 +1,29 @@ -package fr.altarik.toolbox.task.syncTasks; - -import fr.altarik.toolbox.task.AltarikRunnable; +package fr.altarik.toolbox.task; public class SchedulerTaskData { + /** + * Delay before executing the function for the first time + * Correspond to tick in synchronous context and milliseconds in asynchronous context + */ private final long delay; + /** + * Period of time before re-executing the function + * Correspond to tick in synchronous context and milliseconds in asynchronous context + */ private final long period; private final AltarikRunnable function; private long currentDelay; + /** + * + * Delay and Period times corresponds to tick in synchronous context and milliseconds in asynchronous context + * + * @param function instructions to execute + * @param delay Delay before executing the function for the first time + * @param period Period of time before re-executing the function + */ public SchedulerTaskData(AltarikRunnable function, long delay, long period) { this.function = function; this.delay = delay; @@ -36,4 +50,6 @@ public class SchedulerTaskData { public long getPeriod() { return period; } + + } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java b/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java index f0a0ff4..b88d067 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java @@ -1,6 +1,6 @@ package fr.altarik.toolbox.task; -import fr.altarik.toolbox.task.asyncTasks.AsyncTasks; +import fr.altarik.toolbox.task.async.AsyncTasks; import net.fabricmc.api.ModInitializer; public class Task implements ModInitializer { diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncPeriodicTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java similarity index 93% rename from Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncPeriodicTasks.java rename to Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java index de31e44..46262b1 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncPeriodicTasks.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java @@ -1,6 +1,8 @@ -package fr.altarik.toolbox.task.asyncTasks; +package fr.altarik.toolbox.task.async; -import fr.altarik.toolbox.task.*; +import fr.altarik.toolbox.task.AltarikRunnable; +import fr.altarik.toolbox.task.PeriodicTaskI; +import fr.altarik.toolbox.task.TaskI; import it.unimi.dsi.fastutil.ints.IntComparators; import java.util.ArrayList; @@ -56,7 +58,7 @@ public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI { @Override public void addTask(AltarikRunnable function) throws InterruptedException { - this.addTask(function, 0, 1); + this.addTask(function, 0, 1000); } @Override diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTaskI.java new file mode 100644 index 0000000..5084971 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTaskI.java @@ -0,0 +1,6 @@ +package fr.altarik.toolbox.task.async; + +import fr.altarik.toolbox.task.TaskI; + +public interface AsyncTaskI extends TaskI, AutoCloseable { +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTasks.java similarity index 98% rename from Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java rename to Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTasks.java index 50fcc43..29efd5c 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/asyncTasks/AsyncTasks.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTasks.java @@ -1,4 +1,4 @@ -package fr.altarik.toolbox.task.asyncTasks; +package fr.altarik.toolbox.task.async; import fr.altarik.toolbox.task.AltarikRunnable; import fr.altarik.toolbox.task.TaskI; diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskScheduler.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java similarity index 57% rename from Tasks/src/main/java/fr/altarik/toolbox/task/TaskScheduler.java rename to Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java index f990081..04358ae 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskScheduler.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java @@ -1,16 +1,27 @@ -package fr.altarik.toolbox.task; +package fr.altarik.toolbox.task.async; -import fr.altarik.toolbox.task.syncTasks.SchedulerTaskData; +import fr.altarik.toolbox.task.AltarikRunnable; +import fr.altarik.toolbox.task.SchedulerTaskData; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.HashMap; import java.util.Vector; public class TaskScheduler { private Vector asyncTasks; + + /** + * Return last time the method was executed, Value initialized to now when using sending the task to scheduler + */ + private HashMap lastTimeExecution; private boolean stop = false; public synchronized void sendAsyncTask(AltarikRunnable function, long delay, long period) throws InterruptedException { - asyncTasks.addElement(new SchedulerTaskData(function, delay, period)); + SchedulerTaskData data = new SchedulerTaskData(function, delay, period); + asyncTasks.addElement(data); + lastTimeExecution.put(new SchedulerTaskData(function, delay, period), Instant.now()); notify(); } @@ -30,12 +41,13 @@ public class TaskScheduler { asyncTasks.remove(data); if(!data.getFunction().isCancelled()) { long currentDelay = data.getCurrentDelay(); - if(currentDelay != 0) { - data.setCurrentDelay(currentDelay - 1); - asyncTasks.addElement(data); - } else { + Instant currentTime = Instant.now(); + Instant lastExecution = lastTimeExecution.get(data); + // (lastExec + delay) - currentTime + if(lastExecution.plus(currentDelay, ChronoUnit.MILLIS).isBefore(currentTime)) { data.getFunction().run(); data.setCurrentDelay(data.getPeriod()); + lastTimeExecution.put(data, Instant.now()); asyncTasks.addElement(data); } } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java new file mode 100644 index 0000000..c5cee4e --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java @@ -0,0 +1,57 @@ +package fr.altarik.toolbox.task.sync; + +import fr.altarik.toolbox.task.AltarikRunnable; +import fr.altarik.toolbox.task.PeriodicTaskI; +import fr.altarik.toolbox.task.SchedulerTaskData; +import fr.altarik.toolbox.task.TaskI; + +import java.util.ArrayList; +import java.util.List; + +public class PeriodicSyncTask implements PeriodicTaskI, Runnable { + + private ServerTickListener listener; + private List tasks; + + private PeriodicSyncTask() { + this.listener = new ServerTickListener(this); + this.tasks = new ArrayList<>(2); + } + + + public static TaskI initialize() { + return new PeriodicSyncTask(); + } + + @Override + public void addTask(AltarikRunnable function) throws InterruptedException { + addTask(function, 0, 1); + } + + @Override + public void run() { + List removeList = new ArrayList<>(tasks.size()); + for(SchedulerTaskData data : tasks) { + if(!data.getFunction().isCancelled()) { + long currentDelay = data.getCurrentDelay(); + if(currentDelay != 0) { + data.setCurrentDelay(currentDelay - 1); + } else { + data.getFunction().run(); + data.setCurrentDelay(data.getPeriod()); + } + } else { + removeList.add(data); + } + } + for(SchedulerTaskData toRemove : removeList) { + tasks.remove(toRemove); + } + + } + + @Override + public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException { + tasks.add(new SchedulerTaskData(function, delay, period)); + } +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/ServerTickListener.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java similarity index 88% rename from Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/ServerTickListener.java rename to Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java index 663114f..a1ae23c 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/ServerTickListener.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java @@ -1,4 +1,4 @@ -package fr.altarik.toolbox.task.syncTasks; +package fr.altarik.toolbox.task.sync; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.minecraft.server.MinecraftServer; @@ -13,7 +13,7 @@ public class ServerTickListener { } private void onServerTick(MinecraftServer minecraftServer) { - + task.run(); } } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java deleted file mode 100644 index 0c15f4e..0000000 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/syncTasks/PeriodicSyncTask.java +++ /dev/null @@ -1,48 +0,0 @@ -package fr.altarik.toolbox.task.syncTasks; - -import fr.altarik.toolbox.task.AltarikRunnable; -import fr.altarik.toolbox.task.PeriodicTaskI; -import fr.altarik.toolbox.task.TaskI; - -import java.util.ArrayList; -import java.util.List; - -public class PeriodicSyncTask implements PeriodicTaskI, Runnable { - - private ServerTickListener listener; - private List tasks; - - private PeriodicSyncTask() { - this.listener = new ServerTickListener(this); - this.tasks = new ArrayList<>(2); - } - - - public static TaskI initialize() { - return new PeriodicSyncTask(); - } - - @Override - public void addTask(AltarikRunnable function) throws InterruptedException { - tasks.add(function); - } - - @Override - public void run() { - List removeList = new ArrayList<>(tasks.size()); - for(AltarikRunnable task : tasks) { - if(task.isCancelled()) { - removeList.add(task); - } else { - - task.run(); - } - } - tasks.removeAll(removeList); - } - - @Override - public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException { - - } -} diff --git a/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java index 6dd8593..e6169e1 100644 --- a/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java +++ b/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java @@ -2,7 +2,7 @@ package fr.altarik.toolbox; import fr.altarik.toolbox.task.AltarikRunnable; import fr.altarik.toolbox.task.TaskI; -import fr.altarik.toolbox.task.asyncTasks.AsyncTasks; +import fr.altarik.toolbox.task.async.AsyncTasks; import org.junit.jupiter.api.Test; import java.util.Date; From e9c97df08948ddc20e347f874c7067451a92024c Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 3 Feb 2023 23:52:50 +0100 Subject: [PATCH 04/10] Fix issue avoiding the mod not to compile, add a test for asyncTasks (still need to be implemented) Signed-off-by: Quentin Legot --- .../java/fr/altarik/toolbox/task/async/AsyncTasks.java | 7 +++---- .../java/fr/altarik/toolbox/{ => task}/AsyncTaskTest.java | 8 +++----- .../test/java/fr/altarik/toolbox/task/SyncTaskTest.java | 7 +++++++ 3 files changed, 13 insertions(+), 9 deletions(-) rename Tasks/src/test/java/fr/altarik/toolbox/{ => task}/AsyncTaskTest.java (82%) create mode 100644 Tasks/src/test/java/fr/altarik/toolbox/task/SyncTaskTest.java diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTasks.java index 29efd5c..8caed53 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTasks.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncTasks.java @@ -1,7 +1,6 @@ package fr.altarik.toolbox.task.async; import fr.altarik.toolbox.task.AltarikRunnable; -import fr.altarik.toolbox.task.TaskI; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -10,7 +9,7 @@ import java.util.concurrent.TimeUnit; /** * A non-blocking small sized time-consuming tasks to executed asynchronously. */ -public class AsyncTasks implements TaskI { +public class AsyncTasks implements AsyncTaskI { private final ExecutorService worker; @@ -30,11 +29,11 @@ public class AsyncTasks implements TaskI { * * @return an instance of AsyncTasks */ - public static TaskI initialize(int numberOfWorker) { + public static AsyncTaskI initialize(int numberOfWorker) { return new AsyncTasks(numberOfWorker); } - public static TaskI initialize() { + public static AsyncTaskI initialize() { return initialize(Runtime.getRuntime().availableProcessors()); } diff --git a/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/AsyncTaskTest.java similarity index 82% rename from Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java rename to Tasks/src/test/java/fr/altarik/toolbox/task/AsyncTaskTest.java index e6169e1..c73d2a7 100644 --- a/Tasks/src/test/java/fr/altarik/toolbox/AsyncTaskTest.java +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/AsyncTaskTest.java @@ -1,7 +1,6 @@ -package fr.altarik.toolbox; +package fr.altarik.toolbox.task; -import fr.altarik.toolbox.task.AltarikRunnable; -import fr.altarik.toolbox.task.TaskI; +import fr.altarik.toolbox.task.async.AsyncTaskI; import fr.altarik.toolbox.task.async.AsyncTasks; import org.junit.jupiter.api.Test; @@ -21,7 +20,7 @@ class AsyncTaskTest { void testAsyncOp() throws Exception { int numberOfTasks = 10000; System.out.println("Initializing async tasks worker"); - TaskI worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want + AsyncTaskI worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want Stack results = new Stack<>(); for(int i = 0; i < numberOfTasks; i++) { System.out.println(log("sending task " + i)); @@ -40,6 +39,5 @@ class AsyncTaskTest { expected[i] = i; } assertArrayEquals(expected, results.toArray()); - } } diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/SyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/SyncTaskTest.java new file mode 100644 index 0000000..7095e58 --- /dev/null +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/SyncTaskTest.java @@ -0,0 +1,7 @@ +package fr.altarik.toolbox.task; + +public class SyncTaskTest { + + // TODO: 03/02/2023 Envoyé les tasks au workers grâce à un autre thread. + +} From 9123d71a7e04dc491b6e18f1b76784e5772ff23d Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Sun, 12 Feb 2023 14:24:09 +0100 Subject: [PATCH 05/10] Add tests to PeriodicSyncTask Signed-off-by: Quentin Legot --- .../java/fr/altarik/toolbox/task/TaskI.java | 2 +- .../toolbox/task/sync/PeriodicSyncTask.java | 9 ++-- .../fr/altarik/toolbox/task/SyncTaskTest.java | 7 --- .../task/{ => async}/AsyncTaskTest.java | 11 ++-- .../task/sync/PeriodicSyncTaskTest.java | 52 +++++++++++++++++++ 5 files changed, 62 insertions(+), 19 deletions(-) delete mode 100644 Tasks/src/test/java/fr/altarik/toolbox/task/SyncTaskTest.java rename Tasks/src/test/java/fr/altarik/toolbox/task/{ => async}/AsyncTaskTest.java (78%) create mode 100644 Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java index a98753c..2f668a8 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java @@ -2,6 +2,6 @@ package fr.altarik.toolbox.task; public interface TaskI { - public void addTask(AltarikRunnable function) throws InterruptedException; + void addTask(AltarikRunnable function) throws InterruptedException; } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java index c5cee4e..c4e38f9 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java @@ -3,7 +3,6 @@ package fr.altarik.toolbox.task.sync; import fr.altarik.toolbox.task.AltarikRunnable; import fr.altarik.toolbox.task.PeriodicTaskI; import fr.altarik.toolbox.task.SchedulerTaskData; -import fr.altarik.toolbox.task.TaskI; import java.util.ArrayList; import java.util.List; @@ -19,13 +18,13 @@ public class PeriodicSyncTask implements PeriodicTaskI, Runnable { } - public static TaskI initialize() { + public static PeriodicTaskI initialize() { return new PeriodicSyncTask(); } @Override - public void addTask(AltarikRunnable function) throws InterruptedException { - addTask(function, 0, 1); + public void addTask(AltarikRunnable function) { + addTask(function, 0, 0); } @Override @@ -51,7 +50,7 @@ public class PeriodicSyncTask implements PeriodicTaskI, Runnable { } @Override - public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException { + public void addTask(AltarikRunnable function, long delay, long period) { tasks.add(new SchedulerTaskData(function, delay, period)); } } diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/SyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/SyncTaskTest.java deleted file mode 100644 index 7095e58..0000000 --- a/Tasks/src/test/java/fr/altarik/toolbox/task/SyncTaskTest.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.altarik.toolbox.task; - -public class SyncTaskTest { - - // TODO: 03/02/2023 Envoyé les tasks au workers grâce à un autre thread. - -} diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/AsyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/async/AsyncTaskTest.java similarity index 78% rename from Tasks/src/test/java/fr/altarik/toolbox/task/AsyncTaskTest.java rename to Tasks/src/test/java/fr/altarik/toolbox/task/async/AsyncTaskTest.java index c73d2a7..7e2f876 100644 --- a/Tasks/src/test/java/fr/altarik/toolbox/task/AsyncTaskTest.java +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/async/AsyncTaskTest.java @@ -1,7 +1,6 @@ -package fr.altarik.toolbox.task; +package fr.altarik.toolbox.task.async; -import fr.altarik.toolbox.task.async.AsyncTaskI; -import fr.altarik.toolbox.task.async.AsyncTasks; +import fr.altarik.toolbox.task.AltarikRunnable; import org.junit.jupiter.api.Test; import java.util.Date; @@ -19,16 +18,16 @@ class AsyncTaskTest { @Test void testAsyncOp() throws Exception { int numberOfTasks = 10000; - System.out.println("Initializing async tasks worker"); + // System.out.println("Initializing async tasks worker"); AsyncTaskI worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want Stack results = new Stack<>(); for(int i = 0; i < numberOfTasks; i++) { - System.out.println(log("sending task " + i)); + // System.out.println(log("sending task " + i)); AtomicInteger atomicInteger = new AtomicInteger(i); worker.addTask(new AltarikRunnable() { @Override public void run() { - System.out.println(log(" task " + atomicInteger.get())); + // System.out.println(log(" task " + atomicInteger.get())); results.push(atomicInteger.get()); } }); diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java new file mode 100644 index 0000000..b5d0a90 --- /dev/null +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java @@ -0,0 +1,52 @@ +package fr.altarik.toolbox.task.sync; + +import fr.altarik.toolbox.task.AltarikRunnable; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class PeriodicSyncTaskTest { + + @Test + void testPeriodicSyncTask() { + List results = new ArrayList<>(); + PeriodicSyncTask worker = (PeriodicSyncTask) PeriodicSyncTask.initialize(); + AtomicInteger value1 = new AtomicInteger(1); + AtomicInteger value2 = new AtomicInteger(2); + worker.addTask(new AltarikRunnable() { + + @Override + public void run() { + results.add(value1); + } + }, 1, 2); + worker.addTask(new AltarikRunnable() { + private int i = 0; + @Override + public void run() { + results.add(value2); + if(i++ == 5) + this.cancel(); + } + }); + for(int i = 0; i < 10; i++) { + worker.run(); + } + AtomicInteger[] expected = { + value2, + value1, + value2, + value2, + value2, + value1, + value2, + value2, + value1 + }; + Assertions.assertArrayEquals(expected, results.toArray()); + } + +} From 24656fa74f452a7ef9e7d458e5130153bc0ee4d3 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Sun, 12 Feb 2023 14:51:30 +0100 Subject: [PATCH 06/10] add OneTimeSyncTask and started to implement its test (not finished) Signed-off-by: Quentin Legot --- .../toolbox/task/sync/OneTimeSyncTask.java | 53 +++++++++++++++++++ .../toolbox/task/sync/PeriodicSyncTask.java | 4 +- .../toolbox/task/sync/ServerTickListener.java | 4 +- .../task/sync/OneTimeSyncTaskTest.java | 25 +++++++++ 4 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/sync/OneTimeSyncTask.java create mode 100644 Tasks/src/test/java/fr/altarik/toolbox/task/sync/OneTimeSyncTaskTest.java diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/OneTimeSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/OneTimeSyncTask.java new file mode 100644 index 0000000..0beeda1 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/OneTimeSyncTask.java @@ -0,0 +1,53 @@ +package fr.altarik.toolbox.task.sync; + +import fr.altarik.toolbox.task.AltarikRunnable; +import fr.altarik.toolbox.task.SchedulerTaskData; +import fr.altarik.toolbox.task.TaskI; + +import java.util.ArrayList; +import java.util.List; + +public class OneTimeSyncTask implements TaskI, Runnable { + + private final ServerTickListener listener; + private final List tasks; + + private OneTimeSyncTask() { + this.listener = new ServerTickListener(this); + this.tasks = new ArrayList<>(2); + } + + public static TaskI initialize() { + return new OneTimeSyncTask(); + } + + @Override + public void addTask(AltarikRunnable function) { + addTask(function, 0); + } + + public void addTask(AltarikRunnable function, int delay) { + tasks.add(new SchedulerTaskData(function, delay, 0)); + } + + @Override + public void run() { + List removeList = new ArrayList<>(tasks.size()); + for(SchedulerTaskData data : tasks) { + if(!data.getFunction().isCancelled()) { + long currentDelay = data.getCurrentDelay(); + if(currentDelay != 0) { + data.setCurrentDelay(currentDelay - 1); + } else { + data.getFunction().run(); + removeList.add(data); + } + } else { + removeList.add(data); + } + } + for(SchedulerTaskData toRemove : removeList) { + tasks.remove(toRemove); + } + } +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java index c4e38f9..25d2e10 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java @@ -9,8 +9,8 @@ import java.util.List; public class PeriodicSyncTask implements PeriodicTaskI, Runnable { - private ServerTickListener listener; - private List tasks; + private final ServerTickListener listener; + private final List tasks; private PeriodicSyncTask() { this.listener = new ServerTickListener(this); diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java index a1ae23c..d70562d 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java @@ -5,9 +5,9 @@ import net.minecraft.server.MinecraftServer; public class ServerTickListener { - private final PeriodicSyncTask task; + private final Runnable task; - public ServerTickListener(PeriodicSyncTask syncTask) { + public ServerTickListener(Runnable syncTask) { this.task = syncTask; ServerTickEvents.START_SERVER_TICK.register(this::onServerTick); } diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/OneTimeSyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/OneTimeSyncTaskTest.java new file mode 100644 index 0000000..e9e8a1f --- /dev/null +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/OneTimeSyncTaskTest.java @@ -0,0 +1,25 @@ +package fr.altarik.toolbox.task.sync; + +import fr.altarik.toolbox.task.AltarikRunnable; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class OneTimeSyncTaskTest { + + @Test + void testOneTimeTask() { + OneTimeSyncTask worker = (OneTimeSyncTask) OneTimeSyncTask.initialize(); + List results = new ArrayList<>(); + AtomicInteger value1 = new AtomicInteger(1); + AtomicInteger value2 = new AtomicInteger(2); + worker.addTask(new AltarikRunnable() { + @Override + public void run() { + results.add(value1); + } + }); + } +} From be9f422f1ff059f5ed6c0b2650940c61c16979ec Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Sun, 12 Feb 2023 19:10:24 +0100 Subject: [PATCH 07/10] Made some twerks to tasks, fix task period for PeriodicSyncTask Signed-off-by: Quentin Legot --- .../task/async/AsyncPeriodicTasks.java | 5 +- .../toolbox/task/async/TaskScheduler.java | 1 - .../toolbox/task/sync/PeriodicSyncTask.java | 4 +- .../{OneTimeSyncTask.java => SyncTask.java} | 6 +-- .../task/async/PeriodicAsyncTaskTest.java | 32 ++++++++++++ .../task/sync/OneTimeSyncTaskTest.java | 25 ---------- .../task/sync/PeriodicSyncTaskTest.java | 4 +- .../toolbox/task/sync/SyncTaskTest.java | 49 +++++++++++++++++++ 8 files changed, 90 insertions(+), 36 deletions(-) rename Tasks/src/main/java/fr/altarik/toolbox/task/sync/{OneTimeSyncTask.java => SyncTask.java} (91%) create mode 100644 Tasks/src/test/java/fr/altarik/toolbox/task/async/PeriodicAsyncTaskTest.java delete mode 100644 Tasks/src/test/java/fr/altarik/toolbox/task/sync/OneTimeSyncTaskTest.java create mode 100644 Tasks/src/test/java/fr/altarik/toolbox/task/sync/SyncTaskTest.java diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java index 46262b1..1141751 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java @@ -2,7 +2,6 @@ package fr.altarik.toolbox.task.async; import fr.altarik.toolbox.task.AltarikRunnable; import fr.altarik.toolbox.task.PeriodicTaskI; -import fr.altarik.toolbox.task.TaskI; import it.unimi.dsi.fastutil.ints.IntComparators; import java.util.ArrayList; @@ -48,11 +47,11 @@ public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI { * * @return an instance of AsyncTasks */ - public static TaskI initialize(int numberOfWorker) { + public static PeriodicTaskI initialize(int numberOfWorker) { return new AsyncPeriodicTasks(numberOfWorker); } - public static TaskI initialize() { + public static PeriodicTaskI initialize() { return initialize(Runtime.getRuntime().availableProcessors()); } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java index 04358ae..4bc2e74 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java @@ -30,7 +30,6 @@ public class TaskScheduler { */ public synchronized void asyncRunnerPeriodicTasks() throws InterruptedException { loop: while(true) { - notify(); while(asyncTasks.size() == 0) { if(isStop()) { break loop; diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java index 25d2e10..381c263 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java @@ -24,7 +24,7 @@ public class PeriodicSyncTask implements PeriodicTaskI, Runnable { @Override public void addTask(AltarikRunnable function) { - addTask(function, 0, 0); + addTask(function, 0, 1); } @Override @@ -51,6 +51,6 @@ public class PeriodicSyncTask implements PeriodicTaskI, Runnable { @Override public void addTask(AltarikRunnable function, long delay, long period) { - tasks.add(new SchedulerTaskData(function, delay, period)); + tasks.add(new SchedulerTaskData(function, delay, period - 1)); } } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/OneTimeSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/SyncTask.java similarity index 91% rename from Tasks/src/main/java/fr/altarik/toolbox/task/sync/OneTimeSyncTask.java rename to Tasks/src/main/java/fr/altarik/toolbox/task/sync/SyncTask.java index 0beeda1..749fe0c 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/OneTimeSyncTask.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/SyncTask.java @@ -7,18 +7,18 @@ import fr.altarik.toolbox.task.TaskI; import java.util.ArrayList; import java.util.List; -public class OneTimeSyncTask implements TaskI, Runnable { +public class SyncTask implements TaskI, Runnable { private final ServerTickListener listener; private final List tasks; - private OneTimeSyncTask() { + private SyncTask() { this.listener = new ServerTickListener(this); this.tasks = new ArrayList<>(2); } public static TaskI initialize() { - return new OneTimeSyncTask(); + return new SyncTask(); } @Override diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/async/PeriodicAsyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/async/PeriodicAsyncTaskTest.java new file mode 100644 index 0000000..29e0fe6 --- /dev/null +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/async/PeriodicAsyncTaskTest.java @@ -0,0 +1,32 @@ +package fr.altarik.toolbox.task.async; + +import fr.altarik.toolbox.task.AltarikRunnable; +import org.junit.jupiter.api.Test; + +import java.util.Stack; +import java.util.concurrent.atomic.AtomicInteger; + +public class PeriodicAsyncTaskTest { + + @Test + void testPeriodicASyncTask() { + AsyncPeriodicTasks worker = (AsyncPeriodicTasks) AsyncPeriodicTasks.initialize(); + Stack results = new Stack<>(); + AtomicInteger value1 = new AtomicInteger(1); + AtomicInteger value2 = new AtomicInteger(2); + AltarikRunnable runnable1 = new AltarikRunnable() { + @Override + public void run() { + results.add(value1); + } + }; + AltarikRunnable runnable2 = new AltarikRunnable() { + @Override + public void run() { + results.add(value2); + } + }; + + + } +} diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/OneTimeSyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/OneTimeSyncTaskTest.java deleted file mode 100644 index e9e8a1f..0000000 --- a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/OneTimeSyncTaskTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.altarik.toolbox.task.sync; - -import fr.altarik.toolbox.task.AltarikRunnable; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -public class OneTimeSyncTaskTest { - - @Test - void testOneTimeTask() { - OneTimeSyncTask worker = (OneTimeSyncTask) OneTimeSyncTask.initialize(); - List results = new ArrayList<>(); - AtomicInteger value1 = new AtomicInteger(1); - AtomicInteger value2 = new AtomicInteger(2); - worker.addTask(new AltarikRunnable() { - @Override - public void run() { - results.add(value1); - } - }); - } -} diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java index b5d0a90..2a5565c 100644 --- a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java @@ -8,7 +8,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -public class PeriodicSyncTaskTest { +class PeriodicSyncTaskTest { @Test void testPeriodicSyncTask() { @@ -22,7 +22,7 @@ public class PeriodicSyncTaskTest { public void run() { results.add(value1); } - }, 1, 2); + }, 1, 3); worker.addTask(new AltarikRunnable() { private int i = 0; @Override diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/SyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/SyncTaskTest.java new file mode 100644 index 0000000..b700843 --- /dev/null +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/SyncTaskTest.java @@ -0,0 +1,49 @@ +package fr.altarik.toolbox.task.sync; + +import fr.altarik.toolbox.task.AltarikRunnable; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +class SyncTaskTest { + + @Test + void testOneTimeTask() { + SyncTask worker = (SyncTask) SyncTask.initialize(); + List results = new ArrayList<>(); + AtomicInteger value1 = new AtomicInteger(1); + AtomicInteger value2 = new AtomicInteger(2); + AltarikRunnable task1 = new AltarikRunnable() { + @Override + public void run() { + results.add(value1); + } + }; + AltarikRunnable task2 = new AltarikRunnable() { + @Override + public void run() { + results.add(value2); + } + }; + worker.addTask(task1); + worker.run(); + worker.run(); + worker.addTask(task2); + worker.addTask(task1); + worker.addTask(task2); + worker.run(); + worker.addTask(task1); + worker.run(); + AtomicInteger[] expected = { + value1, + value2, + value1, + value2, + value1 + }; + Assertions.assertArrayEquals(expected, results.toArray()); + } +} From c32e72dda643252414f5d025e888b9acee037d34 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 13 Feb 2023 14:17:03 +0100 Subject: [PATCH 08/10] Move each task scheduler to a specific class: Scheduler.java, AsyncPeriodicTasks.java scheduler is now on server thread (send task to async worker) Signed-off-by: Quentin Legot --- Tasks/build.gradle | 2 +- .../altarik/toolbox/task/AltarikRunnable.java | 2 +- .../fr/altarik/toolbox/task/Scheduler.java | 40 +++++++++++ .../altarik/toolbox/task/SendTaskWorkerI.java | 6 ++ .../task/{sync => }/ServerTickListener.java | 2 +- .../task/async/AsyncPeriodicTasks.java | 43 +++++------- .../toolbox/task/async/TaskScheduler.java | 67 ------------------- .../toolbox/task/sync/PeriodicSyncTask.java | 37 +++------- .../altarik/toolbox/task/sync/SyncTask.java | 32 +++------ .../task/async/PeriodicAsyncTaskTest.java | 31 ++++++++- .../task/sync/PeriodicSyncTaskTest.java | 2 +- .../toolbox/task/sync/SyncTaskTest.java | 8 +-- 12 files changed, 115 insertions(+), 157 deletions(-) create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/Scheduler.java create mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/SendTaskWorkerI.java rename Tasks/src/main/java/fr/altarik/toolbox/task/{sync => }/ServerTickListener.java (92%) delete mode 100644 Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java diff --git a/Tasks/build.gradle b/Tasks/build.gradle index adcbbf1..590944e 100644 --- a/Tasks/build.gradle +++ b/Tasks/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.0-SNAPSHOT' + id 'fabric-loom' version '1.1-SNAPSHOT' } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java b/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java index bdc3470..941c6ff 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/AltarikRunnable.java @@ -5,7 +5,7 @@ public abstract class AltarikRunnable implements Runnable { private boolean isCancelled = false; /** - * Warning: Some task cannot be cancelled (mostly async tasks like {@link fr.altarik.toolbox.task.async.AsyncTasks} + * Warning: Some task cannot be cancelled (mostly async tasks like {@link fr.altarik.toolbox.task.async.AsyncTasks}) * The result of this call is ignored in this case, you can still add a way to not execute its content (like if(isCancelled) return;) */ public void cancel() { diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/Scheduler.java b/Tasks/src/main/java/fr/altarik/toolbox/task/Scheduler.java new file mode 100644 index 0000000..c3b5d99 --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/Scheduler.java @@ -0,0 +1,40 @@ +package fr.altarik.toolbox.task; + +import java.util.ArrayList; +import java.util.List; + +public class Scheduler implements Runnable { + + private final List tasks; + private final SendTaskWorkerI worker; + + public Scheduler(SendTaskWorkerI worker, List tasks) { + this.worker = worker; + this.tasks = tasks; + } + + @Override + public void run() { + List removeList = new ArrayList<>(tasks.size()); + for(SchedulerTaskData data : tasks) { + if(!data.getFunction().isCancelled()) { + long currentDelay = data.getCurrentDelay(); + if(currentDelay != 0) { + data.setCurrentDelay(currentDelay - 1); + } else { + worker.sendTask(data.getFunction()); + if(data.getPeriod() == -1) { + removeList.add(data); + } else { + data.setCurrentDelay(data.getPeriod()); + } + } + } else { + removeList.add(data); + } + } + for(SchedulerTaskData toRemove : removeList) { + tasks.remove(toRemove); + } + } +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/SendTaskWorkerI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/SendTaskWorkerI.java new file mode 100644 index 0000000..01f354d --- /dev/null +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/SendTaskWorkerI.java @@ -0,0 +1,6 @@ +package fr.altarik.toolbox.task; + +public interface SendTaskWorkerI { + + void sendTask(AltarikRunnable task); +} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java b/Tasks/src/main/java/fr/altarik/toolbox/task/ServerTickListener.java similarity index 92% rename from Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java rename to Tasks/src/main/java/fr/altarik/toolbox/task/ServerTickListener.java index d70562d..cac9623 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/ServerTickListener.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/ServerTickListener.java @@ -1,4 +1,4 @@ -package fr.altarik.toolbox.task.sync; +package fr.altarik.toolbox.task; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.minecraft.server.MinecraftServer; diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java index 1141751..1e095f8 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java @@ -1,44 +1,30 @@ package fr.altarik.toolbox.task.async; -import fr.altarik.toolbox.task.AltarikRunnable; -import fr.altarik.toolbox.task.PeriodicTaskI; -import it.unimi.dsi.fastutil.ints.IntComparators; +import fr.altarik.toolbox.task.*; -import java.util.ArrayList; -import java.util.List; +import java.util.Stack; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI { +public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI, SendTaskWorkerI { private final ExecutorService worker; - private final List schedulers; + private final Stack tasks; + protected final Scheduler scheduler; + private final ServerTickListener listener; private AsyncPeriodicTasks(int numberOfWorker) { - int size = 0; if(numberOfWorker == 1) { worker = Executors.newSingleThreadExecutor(); - size = 1; } else if (numberOfWorker <= 0) { worker = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - size = Runtime.getRuntime().availableProcessors(); } else { worker = Executors.newFixedThreadPool(numberOfWorker); - size = numberOfWorker; - } - this.schedulers = new ArrayList<>(size); - for(int i = 0; i < size; i++) { - TaskScheduler scheduler = new TaskScheduler(); - schedulers.add(scheduler); - worker.submit(() -> { - try { - scheduler.asyncRunnerPeriodicTasks(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - }); } + tasks = new Stack<>(); + this.scheduler = new Scheduler(this, tasks); + this.listener = new ServerTickListener(scheduler); } /** @@ -65,15 +51,11 @@ public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI { if(worker.isTerminated() || worker.isShutdown()) { throw new InterruptedException("Worker has been terminated or shutdown, it's impossible to add new task"); } - schedulers.stream() - .min((o1, o2) -> IntComparators.NATURAL_COMPARATOR.compare(o1.getNumberOfTasks(), o2.getNumberOfTasks())) - .orElseThrow() - .sendAsyncTask(function, delay, period); + tasks.add(new SchedulerTaskData(function, delay, period - 1)); } @Override public void close() throws Exception { - schedulers.forEach(s -> s.setStop(true)); worker.shutdown(); boolean result = worker.awaitTermination(10, TimeUnit.SECONDS); if(!result) { @@ -81,4 +63,9 @@ public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI { throw new AsyncTasks.UnfinishedTasksException("Tasks take too many time to finish, shutdown has been enforce"); } } + + @Override + public void sendTask(AltarikRunnable task) { + worker.submit(task); + } } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java deleted file mode 100644 index 4bc2e74..0000000 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/async/TaskScheduler.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.altarik.toolbox.task.async; - -import fr.altarik.toolbox.task.AltarikRunnable; -import fr.altarik.toolbox.task.SchedulerTaskData; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.HashMap; -import java.util.Vector; - -public class TaskScheduler { - private Vector asyncTasks; - - /** - * Return last time the method was executed, Value initialized to now when using sending the task to scheduler - */ - private HashMap lastTimeExecution; - private boolean stop = false; - - - public synchronized void sendAsyncTask(AltarikRunnable function, long delay, long period) throws InterruptedException { - SchedulerTaskData data = new SchedulerTaskData(function, delay, period); - asyncTasks.addElement(data); - lastTimeExecution.put(new SchedulerTaskData(function, delay, period), Instant.now()); - notify(); - } - - /** - * Function executed in asynchronous workers with periodic tasks - */ - public synchronized void asyncRunnerPeriodicTasks() throws InterruptedException { - loop: while(true) { - while(asyncTasks.size() == 0) { - if(isStop()) { - break loop; - } - wait(); - } - SchedulerTaskData data = asyncTasks.firstElement(); - asyncTasks.remove(data); - if(!data.getFunction().isCancelled()) { - long currentDelay = data.getCurrentDelay(); - Instant currentTime = Instant.now(); - Instant lastExecution = lastTimeExecution.get(data); - // (lastExec + delay) - currentTime - if(lastExecution.plus(currentDelay, ChronoUnit.MILLIS).isBefore(currentTime)) { - data.getFunction().run(); - data.setCurrentDelay(data.getPeriod()); - lastTimeExecution.put(data, Instant.now()); - asyncTasks.addElement(data); - } - } - } - } - - public synchronized boolean isStop() { - return stop; - } - - public synchronized void setStop(boolean stop) { - this.stop = stop; - } - - public int getNumberOfTasks() { - return asyncTasks.size(); - } -} diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java index 381c263..e0c5e1f 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/PeriodicSyncTask.java @@ -1,20 +1,20 @@ package fr.altarik.toolbox.task.sync; -import fr.altarik.toolbox.task.AltarikRunnable; -import fr.altarik.toolbox.task.PeriodicTaskI; -import fr.altarik.toolbox.task.SchedulerTaskData; +import fr.altarik.toolbox.task.*; import java.util.ArrayList; import java.util.List; -public class PeriodicSyncTask implements PeriodicTaskI, Runnable { +public class PeriodicSyncTask implements PeriodicTaskI, SendTaskWorkerI { private final ServerTickListener listener; private final List tasks; + protected final Scheduler scheduler; private PeriodicSyncTask() { - this.listener = new ServerTickListener(this); this.tasks = new ArrayList<>(2); + this.scheduler = new Scheduler(this, tasks); + this.listener = new ServerTickListener(scheduler); } @@ -27,30 +27,13 @@ public class PeriodicSyncTask implements PeriodicTaskI, Runnable { addTask(function, 0, 1); } - @Override - public void run() { - List removeList = new ArrayList<>(tasks.size()); - for(SchedulerTaskData data : tasks) { - if(!data.getFunction().isCancelled()) { - long currentDelay = data.getCurrentDelay(); - if(currentDelay != 0) { - data.setCurrentDelay(currentDelay - 1); - } else { - data.getFunction().run(); - data.setCurrentDelay(data.getPeriod()); - } - } else { - removeList.add(data); - } - } - for(SchedulerTaskData toRemove : removeList) { - tasks.remove(toRemove); - } - - } - @Override public void addTask(AltarikRunnable function, long delay, long period) { tasks.add(new SchedulerTaskData(function, delay, period - 1)); } + + @Override + public void sendTask(AltarikRunnable task) { + task.run(); + } } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/SyncTask.java b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/SyncTask.java index 749fe0c..19214e2 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/sync/SyncTask.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/sync/SyncTask.java @@ -1,20 +1,20 @@ package fr.altarik.toolbox.task.sync; -import fr.altarik.toolbox.task.AltarikRunnable; -import fr.altarik.toolbox.task.SchedulerTaskData; -import fr.altarik.toolbox.task.TaskI; +import fr.altarik.toolbox.task.*; import java.util.ArrayList; import java.util.List; -public class SyncTask implements TaskI, Runnable { +public class SyncTask implements TaskI, SendTaskWorkerI { private final ServerTickListener listener; private final List tasks; + protected final Scheduler scheduler; private SyncTask() { - this.listener = new ServerTickListener(this); this.tasks = new ArrayList<>(2); + this.scheduler = new Scheduler(this, tasks); + this.listener = new ServerTickListener(scheduler); } public static TaskI initialize() { @@ -27,27 +27,11 @@ public class SyncTask implements TaskI, Runnable { } public void addTask(AltarikRunnable function, int delay) { - tasks.add(new SchedulerTaskData(function, delay, 0)); + tasks.add(new SchedulerTaskData(function, delay, -1)); } @Override - public void run() { - List removeList = new ArrayList<>(tasks.size()); - for(SchedulerTaskData data : tasks) { - if(!data.getFunction().isCancelled()) { - long currentDelay = data.getCurrentDelay(); - if(currentDelay != 0) { - data.setCurrentDelay(currentDelay - 1); - } else { - data.getFunction().run(); - removeList.add(data); - } - } else { - removeList.add(data); - } - } - for(SchedulerTaskData toRemove : removeList) { - tasks.remove(toRemove); - } + public void sendTask(AltarikRunnable task) { + task.run(); } } diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/async/PeriodicAsyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/async/PeriodicAsyncTaskTest.java index 29e0fe6..9797c2b 100644 --- a/Tasks/src/test/java/fr/altarik/toolbox/task/async/PeriodicAsyncTaskTest.java +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/async/PeriodicAsyncTaskTest.java @@ -1,6 +1,7 @@ package fr.altarik.toolbox.task.async; import fr.altarik.toolbox.task.AltarikRunnable; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.Stack; @@ -9,24 +10,48 @@ import java.util.concurrent.atomic.AtomicInteger; public class PeriodicAsyncTaskTest { @Test - void testPeriodicASyncTask() { - AsyncPeriodicTasks worker = (AsyncPeriodicTasks) AsyncPeriodicTasks.initialize(); + void testPeriodicASyncTask() throws Exception { + AsyncPeriodicTasks worker = (AsyncPeriodicTasks) AsyncPeriodicTasks.initialize(1); Stack results = new Stack<>(); AtomicInteger value1 = new AtomicInteger(1); AtomicInteger value2 = new AtomicInteger(2); AltarikRunnable runnable1 = new AltarikRunnable() { + private int i = 0; @Override public void run() { results.add(value1); + i++; + if(i == 2) + cancel(); } }; AltarikRunnable runnable2 = new AltarikRunnable() { + private int i = 0; @Override public void run() { results.add(value2); + i++; + if(i == 4) + cancel(); } }; - + worker.addTask(runnable1, 1, 4); + worker.addTask(runnable2, 0, 2); + for(int i = 0; i < 10; i++) { + worker.scheduler.run(); + } + AtomicInteger[] expected = { + value2, + value1, + value2, + value2, + value1, + value2, + value2, + value1 + }; + worker.close(); + Assertions.assertArrayEquals(expected, results.toArray()); } } diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java index 2a5565c..c252375 100644 --- a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/PeriodicSyncTaskTest.java @@ -33,7 +33,7 @@ class PeriodicSyncTaskTest { } }); for(int i = 0; i < 10; i++) { - worker.run(); + worker.scheduler.run(); } AtomicInteger[] expected = { value2, diff --git a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/SyncTaskTest.java b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/SyncTaskTest.java index b700843..44f5b9f 100644 --- a/Tasks/src/test/java/fr/altarik/toolbox/task/sync/SyncTaskTest.java +++ b/Tasks/src/test/java/fr/altarik/toolbox/task/sync/SyncTaskTest.java @@ -29,14 +29,14 @@ class SyncTaskTest { } }; worker.addTask(task1); - worker.run(); - worker.run(); + worker.scheduler.run(); + worker.scheduler.run(); worker.addTask(task2); worker.addTask(task1); worker.addTask(task2); - worker.run(); + worker.scheduler.run(); worker.addTask(task1); - worker.run(); + worker.scheduler.run(); AtomicInteger[] expected = { value1, value2, From f5db55e96e9eb57bfcd58344b10d8ffc5c4a39c6 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 13 Feb 2023 15:00:13 +0100 Subject: [PATCH 09/10] Added tests --- .../altarik/toolbox/task/PeriodicTaskI.java | 2 +- .../altarik/toolbox/task/SendTaskWorkerI.java | 5 +++ .../java/fr/altarik/toolbox/task/Task.java | 39 ++++++++++++++++++- .../java/fr/altarik/toolbox/task/TaskI.java | 5 +++ .../task/async/AsyncPeriodicTasks.java | 22 ++++++++++- 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java index 2a7cd48..fd65aa2 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/PeriodicTaskI.java @@ -10,5 +10,5 @@ public interface PeriodicTaskI extends TaskI { * @throws InterruptedException When executed asynchronously, task may be interrupted * @see fr.altarik.toolbox.task.sync.PeriodicSyncTask */ - public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException; + void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException; } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/SendTaskWorkerI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/SendTaskWorkerI.java index 01f354d..247ff5b 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/SendTaskWorkerI.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/SendTaskWorkerI.java @@ -2,5 +2,10 @@ package fr.altarik.toolbox.task; public interface SendTaskWorkerI { + /** + * Internal use for scheduler, do not use. + * Scheduler use this method to send the task to execute to worker + * @param task task to execute now + */ void sendTask(AltarikRunnable task); } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java b/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java index b88d067..c9b8129 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java @@ -1,15 +1,50 @@ package fr.altarik.toolbox.task; +import fr.altarik.toolbox.task.async.AsyncPeriodicTasks; +import fr.altarik.toolbox.task.async.AsyncTaskI; import fr.altarik.toolbox.task.async.AsyncTasks; +import fr.altarik.toolbox.task.sync.PeriodicSyncTask; import net.fabricmc.api.ModInitializer; public class Task implements ModInitializer { - public TaskI asyncWorkers = AsyncTasks.initialize(); + public final TaskI asyncWorkers = AsyncTasks.initialize(); + public final PeriodicTaskI periodicSyncTask = PeriodicSyncTask.initialize(); + + public final AsyncTaskI asyncTasks = AsyncTasks.initialize(); + + public final PeriodicTaskI periodicAsyncTask = AsyncPeriodicTasks.initialize(); @Override public void onInitialize() { - + /*try { + asyncWorkers.addTask(new AltarikRunnable() { + @Override + public void run() { + System.out.println("Hello world 1"); + } + }); + periodicSyncTask.addTask(new AltarikRunnable() { + @Override + public void run() { + System.out.println("Hello world 2"); + } + }, 40, 60); + asyncTasks.addTask(new AltarikRunnable() { + @Override + public void run() { + System.out.println("Hello world 3 : " + Thread.currentThread().getName()); + } + }); + periodicAsyncTask.addTask(new AltarikRunnable() { + @Override + public void run() { + System.out.println("Hello world 4 : " + Thread.currentThread().getName()); + } + }, 60, 80); + } catch (InterruptedException e) { + throw new RuntimeException(e); + }*/ } public TaskI getAsyncWorkers() { diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java index 2f668a8..6a22e48 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java @@ -2,6 +2,11 @@ package fr.altarik.toolbox.task; public interface TaskI { + /** + * Send task to worker, execution depends on implementation + * @param function task you send to worker + * @throws InterruptedException used by asynchronous workers if threads has been interrupted or shutdown + */ void addTask(AltarikRunnable function) throws InterruptedException; } diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java index 1e095f8..b3f7b9d 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/async/AsyncPeriodicTasks.java @@ -7,6 +7,10 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +/** + * A task manager to execute periodic tasks asynchronously. A scheduler on the main/server thread will send the task to + * worker threads. + */ public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI, SendTaskWorkerI { private final ExecutorService worker; @@ -41,11 +45,23 @@ public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI, SendTaskWo return initialize(Runtime.getRuntime().availableProcessors()); } + /** + * Send the task to the scheduler, the task is executed at the next server tick and at every following tick + * @param function the function which will be executed + * @throws InterruptedException if worker has terminated or is shutting down + */ @Override public void addTask(AltarikRunnable function) throws InterruptedException { - this.addTask(function, 0, 1000); + this.addTask(function, 0, 1); } + /** + * Send the task to the scheduler, executed depending on the parameters (delay and period) + * @param function the function to execute + * @param delay delay in tick before starting the task + * @param period time in tick to wait between runs + * @throws InterruptedException if worker has terminated or is shutting down + */ @Override public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException { if(worker.isTerminated() || worker.isShutdown()) { @@ -54,6 +70,10 @@ public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI, SendTaskWo tasks.add(new SchedulerTaskData(function, delay, period - 1)); } + /** + * Try to execute task you already send in 10 seconds, otherwise workers are killed. + * @throws AsyncTasks.UnfinishedTasksException if workers has been shutdown before finishing every tasks + */ @Override public void close() throws Exception { worker.shutdown(); From 0f902faa1b9f8b3cf575c386dfdceb165c2cbe9f Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 13 Feb 2023 15:25:08 +0100 Subject: [PATCH 10/10] Fix fabric.mod.json, add run folder to gitignore Signed-off-by: Quentin Legot --- .gitignore | 4 +++- Tasks/src/main/java/fr/altarik/toolbox/task/Task.java | 4 ++-- Tasks/src/main/resources/fabric.mod.json | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index fd00d92..5f60383 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ build/ !**/src/main/**/build/ !**/src/test/**/build/ +Tasks/run + ### IntelliJ IDEA ### .idea *.iws @@ -36,4 +38,4 @@ bin/ .vscode/ ### Mac OS ### -.DS_Store \ No newline at end of file +.DS_Store diff --git a/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java b/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java index c9b8129..f2d163a 100644 --- a/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java +++ b/Tasks/src/main/java/fr/altarik/toolbox/task/Task.java @@ -17,7 +17,7 @@ public class Task implements ModInitializer { @Override public void onInitialize() { - /*try { + /* try { asyncWorkers.addTask(new AltarikRunnable() { @Override public void run() { @@ -44,7 +44,7 @@ public class Task implements ModInitializer { }, 60, 80); } catch (InterruptedException e) { throw new RuntimeException(e); - }*/ + } */ } public TaskI getAsyncWorkers() { diff --git a/Tasks/src/main/resources/fabric.mod.json b/Tasks/src/main/resources/fabric.mod.json index 8f15e03..8921daf 100644 --- a/Tasks/src/main/resources/fabric.mod.json +++ b/Tasks/src/main/resources/fabric.mod.json @@ -27,8 +27,7 @@ "depends": { "fabricloader": ">=0.14.12", "fabric": "*", - "minecraft": "1.19.3", - "npcs": "2.0.1-SNAPSHOT" + "minecraft": "1.19.3" } } \ No newline at end of file