Browse Source

async config save, simplified scheduler

Kajetan Johannes Hammerle 4 years ago
parent
commit
a61fd2812c

+ 1 - 2
src/main/java/me/km/Server.java

@@ -46,7 +46,7 @@ public class Server {
         server = serverIn;
         logger = new SnuviLogger();
 
-        SnuviConfig conf = new SnuviConfig(logger, "", "config");
+        SnuviConfig conf = new SnuviConfig("", "config");
         if(conf.exists()) {
             conf.load();
         }
@@ -130,7 +130,6 @@ public class Server {
     public static void onStop() {
         scripts.startScript("endscript");
         scheduler.stop();
-        scheduler.getWorker().stop();
         databank.closeDataBankConnection();
     }
 

+ 8 - 19
src/main/java/me/km/scheduler/AsyncWorker.java

@@ -1,9 +1,9 @@
 package me.km.scheduler;
 
-import java.util.LinkedList;
+import java.util.concurrent.ConcurrentLinkedQueue;
 
 public class AsyncWorker {
-    private final LinkedList<Runnable> tasks = new LinkedList<>();
+    private final ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>();
     private final Thread worker;
 
     public AsyncWorker() {
@@ -32,18 +32,14 @@ public class AsyncWorker {
                 try {
                     worker.wait();
                 } catch(InterruptedException ex) {
-                    break;
+                    return;
                 }
             }
-
             while(true) {
-                Runnable r;
-                synchronized(tasks) {
-                    if(tasks.isEmpty()) {
-                        break;
-                    }
-                    r = tasks.removeFirst();
+                if(tasks.isEmpty()) {
+                    break;
                 }
+                Runnable r = tasks.poll();
                 try {
                     r.run();
                 } catch(Exception ex) {
@@ -55,20 +51,13 @@ public class AsyncWorker {
     }
 
     public void add(Runnable r) {
-        synchronized(tasks) {
-            tasks.add(r);
-        }
-    }
-
-    public void doWork() {
+        tasks.add(r);
         synchronized(worker) {
             worker.notify();
         }
     }
 
     public boolean hasWork() {
-        synchronized(tasks) {
-            return !tasks.isEmpty();
-        }
+        return !tasks.isEmpty();
     }
 }

+ 35 - 60
src/main/java/me/km/scheduler/SnuviScheduler.java

@@ -1,8 +1,7 @@
 package me.km.scheduler;
 
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import me.hammerle.snuviscript.code.ISnuviLogger;
 import me.hammerle.snuviscript.code.ISnuviScheduler;
 import net.minecraftforge.api.distmarker.Dist;
@@ -11,17 +10,12 @@ import net.minecraftforge.api.distmarker.OnlyIn;
 @OnlyIn(Dist.DEDICATED_SERVER)
 public class SnuviScheduler implements ISnuviScheduler {
     private final ISnuviLogger logger;
-    private boolean checker;
-    private int counter;
-    private final LinkedList<SnuviTask> addQueue = new LinkedList<>();
-    private final LinkedList<Integer> removeQueue = new LinkedList<>();
-    private final HashMap<Integer, SnuviTask> tasks = new HashMap<>();
+    private final ConcurrentLinkedQueue<SnuviTask> tasks = new ConcurrentLinkedQueue<>();
     private final AsyncWorker worker = new AsyncWorker();
     private boolean noAdding = false;
 
     public SnuviScheduler(ISnuviLogger logger) {
         this.logger = logger;
-        counter = 0;
         worker.start();
     }
 
@@ -30,7 +24,7 @@ public class SnuviScheduler implements ISnuviScheduler {
         long endTime = System.nanoTime() + 60_000_000_000l;
         logger.print("Waiting until end of synchronized tasks ...");
         while(!tasks.isEmpty() && System.nanoTime() < endTime) {
-            tick();
+            tick(1000);
         }
         logger.print("Waiting until end of asynchronous tasks ...");
         while(worker.hasWork() && System.nanoTime() < endTime) {
@@ -39,73 +33,54 @@ public class SnuviScheduler implements ISnuviScheduler {
             } catch(InterruptedException ex) {
             }
         }
+        worker.stop();
         logger.print("the scheduler is now stopped");
     }
 
-    public void cancelTask(int id) {
-        removeQueue.add(id);
-    }
-
-    public int scheduleRepeatingTask(Runnable r, long ticks, long rtimer) {
+    public void scheduleRepeatingTask(Runnable r, long ticks, long rtimer) {
         if(noAdding) {
-            logger.print("scheduling tasks is not allowed on server stop");
-            return -1;
+            return;
         }
-        synchronized(addQueue) {
-            counter++;
-            addQueue.add(new SnuviTask(counter, r, ticks, rtimer));
-        }
-        return counter;
+        tasks.add(new SnuviTask(r, ticks, rtimer));
     }
 
     @Override
-    public int scheduleTask(Runnable r, long delay) {
-        return scheduleRepeatingTask(r, delay, 0);
+    public void scheduleTask(Runnable r, long delay) {
+        scheduleRepeatingTask(r, delay, 0);
     }
 
-    @Override
-    public int scheduleTask(Runnable r) {
-        return scheduleTask(r, 0);
+    public void tick() {
+        tick(1);
     }
 
-    public void tick() {
-        worker.doWork();
-        try {
-            if(!removeQueue.isEmpty()) {
-                removeQueue.forEach(i -> tasks.remove(i));
-                removeQueue.clear();
+    private void tick(int ticks) {
+        Iterator<SnuviTask> iter = tasks.iterator();
+        long endTime = System.currentTimeMillis() + 25;
+        while(iter.hasNext()) {
+            if(System.currentTimeMillis() > endTime) {
+                logger.print("scheduler has run longer than 25 ms");
+                break;
             }
-            synchronized(addQueue) {
-                if(!addQueue.isEmpty()) {
-                    addQueue.forEach(task -> tasks.put(task.getId(), task));
-                    addQueue.clear();
+            SnuviTask task = iter.next();
+            try {
+                if(task.tick(ticks, noAdding)) {
+                    iter.remove();
                 }
+            } catch(Exception ex) {
+                logger.print("scheduler exception - task will be removed", ex, null, null, null, null);
+                iter.remove();
             }
-            checker = false;
-            long l = System.currentTimeMillis();
-            tasks.values().removeIf(task -> {
-                if(checker) {
-                    return false;
-                }
-                if(System.currentTimeMillis() - l > 25) {
-                    checker = true;
-                    logger.print("scheduler has run longer than 25 ms");
-                    return false;
-                }
-                try {
-                    return task.tick(noAdding);
-                } catch(Exception ex) {
-                    logger.print("scheduler exception - task will be removed");
-                    ex.printStackTrace();
-                    return true;
-                }
-            });
-        } catch(ConcurrentModificationException ex) {
-            logger.print(ex);
         }
     }
 
-    public AsyncWorker getWorker() {
-        return worker;
+    public void scheduleAsyncTask(Runnable r) {
+        if(noAdding) {
+            return;
+        }
+        worker.add(r);
+    }
+
+    public boolean hasAsyncWork() {
+        return worker.hasWork();
     }
 }

+ 3 - 9
src/main/java/me/km/scheduler/SnuviTask.java

@@ -1,20 +1,14 @@
 package me.km.scheduler;
 
 public class SnuviTask {
-    private final int id;
     private final long rtimer;
     private final Runnable r;
     private long timer;
 
-    public SnuviTask(int id, Runnable r, long delay, long rtimer) {
+    public SnuviTask(Runnable r, long delay, long rtimer) {
         this.rtimer = rtimer;
         this.timer = delay;
         this.r = r;
-        this.id = id;
-    }
-
-    public int getId() {
-        return id;
     }
 
     public long getRepeatTimer() {
@@ -25,8 +19,8 @@ public class SnuviTask {
         return rtimer > 0;
     }
 
-    public boolean tick(boolean noRepeat) {
-        timer -= 1;
+    public boolean tick(int ticks, boolean noRepeat) {
+        timer -= ticks;
         if(timer <= 0) {
             r.run();
             if(rtimer <= 0 || noRepeat) {

+ 5 - 0
src/main/java/me/km/snuviscript/commands/Commands.java

@@ -2,6 +2,7 @@ package me.km.snuviscript.commands;
 
 import me.hammerle.snuviscript.code.ScriptManager;
 import me.hammerle.snuviscript.code.SnuviUtils;
+import me.hammerle.snuviscript.config.SnuviConfig;
 import me.km.permissions.ModCommandManager;
 import me.km.permissions.Permissions;
 import me.km.scheduler.SnuviScheduler;
@@ -35,5 +36,9 @@ public class Commands {
             Object o = in[0].get(sc);
             return o != null && o instanceof LivingEntity;
         });
+        sm.registerConsumer("config.saveasync", (sc, in) -> {
+            SnuviConfig config = (SnuviConfig) in[0].get(sc);
+            scheduler.scheduleAsyncTask(() -> config.save());
+        });
     }
 }

+ 2 - 2
src/main/java/me/km/snuviscript/commands/DatabankCommands.java

@@ -42,7 +42,7 @@ public class DatabankCommands {
             final PreparedStatement p = (PreparedStatement) in[0].get(sc);
             StackTrace lines = sc.getStackTrace();
             String function = "databank.workerexecute";
-            scheduler.getWorker().add(() -> {
+            scheduler.scheduleAsyncTask(() -> {
                 try {
                     p.execute();
                 } catch(SQLException ex) {
@@ -66,6 +66,6 @@ public class DatabankCommands {
             auto.close();
             sc.removeCloseable(auto);
         });
-        sm.registerFunction("worker.haswork", (sc, in) -> scheduler.getWorker().hasWork());
+        sm.registerFunction("worker.haswork", (sc, in) -> scheduler.hasAsyncWork());
     }
 }

+ 9 - 9
src/main/java/me/km/snuviscript/commands/DeprecatedCommands.java

@@ -29,7 +29,7 @@ public class DeprecatedCommands {
             final String value = in[2].getString(sc);
             final String var = in[1].getString(sc);
             final int id = getId(playerBank, in[0].get(sc));
-            scheduler.getWorker().add(() -> {
+            scheduler.scheduleAsyncTask(() -> {
                 try {
                     scriptBank.setVar(value, var, id);
                 } catch(Exception ex) {
@@ -43,7 +43,7 @@ public class DeprecatedCommands {
         sm.registerConsumer("delglobalvar", (sc, in) -> {
             final String var = in[1].getString(sc);
             final int id = getId(playerBank, in[0].get(sc));
-            scheduler.getWorker().add(() -> {
+            scheduler.scheduleAsyncTask(() -> {
                 try {
                     scriptBank.deleteVar(var, id);
                 } catch(Exception ex) {
@@ -56,7 +56,7 @@ public class DeprecatedCommands {
         sm.registerAlias("delglobalvar", "dgv");
         sm.registerConsumer("gmap.removeall", (sc, in) -> {
             final String map = in[0].getString(sc);
-            scheduler.getWorker().add(() -> {
+            scheduler.scheduleAsyncTask(() -> {
                 try {
                     scriptBank.removeMap(map);
                 } catch(Exception ex) {
@@ -70,7 +70,7 @@ public class DeprecatedCommands {
             final String map = in[0].getString(sc);
             final String key = in[1].getString(sc);
             final String value = in[2].getString(sc);
-            scheduler.getWorker().add(() -> {
+            scheduler.scheduleAsyncTask(() -> {
                 try {
                     scriptBank.addMapElement(map, key, value);
                 } catch(Exception ex) {
@@ -83,7 +83,7 @@ public class DeprecatedCommands {
         sm.registerConsumer("gmap.remove", (sc, in) -> {
             final String map = in[0].getString(sc);
             final String key = in[1].getString(sc);
-            scheduler.getWorker().add(() -> {
+            scheduler.scheduleAsyncTask(() -> {
                 try {
                     scriptBank.removeMapElement(map, key);
                 } catch(Exception ex) {
@@ -105,7 +105,7 @@ public class DeprecatedCommands {
             if(in.length >= 2) {
                 final String map = in[0].getString(sc);
                 final String key = in[1].getString(sc);
-                scheduler.getWorker().add(() -> {
+                scheduler.scheduleAsyncTask(() -> {
                     try {
                         scriptBank.removeDualMapElement(map, key);
                     } catch(Exception ex) {
@@ -116,7 +116,7 @@ public class DeprecatedCommands {
                 });
             } else {
                 final String map = in[0].getString(sc);
-                scheduler.getWorker().add(() -> {
+                scheduler.scheduleAsyncTask(() -> {
                     try {
                         scriptBank.removeDualMap(map);
                     } catch(Exception ex) {
@@ -132,7 +132,7 @@ public class DeprecatedCommands {
             final String key1 = in[1].getString(sc);
             final String key2 = in[2].getString(sc);
             final String value = in[3].getString(sc);
-            scheduler.getWorker().add(() -> {
+            scheduler.scheduleAsyncTask(() -> {
                 try {
                     scriptBank.addDualMapElement(map, key1, key2, value);
                 } catch(Exception ex) {
@@ -146,7 +146,7 @@ public class DeprecatedCommands {
             final String map = in[0].getString(sc);
             final String key1 = in[1].getString(sc);
             final String key2 = in[2].getString(sc);
-            scheduler.getWorker().add(() -> {
+            scheduler.scheduleAsyncTask(() -> {
                 try {
                     scriptBank.removeDualMapElement(map, key1, key2);
                 } catch(Exception ex) {

+ 4 - 3
src/main/java/me/km/snuviscript/commands/ItemCommands.java

@@ -45,6 +45,7 @@ public class ItemCommands {
         sm.registerFunction("item.hastag", (sc, in) -> ((Tag<Item>) in[0].get(sc)).contains(((ItemStack) in[1].get(sc)).getItem()));
         sm.registerFunction("item.get", (sc, in) -> ((ItemStack) in[0].get(sc)).getItem());
         sm.registerFunction("item.gettype", (sc, in) -> ((ItemStack) in[0].get(sc)).getItem().getRegistryName().toString());
+        sm.registerFunction("item.getmaxamount", (sc, in) -> (double) ((ItemStack) in[0].get(sc)).getMaxStackSize());
         sm.registerFunction("item.getamount", (sc, in) -> (double) ((ItemStack) in[0].get(sc)).getCount());
         sm.registerConsumer("item.setamount", (sc, in) -> ((ItemStack) in[0].get(sc)).setCount(in[1].getInt(sc)));
         sm.registerFunction("item.getfulltext", (sc, in) -> ((ItemStack) in[0].get(sc)).getTextComponent());
@@ -94,9 +95,9 @@ public class ItemCommands {
             }
         });
         sm.registerFunction("item.clone", (sc, in) -> ((ItemStack) in[0].get(sc)).copy());
-        sm.registerFunction("item.getmaxdamage", (sc, in) -> ((ItemStack) in[0].get(sc)).getMaxDamage());
-        sm.registerConsumer("item.isdamageable", (sc, in) -> ((ItemStack) in[0].get(sc)).isDamageable());
-        sm.registerConsumer("item.getdamage", (sc, in) -> ((ItemStack) in[0].get(sc)).getDamage());
+        sm.registerFunction("item.getmaxdamage", (sc, in) -> (double) ((ItemStack) in[0].get(sc)).getMaxDamage());
+        sm.registerFunction("item.isdamageable", (sc, in) -> ((ItemStack) in[0].get(sc)).isDamageable());
+        sm.registerFunction("item.getdamage", (sc, in) -> (double) ((ItemStack) in[0].get(sc)).getDamage());
         sm.registerConsumer("item.setdamage", (sc, in) -> {
             ((ItemStack) in[0].get(sc)).setDamage(in[1].getInt(sc));
         });

+ 1 - 1
src/main/java/me/km/world/ModWorldInfo.java

@@ -53,7 +53,7 @@ public class ModWorldInfo extends DerivedWorldInfo {
     public ModWorldInfo(WorldInfo info, String name, MinecraftServer server) {
         super(info);
 
-        config = new SnuviConfig(Server.getLogger(), "worlddata", name);
+        config = new SnuviConfig("worlddata", name);
         if(config.exists()) {
             config.load();
         }