From 3db1d5fdb3d0acf16c85ff1ccdc58f4c2936789d Mon Sep 17 00:00:00 2001 From: drtshock Date: Fri, 7 Aug 2015 15:03:22 -0500 Subject: [PATCH] Improve concurrency with help from @evilmidget38 --- .../java/com/massivecraft/factions/Board.java | 4 +- .../zcore/persist/json/JSONBoard.java | 31 ++-------- .../zcore/persist/json/JSONFPlayers.java | 19 ++---- .../zcore/persist/json/JSONFactions.java | 19 ++---- .../factions/zcore/util/DiscUtil.java | 59 +++++++++++++++++-- .../factions/zcore/util/Persist.java | 2 +- 6 files changed, 70 insertions(+), 64 deletions(-) diff --git a/src/main/java/com/massivecraft/factions/Board.java b/src/main/java/com/massivecraft/factions/Board.java index 8f27f783..24d796ba 100644 --- a/src/main/java/com/massivecraft/factions/Board.java +++ b/src/main/java/com/massivecraft/factions/Board.java @@ -78,9 +78,9 @@ public abstract class Board { */ public abstract ArrayList getMap(Faction faction, FLocation flocation, double inDegrees); - public abstract boolean forceSave(); + public abstract void forceSave(); - public abstract boolean forceSave(boolean sync); + public abstract void forceSave(boolean sync); public abstract boolean load(); } diff --git a/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONBoard.java b/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONBoard.java index 512686ff..d81afb45 100644 --- a/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONBoard.java +++ b/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONBoard.java @@ -6,7 +6,6 @@ import com.massivecraft.factions.FLocation; import com.massivecraft.factions.P; import com.massivecraft.factions.zcore.persist.MemoryBoard; import com.massivecraft.factions.zcore.util.DiscUtil; -import org.bukkit.Bukkit; import java.io.File; import java.lang.reflect.Type; @@ -63,34 +62,12 @@ public class JSONBoard extends MemoryBoard { } } - public boolean forceSave() { - return forceSave(true); + public void forceSave() { + forceSave(true); } - public boolean forceSave(boolean sync) { - if (sync) { - try { - DiscUtil.write(file, P.p.gson.toJson(dumpAsSaveFormat())); - } catch (Exception e) { - e.printStackTrace(); - P.p.log("Failed to save the board to disk."); - return false; - } - } else { - Bukkit.getScheduler().runTaskAsynchronously(P.p, new Runnable() { - @Override - public void run() { - try { - DiscUtil.write(file, P.p.gson.toJson(dumpAsSaveFormat())); - } catch (Exception e) { - e.printStackTrace(); - P.p.log("Failed to save the board to disk."); - } - } - }); - } - - return true; + public void forceSave(boolean sync) { + DiscUtil.writeCatch(file, P.p.gson.toJson(dumpAsSaveFormat()), sync); } public boolean load() { diff --git a/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONFPlayers.java b/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONFPlayers.java index af5e3148..66d3d1f2 100644 --- a/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONFPlayers.java +++ b/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONFPlayers.java @@ -62,20 +62,11 @@ public class JSONFPlayers extends MemoryFPlayers { } } - if (sync) { - saveCore(file, entitiesThatShouldBeSaved); - } else { - Bukkit.getScheduler().runTaskAsynchronously(P.p, new Runnable() { - @Override - public void run() { - saveCore(file, entitiesThatShouldBeSaved); - } - }); - } + saveCore(file, entitiesThatShouldBeSaved, sync); } - private boolean saveCore(File target, Map data) { - return DiscUtil.writeCatch(target, this.gson.toJson(data)); + private boolean saveCore(File target, Map data, boolean sync) { + return DiscUtil.writeCatch(target, this.gson.toJson(data), sync); } public void load() { @@ -126,7 +117,7 @@ public class JSONFPlayers extends MemoryFPlayers { } catch (IOException e) { e.printStackTrace(); } - saveCore(file, (Map) data); + saveCore(file, (Map) data, true); Bukkit.getLogger().log(Level.INFO, "Backed up your old data at " + file.getAbsolutePath()); // Start fetching those UUIDs @@ -170,7 +161,7 @@ public class JSONFPlayers extends MemoryFPlayers { Bukkit.getLogger().log(Level.INFO, "While converting we found names that either don't have a UUID or aren't players and removed them from storage."); Bukkit.getLogger().log(Level.INFO, "The following names were detected as being invalid: " + StringUtils.join(invalidList, ", ")); } - saveCore(this.file, (Map) data); // Update the + saveCore(this.file, (Map) data, true); // Update the // flatfile Bukkit.getLogger().log(Level.INFO, "Done converting players.json to UUID."); } diff --git a/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONFactions.java b/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONFactions.java index f450122d..4bee78c0 100644 --- a/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONFactions.java +++ b/src/main/java/com/massivecraft/factions/zcore/persist/json/JSONFactions.java @@ -62,20 +62,11 @@ public class JSONFactions extends MemoryFactions { entitiesThatShouldBeSaved.put(entity.getId(), (JSONFaction) entity); } - if (sync) { - saveCore(file, entitiesThatShouldBeSaved); - } else { - Bukkit.getScheduler().runTaskAsynchronously(P.p, new Runnable() { - @Override - public void run() { - saveCore(file, entitiesThatShouldBeSaved); - } - }); - } + saveCore(file, entitiesThatShouldBeSaved, sync); } - private boolean saveCore(File target, Map entities) { - return DiscUtil.writeCatch(target, this.gson.toJson(entities)); + private boolean saveCore(File target, Map entities, boolean sync) { + return DiscUtil.writeCatch(target, this.gson.toJson(entities), sync); } public void load() { @@ -129,7 +120,7 @@ public class JSONFactions extends MemoryFactions { } catch (IOException e) { e.printStackTrace(); } - saveCore(file, (Map) data); + saveCore(file, (Map) data, true); Bukkit.getLogger().log(Level.INFO, "Backed up your old data at " + file.getAbsolutePath()); Bukkit.getLogger().log(Level.INFO, "Please wait while Factions converts " + needsUpdate + " old player names to UUID. This may take a while."); @@ -189,7 +180,7 @@ public class JSONFactions extends MemoryFactions { } } - saveCore(this.file, (Map) data); // Update the flatfile + saveCore(this.file, (Map) data, true); // Update the flatfile Bukkit.getLogger().log(Level.INFO, "Done converting factions.json to UUID."); } return data; diff --git a/src/main/java/com/massivecraft/factions/zcore/util/DiscUtil.java b/src/main/java/com/massivecraft/factions/zcore/util/DiscUtil.java index e618179f..fb27d6ec 100644 --- a/src/main/java/com/massivecraft/factions/zcore/util/DiscUtil.java +++ b/src/main/java/com/massivecraft/factions/zcore/util/DiscUtil.java @@ -1,6 +1,13 @@ package com.massivecraft.factions.zcore.util; +import com.massivecraft.factions.P; +import org.bukkit.Bukkit; + import java.io.*; +import java.util.HashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; public class DiscUtil { @@ -14,6 +21,7 @@ public class DiscUtil { // BYTE // -------------------------------------------- // + public static byte[] readBytes(File file) throws IOException { int length = (int) file.length(); byte[] output = new byte[length]; @@ -48,13 +56,52 @@ public class DiscUtil { // CATCH // -------------------------------------------- // - public static boolean writeCatch(File file, String content) { - try { - write(file, content); - return true; - } catch (Exception e) { - return false; + private static HashMap locks = new HashMap(); + + public static boolean writeCatch(final File file, final String content, boolean sync) { + final byte[] bytes = utf8(content); + String name = file.getName(); + final Lock lock; + + // Create lock for each file if there isn't already one. + if (locks.containsKey(name)) { + lock = locks.get(name); + } else { + ReadWriteLock rwl = new ReentrantReadWriteLock(); + lock = rwl.writeLock(); + locks.put(name, lock); } + + if (sync) { + lock.lock(); + try { + FileOutputStream out = new FileOutputStream(file); + out.write(bytes); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } else { + Bukkit.getScheduler().runTaskAsynchronously(P.p, new Runnable() { + @Override + public void run() { + lock.lock(); + try { + FileOutputStream out = new FileOutputStream(file); + out.write(bytes); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + }); + } + + return true; // don't really care but for some reason this is a boolean. } public static String readCatch(File file) { diff --git a/src/main/java/com/massivecraft/factions/zcore/util/Persist.java b/src/main/java/com/massivecraft/factions/zcore/util/Persist.java index 42ff4370..839e842f 100644 --- a/src/main/java/com/massivecraft/factions/zcore/util/Persist.java +++ b/src/main/java/com/massivecraft/factions/zcore/util/Persist.java @@ -100,7 +100,7 @@ public class Persist { } public boolean save(Object instance, File file) { - return DiscUtil.writeCatch(file, p.gson.toJson(instance)); + return DiscUtil.writeCatch(file, p.gson.toJson(instance), true); } // LOAD BY CLASS