From 5a7ba770955e664d3037219f3afd115d71d47453 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 16:53:34 +0200 Subject: [PATCH] Make the materials mappings safe to be used by multiple servers at the same time --- .../java/de/diddiz/LogBlock/Consumer.java | 58 -------- .../de/diddiz/LogBlock/MaterialConverter.java | 132 +++++++++++------- src/main/java/de/diddiz/LogBlock/Updater.java | 22 ++- 3 files changed, 102 insertions(+), 110 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 0d37b21..b192ca3 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -398,14 +398,6 @@ public class Consumer extends TimerTask { queue.add(new PlayerLeaveRow(player, onlineTime)); } - public void queueAddMaterialMapping(int key, String material) { - queue.add(new AddMaterialRow(key, material)); - } - - public void queueAddBlockStateMapping(int key, String blockState) { - queue.add(new AddBlockStateRow(key, blockState)); - } - @Override public synchronized void run() { if (queue.isEmpty() || !lock.tryLock()) { @@ -1046,56 +1038,6 @@ public class Consumer extends TimerTask { } } - private class AddMaterialRow implements Row { - private final int key; - private final String material; - - AddMaterialRow(int key, String material) { - this.key = key; - this.material = material; - } - - @Override - public String[] getInserts() { - return new String[] { "INSERT INTO `lb-materials` (id, name) VALUES (" + key + ",'" + mysqlTextEscape(material) + "');" }; - } - - @Override - public String[] getPlayers() { - return new String[0]; - } - - @Override - public Actor[] getActors() { - return new Actor[0]; - } - } - - private class AddBlockStateRow implements Row { - private final int key; - private final String blockstate; - - AddBlockStateRow(int key, String blockstate) { - this.key = key; - this.blockstate = blockstate; - } - - @Override - public String[] getInserts() { - return new String[] { "INSERT INTO `lb-blockstates` (id, name) VALUES (" + key + ",'" + mysqlTextEscape(blockstate) + "');" }; - } - - @Override - public String[] getPlayers() { - return new String[0]; - } - - @Override - public Actor[] getActors() { - return new Actor[0]; - } - } - private int safeY(Location loc) { int safeY = loc.getBlockY(); if (safeY < 0) diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index 2f48d86..ff89953 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -1,11 +1,13 @@ package de.diddiz.LogBlock; import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import java.util.HashMap; +import java.util.logging.Level; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -40,18 +42,32 @@ public class MaterialConverter { materialString = blockDataString.substring(0, dataPart); } Integer key = materialToID.get(materialString); - if (key == null) { - key = nextMaterialId++; - materialToID.put(materialString, key); - int length = idToMaterial.length; - while (length <= key) { - length = (length * 3 / 2) + 5; + while (key == null) { + key = nextMaterialId; + Connection conn = LogBlock.getInstance().getConnection(); + try { + conn.setAutoCommit(false); + PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-materials` (id, name) VALUES (?, ?)"); + smt.setInt(1, key); + smt.setString(2, materialString); + boolean couldAdd = smt.executeUpdate() > 0; + conn.commit(); + smt.close(); + if (couldAdd) { + internalAddMaterial(key, materialString); + } else { + initializeMaterials(conn); + } + } catch (SQLException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-materials", e); + } finally { + try { + conn.close(); + } catch (SQLException e) { + // ignored + } } - if (length > idToMaterial.length) { - idToMaterial = Arrays.copyOf(idToMaterial, length); - } - idToMaterial[key] = materialString; - LogBlock.getInstance().getConsumer().queueAddMaterialMapping(key, materialString); + key = materialToID.get(materialString); } return key.intValue(); } @@ -63,18 +79,32 @@ public class MaterialConverter { } String materialString = blockDataString.substring(dataPart); Integer key = blockStateToID.get(materialString); - if (key == null) { - key = nextBlockStateId++; - blockStateToID.put(materialString, key); - int length = idToBlockState.length; - while (length <= key) { - length = (length * 3 / 2) + 5; + while (key == null) { + key = nextBlockStateId; + Connection conn = LogBlock.getInstance().getConnection(); + try { + conn.setAutoCommit(false); + PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-blockstates` (id, name) VALUES (?, ?)"); + smt.setInt(1, key); + smt.setString(2, materialString); + boolean couldAdd = smt.executeUpdate() > 0; + conn.commit(); + smt.close(); + if (couldAdd) { + internalAddBlockState(key, materialString); + } else { + initializeMaterials(conn); + } + } catch (SQLException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-blockstates", e); + } finally { + try { + conn.close(); + } catch (SQLException e) { + // ignored + } } - if (length > idToBlockState.length) { - idToBlockState = Arrays.copyOf(idToBlockState, length); - } - idToBlockState[key] = materialString; - LogBlock.getInstance().getConsumer().queueAddBlockStateMapping(key, materialString); + key = blockStateToID.get(materialString); } return key.intValue(); } @@ -97,41 +127,47 @@ public class MaterialConverter { while (rs.next()) { int key = rs.getInt(1); String materialString = rs.getString(2); - - materialToID.put(materialString, key); - int length = idToMaterial.length; - while (length <= key) { - length = (length * 3 / 2) + 5; - } - if (length > idToMaterial.length) { - idToMaterial = Arrays.copyOf(idToMaterial, length); - } - idToMaterial[key] = materialString; - if (nextMaterialId <= key) { - nextMaterialId = key + 1; - } + internalAddMaterial(key, materialString); } rs.close(); rs = smt.executeQuery("SELECT id, name FROM `lb-blockstates`"); while (rs.next()) { int key = rs.getInt(1); String materialString = rs.getString(2); - - blockStateToID.put(materialString, key); - int length = idToBlockState.length; - while (length <= key) { - length = (length * 3 / 2) + 5; - } - if (length > idToBlockState.length) { - idToBlockState = Arrays.copyOf(idToBlockState, length); - } - idToBlockState[key] = materialString; - if (nextBlockStateId <= key) { - nextBlockStateId = key + 1; - } + internalAddBlockState(key, materialString); } rs.close(); smt.close(); connection.close(); } + + private synchronized static void internalAddMaterial(int key, String materialString) { + materialToID.put(materialString, key); + int length = idToMaterial.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToMaterial.length) { + idToMaterial = Arrays.copyOf(idToMaterial, length); + } + idToMaterial[key] = materialString; + if (nextMaterialId <= key) { + nextMaterialId = key + 1; + } + } + + private synchronized static void internalAddBlockState(int key, String materialString) { + blockStateToID.put(materialString, key); + int length = idToBlockState.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToBlockState.length) { + idToBlockState = Arrays.copyOf(idToBlockState, length); + } + idToBlockState[key] = materialString; + if (nextBlockStateId <= key) { + nextBlockStateId = key + 1; + } + } } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index d54bcb6..34822b1 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -47,9 +47,9 @@ class Updater { logblock.saveConfig(); } ComparableVersion configVersion = new ComparableVersion(versionString); - if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) { - return false; - } + // if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) { + // return false; + // } if (configVersion.compareTo(new ComparableVersion("1.2.7")) < 0) { logblock.getLogger().info("Updating tables to 1.2.7 ..."); if (isLogging(Logging.CHAT)) { @@ -623,7 +623,7 @@ class Updater { } config.set("version", "1.13.0"); } - + if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) { logblock.getLogger().info("Updating tables to 1.13.1 ..."); try { @@ -717,6 +717,8 @@ class Updater { if (isLogging(Logging.CHAT)) { checkCharset("lb-chat", "message", st, true); } + createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(250))", st, true); + createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(250))", st, true); st.close(); conn.close(); @@ -729,6 +731,17 @@ class Updater { return true; } + void createIndexIfDoesNotExist(String table, String indexName, String definition, Statement st, boolean silent) throws SQLException { + final ResultSet rs = st.executeQuery("SHOW INDEX FROM `" + table + "` WHERE Key_name = '" + indexName + "'"); + if (!rs.next()) { + st.execute("ALTER TABLE `" + table + "` ADD " + definition); + logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Table modified"); + } else if (!silent) { + logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Already fine, skipping it"); + } + rs.close(); + } + void checkCharset(String table, String column, Statement st, boolean silent) throws SQLException { final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `" + table + "` WHERE field = '" + column + "'"); String charset = "utf8"; @@ -741,6 +754,7 @@ class Updater { } else if (!silent) { logblock.getLogger().info("Table " + table + " already fine, skipping it"); } + rs.close(); } void checkTables() throws SQLException {