Updates to new database system
This commit is contained in:
parent
1a4a83441b
commit
f3c8778ad2
|
@ -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();
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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," +
|
||||||
|
|
|
@ -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, () -> {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue