Updates to new database system

This commit is contained in:
ceze88 2023-08-02 17:20:52 +02:00
parent 1a4a83441b
commit f3c8778ad2
9 changed files with 253 additions and 289 deletions

View File

@ -1,5 +1,6 @@
package com.craftaro.epicanchors.api; package com.craftaro.epicanchors.api;
import com.craftaro.core.database.Data;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
@ -7,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.UUID; import java.util.UUID;
public interface Anchor { public interface Anchor extends Data {
int getDbId(); int getDbId();
UUID getOwner(); UUID getOwner();

View File

@ -1,5 +1,7 @@
package com.craftaro.epicanchors; package com.craftaro.epicanchors;
import com.craftaro.core.database.Data;
import com.craftaro.core.database.SerializedLocation;
import com.craftaro.epicanchors.api.Anchor; import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.utils.WorldUtils; import com.craftaro.epicanchors.utils.WorldUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -10,6 +12,8 @@ import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@ -21,6 +25,15 @@ public class AnchorImpl implements Anchor {
private final Location location; private final Location location;
private int ticksLeft; private int ticksLeft;
/**
* Default constructor for deserialization.
*/
public AnchorImpl() {
dbId = 0;
owner = null;
location = null;
}
public AnchorImpl(int dbId, @Nullable UUID owner, @NotNull Location location, int ticksLeft) { public AnchorImpl(int dbId, @Nullable UUID owner, @NotNull Location location, int ticksLeft) {
if (dbId <= 0) throw new IllegalArgumentException("Invalid value for dbId"); if (dbId <= 0) throw new IllegalArgumentException("Invalid value for dbId");
if (ticksLeft <= 0 && ticksLeft != -1) throw new IllegalArgumentException("Invalid value for ticksLeft"); if (ticksLeft <= 0 && ticksLeft != -1) throw new IllegalArgumentException("Invalid value for ticksLeft");
@ -137,4 +150,29 @@ public class AnchorImpl implements Anchor {
public boolean isInfinite() { public boolean isInfinite() {
return this.ticksLeft == -1; return this.ticksLeft == -1;
} }
@Override
public Map<String, Object> serialize() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("id", dbId);
map.putAll(SerializedLocation.of(location));
map.put("ticks_left", ticksLeft);
map.put("owner", owner == null ? null : owner.toString());
return map;
}
@Override
public Data deserialize(Map<String, Object> map) {
return new AnchorImpl(
(int) map.get("id"),
map.get("owner") == null ? null : UUID.fromString((String) map.get("owner")),
SerializedLocation.of(map),
(int) map.get("ticks_left")
);
}
@Override
public String getTableName() {
return "anchors";
}
} }

View File

@ -3,6 +3,8 @@ package com.craftaro.epicanchors;
import com.craftaro.core.SongodaPlugin; import com.craftaro.core.SongodaPlugin;
import com.craftaro.core.compatibility.CompatibleMaterial; import com.craftaro.core.compatibility.CompatibleMaterial;
import com.craftaro.core.compatibility.CompatibleParticleHandler; import com.craftaro.core.compatibility.CompatibleParticleHandler;
import com.craftaro.core.database.Data;
import com.craftaro.core.database.DataManager;
import com.craftaro.core.hooks.HologramManager; import com.craftaro.core.hooks.HologramManager;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial; import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XSound; import com.craftaro.core.third_party.com.cryptomorin.xseries.XSound;
@ -12,9 +14,9 @@ import com.craftaro.core.utils.TimeUtils;
import com.craftaro.epicanchors.api.Anchor; import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.api.AnchorAccessCheck; import com.craftaro.epicanchors.api.AnchorAccessCheck;
import com.craftaro.epicanchors.api.AnchorManager; import com.craftaro.epicanchors.api.AnchorManager;
import com.craftaro.epicanchors.files.DataManager;
import com.craftaro.epicanchors.files.Settings; import com.craftaro.epicanchors.files.Settings;
import com.craftaro.epicanchors.utils.Callback; import com.craftaro.epicanchors.utils.Callback;
import com.craftaro.epicanchors.utils.DataHelper;
import com.craftaro.epicanchors.utils.UpdateCallback; import com.craftaro.epicanchors.utils.UpdateCallback;
import com.craftaro.epicanchors.utils.Utils; import com.craftaro.epicanchors.utils.Utils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -31,6 +33,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -62,7 +65,8 @@ public class AnchorManagerImpl implements AnchorManager {
protected void saveAll() { protected void saveAll() {
for (Set<Anchor> anchorSet : this.anchors.values()) { for (Set<Anchor> anchorSet : this.anchors.values()) {
this.dataManager.updateAnchors(anchorSet, null); Collection<Data> asData = new ArrayList<>(anchorSet.size());
this.dataManager.saveBatch(asData);
} }
} }
@ -83,7 +87,7 @@ public class AnchorManagerImpl implements AnchorManager {
long start = System.nanoTime(); long start = System.nanoTime();
this.dataManager.getAnchors(world, (ex, result) -> { DataHelper.getAnchors(world, (ex, result) -> {
if (ex == null) { if (ex == null) {
this.anchors.computeIfAbsent(world, key -> new HashSet<>()); this.anchors.computeIfAbsent(world, key -> new HashSet<>());
@ -114,8 +118,10 @@ public class AnchorManagerImpl implements AnchorManager {
protected void deInitAnchors(@NotNull World world) { protected void deInitAnchors(@NotNull World world) {
Set<Anchor> tmpAnchors = this.anchors.remove(world); Set<Anchor> tmpAnchors = this.anchors.remove(world);
if (tmpAnchors != null) { if (tmpAnchors != null) {
this.dataManager.updateAnchors(tmpAnchors, null); Collection<Data> asData = new ArrayList<>(tmpAnchors.size());
this.dataManager.saveBatch(asData);
for (Anchor anchor : tmpAnchors) { for (Anchor anchor : tmpAnchors) {
((AnchorImpl) anchor).deInit(this.plugin); ((AnchorImpl) anchor).deInit(this.plugin);
@ -229,27 +235,19 @@ public class AnchorManagerImpl implements AnchorManager {
throw new IllegalStateException(ERR_WORLD_NOT_READY); throw new IllegalStateException(ERR_WORLD_NOT_READY);
} }
this.dataManager.insertAnchorAsync(loc, Objects.requireNonNull(owner), ticks, (ex, anchor) -> { Anchor anchor = new AnchorImpl(dataManager.getNextId("anchors"), owner, loc, ticks);
if (ex != null) { this.dataManager.save(anchor);
if (callback != null) { Bukkit.getScheduler().runTask(this.plugin, () -> { //TODO: Do we need to run this sync, or we are already on the main thread?
callback.accept(ex, null); Block block = loc.getBlock();
} else { block.setType(Settings.MATERIAL.getMaterial().parseMaterial());
Utils.logException(this.plugin, ex, "SQLite");
}
} else {
Bukkit.getScheduler().runTask(this.plugin, () -> {
Block block = loc.getBlock();
block.setType(Settings.MATERIAL.getMaterial().parseMaterial());
this.anchors.computeIfAbsent(anchor.getWorld(), key -> new HashSet<>()) this.anchors.computeIfAbsent(anchor.getWorld(), key -> new HashSet<>())
.add(anchor); .add(anchor);
updateHologram(anchor); updateHologram(anchor);
if (callback != null) { if (callback != null) {
callback.accept(null, anchor); callback.accept(null, anchor);
}
});
} }
}); });
} }
@ -292,7 +290,7 @@ public class AnchorManagerImpl implements AnchorManager {
anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5); anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5);
((AnchorImpl) anchor).deInit(this.plugin); ((AnchorImpl) anchor).deInit(this.plugin);
this.dataManager.deleteAnchorAsync(anchor); this.dataManager.delete(anchor);
} }
/* Anchor access */ /* Anchor access */

View File

@ -30,6 +30,7 @@ import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@ -38,8 +39,6 @@ public final class EpicAnchors extends SongodaPlugin {
private GuiManager guiManager; private GuiManager guiManager;
private AnchorManagerImpl anchorManager; private AnchorManagerImpl anchorManager;
private DataManager dataManager;
@Override @Override
public void onPluginLoad() { public void onPluginLoad() {
} }
@ -49,13 +48,15 @@ public final class EpicAnchors extends SongodaPlugin {
SongodaCore.registerPlugin(this, 31, XMaterial.END_PORTAL_FRAME); SongodaCore.registerPlugin(this, 31, XMaterial.END_PORTAL_FRAME);
// Initialize database // Initialize database
this.getLogger().info("Initializing SQLite..."); // this.getLogger().info("Initializing SQLite...");
DatabaseConnector dbCon = new SQLiteConnector(this); // DatabaseConnector dbCon = new SQLiteConnector(this);
this.dataManager = new DataManager(dbCon, this); // this.dataManager = new DataManager(dbCon, this);
AnchorMigration anchorMigration = new AnchorMigration(dbCon, this.dataManager, new _1_InitialMigration()); // AnchorMigration anchorMigration = new AnchorMigration(dbCon, this.dataManager, new _1_InitialMigration());
anchorMigration.runMigrations(); // anchorMigration.runMigrations();
// anchorMigration.migrateLegacyData(this);
initDatabase(Arrays.asList(new _1_InitialMigration(), new AnchorMigration()));
anchorMigration.migrateLegacyData(this);
this.anchorManager = new AnchorManagerImpl(this, this.dataManager); this.anchorManager = new AnchorManagerImpl(this, this.dataManager);
EpicAnchorsApi.initApi(this.anchorManager); EpicAnchorsApi.initApi(this.anchorManager);
@ -100,7 +101,7 @@ public final class EpicAnchors extends SongodaPlugin {
if (this.dataManager != null) { if (this.dataManager != null) {
this.anchorManager.deInitAll(); this.anchorManager.deInitAll();
this.dataManager.close(); this.dataManager.shutdown();
} }
// Remove all holograms // Remove all holograms

View File

@ -1,6 +1,5 @@
package com.craftaro.epicanchors.files; package com.craftaro.epicanchors.files;
import com.craftaro.core.database.DataManagerAbstract;
import com.craftaro.core.database.DatabaseConnector; import com.craftaro.core.database.DatabaseConnector;
import com.craftaro.epicanchors.AnchorImpl; import com.craftaro.epicanchors.AnchorImpl;
import com.craftaro.epicanchors.api.Anchor; import com.craftaro.epicanchors.api.Anchor;
@ -28,248 +27,71 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class DataManager extends DataManagerAbstract { public class DataManager {
private final ExecutorService thread = Executors.newSingleThreadExecutor();
private final String anchorTable;
public DataManager(DatabaseConnector databaseConnector, Plugin plugin) {
super(databaseConnector, plugin);
this.anchorTable = getTableName(super.getTablePrefix(), "anchors"); // public void updateAnchors(Collection<Anchor> anchors, UpdateCallback callback) {
} // this.databaseConnector.connect((con) -> {
// con.setAutoCommit(false);
public void close() { //
if (!this.thread.isShutdown()) { // SQLException err = null;
this.thread.shutdown(); //
// for (Anchor anchor : anchors) {
try { // try (PreparedStatement ps = con.prepareStatement("UPDATE " + this.anchorTable +
if (!this.thread.awaitTermination(60, TimeUnit.SECONDS)) { // " SET ticks_left =? WHERE id =?;")) {
// Try stopping the thread forcefully (there is basically no hope left for the data) // ps.setInt(1, anchor.getTicksLeft());
this.thread.shutdownNow(); // ps.setInt(2, anchor.getDbId());
} //
} catch (InterruptedException ex) { // ps.executeUpdate();
Utils.logException(super.plugin, ex); // } catch (SQLException ex) {
} // err = ex;
// break;
this.databaseConnector.closeConnection(); // }
} // }
} //
// if (err == null) {
public void exists(@NotNull String worldName, int x, int y, int z, @NotNull Callback<Boolean> callback) { // con.commit();
this.databaseConnector.connect((con) -> { //
try (PreparedStatement ps = con.prepareStatement("SELECT id FROM " + this.anchorTable + // resolveUpdateCallback(callback, null);
" WHERE world_name =? AND x =? AND y =? AND z=?;")) { // } else {
ps.setString(1, worldName); // con.rollback();
ps.setInt(2, x); //
ps.setInt(3, y); // resolveUpdateCallback(callback, err);
ps.setInt(4, z); // }
//
ResultSet rs = ps.executeQuery(); // con.setAutoCommit(true);
// });
callback.accept(null, rs.next()); // }
} catch (Exception ex) { //
resolveCallback(callback, ex); // public void deleteAnchorAsync(Anchor anchor) {
} // deleteAnchorAsync(anchor, null);
}); // }
} //
// public void deleteAnchorAsync(Anchor anchor, UpdateCallback callback) {
public void getAnchors(@Nullable World world, @NotNull Callback<List<Anchor>> callback) { // this.thread.execute(() ->
List<Anchor> result = new ArrayList<>(); // this.databaseConnector.connect((con) -> {
// try (PreparedStatement ps = con.prepareStatement("DELETE FROM " + this.anchorTable +
this.databaseConnector.connect((con) -> { // " WHERE id =?;")) {
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM " + this.anchorTable + // ps.setInt(1, anchor.getDbId());
(world != null ? " WHERE world_name =?" : "") + ";")) { //
if (world != null) { // ps.executeUpdate();
ps.setString(1, world.getName()); //
} // resolveUpdateCallback(callback, null);
// } catch (Exception ex) {
ResultSet rs = ps.executeQuery(); // resolveUpdateCallback(callback, ex);
// }
while (rs.next()) { // })
result.add(extractAnchor(rs)); // );
} // }
//
callback.accept(null, result); // public static String getTableName(String prefix, String name) {
} catch (Exception ex) { // String result = prefix + name;
resolveCallback(callback, ex); //
} // if (!result.matches("[a-z0-9_]+")) {
}); // throw new IllegalStateException("The generated table name '" + result + "' contains invalid characters");
} // }
//
public void insertAnchorAsync(Location loc, UUID owner, int ticks, Callback<Anchor> callback) { // return result;
this.thread.execute(() -> insertAnchor(loc, owner, ticks, callback)); // }
}
public void insertAnchor(Location loc, UUID owner, int ticks, Callback<Anchor> callback) {
this.databaseConnector.connect((con) -> {
try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + this.anchorTable +
"(owner, world_name,x,y,z, ticks_left) VALUES (?,?,?,?,?, ?);");// Future SQLite version might support 'RETURNING *'
PreparedStatement psFetch = con.prepareStatement("SELECT * FROM " + this.anchorTable +
" WHERE world_name =? AND x =? AND y =? AND z=?;")) {
ps.setString(1, owner != null ? owner.toString() : null);
ps.setString(2, Objects.requireNonNull(loc.getWorld()).getName());
psFetch.setString(1, Objects.requireNonNull(loc.getWorld()).getName());
ps.setInt(3, loc.getBlockX());
psFetch.setInt(2, loc.getBlockX());
ps.setInt(4, loc.getBlockY());
psFetch.setInt(3, loc.getBlockY());
ps.setInt(5, loc.getBlockZ());
psFetch.setInt(4, loc.getBlockZ());
ps.setInt(6, ticks);
ps.executeUpdate();
if (callback != null) {
ResultSet rs = psFetch.executeQuery();
rs.next();
callback.accept(null, extractAnchor(rs));
}
} catch (Exception ex) {
resolveCallback(callback, ex);
}
});
}
public void migrateAnchor(List<AnchorMigration.LegacyAnchorEntry> anchorEntries, UpdateCallback callback) {
this.databaseConnector.connect((con) -> {
con.setAutoCommit(false);
SQLException err = null;
try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + this.anchorTable +
"(world_name,x,y,z, ticks_left) VALUES (?,?,?,?, ?);")) {
for (AnchorMigration.LegacyAnchorEntry entry : anchorEntries) {
ps.setString(1, entry.worldName);
ps.setInt(2, entry.x);
ps.setInt(3, entry.y);
ps.setInt(4, entry.z);
ps.setInt(5, entry.ticksLeft);
ps.addBatch();
}
int[] batchRes = ps.executeBatch();
for (int i : batchRes) {
if (i < 0 && i != Statement.SUCCESS_NO_INFO) {
throw new AssertionError("Batch-INSERT failed for at least one statement with code " + i);
}
}
} catch (SQLException ex) {
err = ex;
}
if (err == null) {
con.commit();
resolveUpdateCallback(callback, null);
} else {
con.rollback();
resolveUpdateCallback(callback, err);
}
con.setAutoCommit(true);
});
}
public void updateAnchors(Collection<Anchor> anchors, UpdateCallback callback) {
this.databaseConnector.connect((con) -> {
con.setAutoCommit(false);
SQLException err = null;
for (Anchor anchor : anchors) {
try (PreparedStatement ps = con.prepareStatement("UPDATE " + this.anchorTable +
" SET ticks_left =? WHERE id =?;")) {
ps.setInt(1, anchor.getTicksLeft());
ps.setInt(2, anchor.getDbId());
ps.executeUpdate();
} catch (SQLException ex) {
err = ex;
break;
}
}
if (err == null) {
con.commit();
resolveUpdateCallback(callback, null);
} else {
con.rollback();
resolveUpdateCallback(callback, err);
}
con.setAutoCommit(true);
});
}
public void deleteAnchorAsync(Anchor anchor) {
deleteAnchorAsync(anchor, null);
}
public void deleteAnchorAsync(Anchor anchor, UpdateCallback callback) {
this.thread.execute(() ->
this.databaseConnector.connect((con) -> {
try (PreparedStatement ps = con.prepareStatement("DELETE FROM " + this.anchorTable +
" WHERE id =?;")) {
ps.setInt(1, anchor.getDbId());
ps.executeUpdate();
resolveUpdateCallback(callback, null);
} catch (Exception ex) {
resolveUpdateCallback(callback, ex);
}
})
);
}
public static String getTableName(String prefix, String name) {
String result = prefix + name;
if (!result.matches("[a-z0-9_]+")) {
throw new IllegalStateException("The generated table name '" + result + "' contains invalid characters");
}
return result;
}
private Anchor extractAnchor(ResultSet rs) throws SQLException {
String ownerStr = rs.getString("owner");
return new AnchorImpl(rs.getInt("id"),
ownerStr != null ? UUID.fromString(ownerStr) : null,
new Location(Bukkit.getWorld(rs.getString("world_name")),
rs.getInt("x"),
rs.getInt("y"),
rs.getInt("z")),
rs.getInt("ticks_left"));
}
private void resolveUpdateCallback(@Nullable UpdateCallback callback, @Nullable Exception ex) {
if (callback != null) {
callback.accept(ex);
} else if (ex != null) {
Utils.logException(this.plugin, ex, "SQLite");
}
}
private void resolveCallback(@Nullable Callback<?> callback, @NotNull Exception ex) {
if (callback != null) {
callback.accept(ex, null);
} else {
Utils.logException(this.plugin, ex, "SQLite");
}
}
} }

View File

@ -3,31 +3,32 @@ package com.craftaro.epicanchors.files.migration;
import com.craftaro.core.configuration.Config; import com.craftaro.core.configuration.Config;
import com.craftaro.core.configuration.ConfigSection; import com.craftaro.core.configuration.ConfigSection;
import com.craftaro.core.database.DataMigration; import com.craftaro.core.database.DataMigration;
import com.craftaro.core.database.DataMigrationManager;
import com.craftaro.core.database.DatabaseConnector; import com.craftaro.core.database.DatabaseConnector;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.files.DataManager; import com.craftaro.epicanchors.files.DataManager;
import com.craftaro.epicanchors.utils.DataHelper;
import com.craftaro.epicanchors.utils.ThreadSync; import com.craftaro.epicanchors.utils.ThreadSync;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.sql.Connection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
public class AnchorMigration extends DataMigrationManager { public class AnchorMigration extends DataMigration {
private final DataManager dataManager;
public AnchorMigration(DatabaseConnector databaseConnector, DataManager dataManager, DataMigration... migrations) { public AnchorMigration() {
super(databaseConnector, dataManager, migrations); super(2);
this.dataManager = dataManager;
} }
public void migrateLegacyData(Plugin plugin) { @Override
public void migrate(DatabaseConnector databaseConnector, String tablePrefix) {
Plugin plugin = EpicAnchors.getPlugin(EpicAnchors.class);
long start = System.nanoTime(); long start = System.nanoTime();
AtomicBoolean abortMigration = new AtomicBoolean(false); AtomicBoolean abortMigration = new AtomicBoolean(false);
@ -67,7 +68,7 @@ public class AnchorMigration extends DataMigrationManager {
int z = Location.locToBlock(Double.parseDouble(locArgs[3])); int z = Location.locToBlock(Double.parseDouble(locArgs[3]));
int finalTicksLeft = ticksLeft; int finalTicksLeft = ticksLeft;
this.dataManager.exists(worldName, x, y, z, (ex, anchorExists) -> { DataHelper.exists(worldName, x, y, z, (ex, anchorExists) -> {
if (ex == null) { if (ex == null) {
if (anchorExists) { if (anchorExists) {
cfgSection.set(locationStr, null); cfgSection.set(locationStr, null);
@ -94,7 +95,7 @@ public class AnchorMigration extends DataMigrationManager {
if (!abortMigration.get()) { if (!abortMigration.get()) {
int finalMigratedAnchors = migratedAnchors; int finalMigratedAnchors = migratedAnchors;
this.dataManager.migrateAnchor(anchorQueue, ex -> { DataHelper.migrateAnchor(anchorQueue, ex -> {
long end = System.nanoTime(); long end = System.nanoTime();
if (ex == null) { if (ex == null) {

View File

@ -1,6 +1,8 @@
package com.craftaro.epicanchors.files.migration; package com.craftaro.epicanchors.files.migration;
import com.craftaro.core.database.DataMigration; import com.craftaro.core.database.DataMigration;
import com.craftaro.core.database.DatabaseConnector;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.files.DataManager; import com.craftaro.epicanchors.files.DataManager;
import java.sql.Connection; import java.sql.Connection;
@ -13,9 +15,9 @@ public class _1_InitialMigration extends DataMigration {
} }
@Override @Override
public void migrate(Connection connection, String tablePrefix) throws SQLException { public void migrate(DatabaseConnector databaseConnector, String tablePrefix) throws SQLException {
try (Statement statement = connection.createStatement()) { try (Statement statement = databaseConnector.getConnection().createStatement()) {
statement.execute("CREATE TABLE " + DataManager.getTableName(tablePrefix, "anchors") + "(" + statement.execute("CREATE TABLE " + EpicAnchors.getPlugin(EpicAnchors.class).getDataManager().getTablePrefix() + "anchors (" +
"id INTEGER NOT NULL," + "id INTEGER NOT NULL," +
"world_name TEXT NOT NULL," + "world_name TEXT NOT NULL," +
"x INTEGER NOT NULL," + "x INTEGER NOT NULL," +

View File

@ -49,7 +49,7 @@ public class AnchorListener implements Listener {
this.plugin.getAnchorManager().createAnchor(e.getBlock().getLocation(), e.getPlayer().getUniqueId(), ticksLeft, this.plugin.getAnchorManager().createAnchor(e.getBlock().getLocation(), e.getPlayer().getUniqueId(), ticksLeft,
(ex, result) -> { (ex, result) -> {
if (ex != null) { if (ex != null) {
Utils.logException(this.plugin, ex, "SQLite"); Utils.logException(this.plugin, ex, "SQL");
e.getPlayer().sendMessage("Error creating anchor!"); // TODO e.getPlayer().sendMessage("Error creating anchor!"); // TODO
Bukkit.getScheduler().runTask(this.plugin, () -> { Bukkit.getScheduler().runTask(this.plugin, () -> {

View File

@ -0,0 +1,101 @@
package com.craftaro.epicanchors.utils;
import com.craftaro.core.database.Data;
import com.craftaro.core.database.DataManager;
import com.craftaro.core.third_party.org.jooq.Queries;
import com.craftaro.core.third_party.org.jooq.Query;
import com.craftaro.core.third_party.org.jooq.Record1;
import com.craftaro.core.third_party.org.jooq.Result;
import com.craftaro.core.third_party.org.jooq.impl.DSL;
import com.craftaro.epicanchors.AnchorImpl;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.files.migration.AnchorMigration;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class DataHelper {
public static void exists(@NotNull String worldName, int x, int y, int z, @NotNull Callback<Boolean> callback) {
DataManager dataManager = EpicAnchors.getPlugin(EpicAnchors.class).getDataManager();
dataManager.getDatabaseConnector().connectDSL(dslContext -> {
try {
@NotNull Result<Record1<Object>> result = dslContext.select(DSL.field("id")).from(DSL.table(dataManager.getTablePrefix() + "anchors"))
.where(DSL.field("world_name").eq(worldName))
.and(DSL.field("x").eq(x))
.and(DSL.field("y").eq(y))
.and(DSL.field("z").eq(z)).fetch();
callback.accept(null, result.size() > 0);
} catch (Exception ex) {
resolveCallback(callback, ex);
}
});
}
public static void getAnchors(@Nullable World world, @NotNull Callback<List<Anchor>> callback) {
try {
callback.accept(null, EpicAnchors.getPlugin(EpicAnchors.class).getDataManager().loadBatch(AnchorImpl.class, "anchors"));
} catch (Exception ex) {
resolveCallback(callback, ex);
}
}
private static void resolveUpdateCallback(@Nullable UpdateCallback callback, @Nullable Exception ex) {
if (callback != null) {
callback.accept(ex);
} else if (ex != null) {
Utils.logException(EpicAnchors.getPlugin(EpicAnchors.class), ex, "SQL");
}
}
private static void resolveCallback(@Nullable Callback<?> callback, @NotNull Exception ex) {
if (callback != null) {
callback.accept(ex, null);
} else {
Utils.logException(EpicAnchors.getPlugin(EpicAnchors.class), ex, "SQL");
}
}
public static void migrateAnchor(List<AnchorMigration.LegacyAnchorEntry> anchorQueue, UpdateCallback callback) {
DataManager dataManager = EpicAnchors.getPlugin(EpicAnchors.class).getDataManager();
//recreate it with Jooq
dataManager.getDatabaseConnector().connectDSL(dslContext -> {
Connection connection = dslContext.configuration().connectionProvider().acquire();
connection.setAutoCommit(false);
try {
List<Query> queries = new ArrayList<>();
for (AnchorMigration.LegacyAnchorEntry entry : anchorQueue) {
queries.add(dslContext.insertInto(DSL.table(dataManager.getTablePrefix() + "anchors"))
.columns(
DSL.field("world_name"),
DSL.field("x"),
DSL.field("y"),
DSL.field("z"),
DSL.field("ticks_left"))
.values(entry.worldName, entry.x, entry.y, entry.z, entry.ticksLeft));
}
dslContext.batch(queries).execute();
connection.commit();
} catch (Exception ex) {
connection.rollback();
resolveUpdateCallback(callback, ex);
} finally {
connection.setAutoCommit(true);
dslContext.configuration().connectionProvider().release(connection);
}
});
}
}