From b37bf12e7f6739326ecdedd5e46cc4ec260303ad Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Sat, 30 Mar 2019 15:40:31 +0100 Subject: [PATCH] Convert old item metadata to newest version (Fixes #202) --- .../com/Acrobot/ChestShop/Database/Item.java | 2 +- .../ChestShop/Database/Migrations.java | 31 ++++++- .../ChestShop/Metadata/ItemDatabase.java | 89 +++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/Acrobot/ChestShop/Database/Item.java b/src/main/java/com/Acrobot/ChestShop/Database/Item.java index 2055803..3e46882 100644 --- a/src/main/java/com/Acrobot/ChestShop/Database/Item.java +++ b/src/main/java/com/Acrobot/ChestShop/Database/Item.java @@ -14,7 +14,7 @@ public class Item { @DatabaseField(canBeNull = false, generatedId = true) private int id; - @DatabaseField(columnName = "code", canBeNull = false, unique = true) + @DatabaseField(columnName = "code", canBeNull = false, index = true) private String base64ItemCode; public Item() { diff --git a/src/main/java/com/Acrobot/ChestShop/Database/Migrations.java b/src/main/java/com/Acrobot/ChestShop/Database/Migrations.java index 5fde854..2f8204f 100644 --- a/src/main/java/com/Acrobot/ChestShop/Database/Migrations.java +++ b/src/main/java/com/Acrobot/ChestShop/Database/Migrations.java @@ -17,7 +17,7 @@ import java.util.logging.Level; * @author Andrzej Pomirski */ public class Migrations { - public static final int CURRENT_DATABASE_VERSION = 3; + public static final int CURRENT_DATABASE_VERSION = 4; /** * Migrates a database from the given version @@ -46,6 +46,12 @@ public class Migrations { return -1; } case 3: + if (migrateTo4()) { + currentVersion++; + } else { + return -1; + } + case 4: default: break; //do nothing @@ -120,4 +126,27 @@ public class Migrations { return false; } } + + private static boolean migrateTo4() { + try { + Dao itemsOld = DaoCreator.getDao(Item.class); + + itemsOld.executeRawNoArgs("ALTER TABLE `items` RENAME TO `items-old`"); + + Dao items = DaoCreator.getDaoAndCreateTable(Item.class); + + long start = System.currentTimeMillis(); + try { + items.executeRawNoArgs("INSERT INTO `items` (id, code) SELECT id, code uuid FROM `items-old`"); + } catch (SQLException e) { + e.printStackTrace(); + } + ChestShop.getBukkitLogger().log(Level.INFO, "Migration of items table finished in " + (System.currentTimeMillis() - start) / 1000.0 + "s!"); + + return true; + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } } diff --git a/src/main/java/com/Acrobot/ChestShop/Metadata/ItemDatabase.java b/src/main/java/com/Acrobot/ChestShop/Metadata/ItemDatabase.java index e226e3d..7ec1715 100644 --- a/src/main/java/com/Acrobot/ChestShop/Metadata/ItemDatabase.java +++ b/src/main/java/com/Acrobot/ChestShop/Metadata/ItemDatabase.java @@ -2,18 +2,29 @@ package com.Acrobot.ChestShop.Metadata; import com.Acrobot.Breeze.Utils.Encoding.Base62; import com.Acrobot.Breeze.Utils.Encoding.Base64; +import com.Acrobot.ChestShop.ChestShop; import com.Acrobot.ChestShop.Database.DaoCreator; import com.Acrobot.ChestShop.Database.Item; +import com.j256.ormlite.dao.CloseableIterator; import com.j256.ormlite.dao.Dao; +import org.bukkit.Material; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConstructor; import org.bukkit.configuration.file.YamlRepresenter; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.nodes.Tag; +import java.io.File; import java.io.IOException; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; /** * Saves items with Metadata in database, which allows for saving items on signs easily. @@ -30,11 +41,89 @@ public class ItemDatabase { try { itemDao = DaoCreator.getDaoAndCreateTable(Item.class); + handleMetadataUpdate(); } catch (SQLException e) { e.printStackTrace(); } } + private void handleMetadataUpdate() { + File configFile = ChestShop.loadFile("version"); + YamlConfiguration versionConfig = YamlConfiguration.loadConfiguration(configFile); + + int previousVersion = versionConfig.getInt("metadata-version", -1); + int newVersion = getCurrentMetadataVersion(); + if (previousVersion < newVersion) { + if (updateMetadataVersion(previousVersion, newVersion)) { + versionConfig.set("metadata-version", newVersion); + try { + versionConfig.save(configFile); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + ChestShop.getBukkitLogger().log(Level.WARNING, "Error while updating Item Metadata database! While the plugin will still run it will work less efficiently."); + } + } + } + + private int getCurrentMetadataVersion() { + ItemStack item = new ItemStack(Material.STONE); + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName("GetCurrentMetadataVersion"); + item.setItemMeta(meta); + Map serialized = item.serialize(); + return (int) serialized.getOrDefault("v", -1); + } + + private boolean updateMetadataVersion(int previousVersion, int newVersion) { + if (previousVersion > -1) { + ChestShop.getBukkitLogger().info("Data version change detected! Previous version was " + previousVersion); + } + ChestShop.getBukkitLogger().info("Updating Item Metadata database to data version " + newVersion + "..."); + + AtomicInteger i = new AtomicInteger(); + AtomicInteger updated = new AtomicInteger(); + CloseableIterator it = itemDao.iterator(); + List toUpdate = new ArrayList<>(); + + long start = System.currentTimeMillis(); + try { + itemDao.callBatchTasks(() -> { + while (it.hasNext()) { + i.getAndIncrement(); + Item item = it.next(); + + try { + String serialized = (String) Base64.decodeToObject(item.getBase64ItemCode()); + if (previousVersion < 0 || !serialized.contains("\nv: " + newVersion + "\n")) { // Hacky way to quickly check the version as it's not too big of an issue if some items don't convert + ItemStack itemStack = yaml.loadAs(serialized, ItemStack.class); + item.setBase64ItemCode(Base64.encodeObject(yaml.dump(itemStack))); + toUpdate.add(item); + itemDao.update(item); + updated.getAndIncrement(); + } + } catch (IOException | ClassNotFoundException | SQLException e) { + e.printStackTrace(); + } + if (i.get() % 1000 == 0) { + ChestShop.getBukkitLogger().info("Checked " + i + " items. Updated " + updated + "..."); + } + } + return true; + }); + } catch (Exception e) { + e.printStackTrace(); + return false; + } finally { + it.closeQuietly(); + } + + ChestShop.getBukkitLogger().info("Finished updating database in " + (System.currentTimeMillis() - start) / 1000.0 + "s. " + + toUpdate.size() + " items out of " + i + " were updated!"); + return true; + } + /** * Gets the item code for this item *