diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index dd7c32538f6..9697935da58 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -45,6 +45,7 @@ import com.earth2me.essentials.utils.VersionUtil; import io.papermc.lib.PaperLib; import net.ess3.api.Economy; +import com.earth2me.essentials.config.EssentialsConfiguration; import net.ess3.api.IEssentials; import net.ess3.api.IItemDb; import net.ess3.api.IJails; @@ -570,6 +571,8 @@ public void onDisable() { Trade.closeLog(); getUsers().shutdown(); + EssentialsConfiguration.shutdownExecutor(); + HandlerList.unregisterAll(this); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurationSaveTask.java b/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurationSaveTask.java index b6d4c7461b9..43c20e5f7db 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurationSaveTask.java +++ b/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurationSaveTask.java @@ -6,34 +6,32 @@ import org.spongepowered.configurate.yaml.YamlConfigurationLoader; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; import java.util.logging.Level; public class ConfigurationSaveTask implements Runnable { private final YamlConfigurationLoader loader; - private final CommentedConfigurationNode node; + private final Supplier nodeSupplier; private final AtomicInteger pendingWrites; - public ConfigurationSaveTask(final YamlConfigurationLoader loader, final CommentedConfigurationNode node, final AtomicInteger pendingWrites) { + public ConfigurationSaveTask(final YamlConfigurationLoader loader, final Supplier nodeSupplier, final AtomicInteger pendingWrites) { this.loader = loader; - this.node = node; + this.nodeSupplier = nodeSupplier; this.pendingWrites = pendingWrites; } @Override public void run() { - synchronized (loader) { - // Check if there are more writes in queue. - // If that's the case, we shouldn't bother writing data which is already out-of-date. - if (pendingWrites.get() > 1) { - pendingWrites.decrementAndGet(); - } + if (pendingWrites.decrementAndGet() > 0) { + return; + } + synchronized (loader) { try { + final CommentedConfigurationNode node = nodeSupplier.get(); loader.save(node); } catch (ConfigurateException e) { Essentials.getWrappedLogger().log(Level.SEVERE, e.getMessage(), e); - } finally { - pendingWrites.decrementAndGet(); } } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java b/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java index 95d97ce9565..875683cb823 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java +++ b/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java @@ -43,7 +43,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; @@ -51,7 +51,7 @@ import static com.earth2me.essentials.I18n.tlLiteral; public class EssentialsConfiguration { - private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + private static volatile ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); private static final ObjectMapper.Factory MAPPER_FACTORY = ObjectMapper.factoryBuilder() .addProcessor(DeleteOnEmpty.class, (data, value) -> new DeleteOnEmptyProcessor()) .addProcessor(DeleteIfIncomplete.class, (data, value) -> new DeleteIfIncompleteProcessor()) @@ -462,21 +462,50 @@ public synchronized void save() { public synchronized void blockingSave() { try { - delaySave().get(); + delaySave(); + getExecutor().submit(() -> {}).get(); } catch (final InterruptedException | ExecutionException e) { Essentials.getWrappedLogger().log(Level.SEVERE, e.getMessage(), e); } } - private Future delaySave() { + private void delaySave() { if (saveHook != null) { saveHook.run(); } - final CommentedConfigurationNode node = configurationNode.copy(); - pendingWrites.incrementAndGet(); + try { + getExecutor().submit(new ConfigurationSaveTask(loader, () -> configurationNode.copy(), pendingWrites)); + } catch (RejectedExecutionException rex) { + try { + synchronized (loader) { + loader.save(configurationNode.copy()); + } + } catch (ConfigurateException e) { + Essentials.getWrappedLogger().log(Level.SEVERE, e.getMessage(), e); + } finally { + pendingWrites.decrementAndGet(); + } + } + } - return EXECUTOR_SERVICE.submit(new ConfigurationSaveTask(loader, node, pendingWrites)); + public static void shutdownExecutor() { + final ExecutorService exec = EXECUTOR_SERVICE; + exec.shutdown(); + try { + if (!exec.awaitTermination(5, java.util.concurrent.TimeUnit.SECONDS)) { + exec.shutdownNow(); + } + } catch (InterruptedException ignored) { + exec.shutdownNow(); + } + } + + private static synchronized ExecutorService getExecutor() { + if (EXECUTOR_SERVICE == null || EXECUTOR_SERVICE.isShutdown() || EXECUTOR_SERVICE.isTerminated()) { + EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + } + return EXECUTOR_SERVICE; } }