Starting to implement async in db actions

This commit is contained in:
anthorob committed 2020-01-08 20:30:20 -05:00
1 parent 35290a83da
commit 5ae7e8f819
8 files changed
+188 -77

No files matched your search

@@ -18,19 +18,19 @@ public class ThreadManager {
public static void shutdownExecutor() { public static void shutdownExecutor() {
try { try {
System.out.println("[Executor] Shutting down..."); MusicBot.LOGGER.info("[Executor] Shutting down...");
executor.shutdown(); executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS); executor.awaitTermination(5, TimeUnit.SECONDS);
} }
catch (InterruptedException e) { catch (InterruptedException e) {
System.err.println("[Executor] Running tasks interrupted"); MusicBot.LOGGER.warn("[Executor] Running tasks interrupted");
} }
finally { finally {
if (!executor.isTerminated()) { if (!executor.isTerminated()) {
System.err.println("[Executor] Forcing shutdown of running tasks.."); MusicBot.LOGGER.warn("[Executor] Forcing shutdown of running tasks..");
} }
executor.shutdownNow(); executor.shutdownNow();
System.out.println("[Executor] Shutdown finished!"); MusicBot.LOGGER.info("[Executor] Shutdown finished!");
} }
} }
} }
@@ -48,7 +48,7 @@ public class BlacklistCommand extends AbstractCommand {
switch (parseArgs(args, 0)) { switch (parseArgs(args, 0)) {
case "get": case "get":
event.getTextChannel().sendMessage("Retreiving list, please wait...").queue(t -> { event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> {
try { try {
@@ -0,0 +1,87 @@
package netneutrality.db;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import netneutrality.MusicBot;
import netneutrality.ThreadManager;
import netneutrality.db.models.MTableModel;
import java.sql.ResultSet;
import java.util.function.Consumer;
public class AsyncMySqlAction {
private String sqlString;
private Object[] params;
private MysqlDatabase.CommandType type;
private MysqlDatabase db;
public AsyncMySqlAction(MysqlDatabase db, String sql, Object... params) {
this.db = db;
this.sqlString = sql;
this.params = params;
type = MysqlDatabase.CommandType.stringToType(sqlString.toUpperCase().split(" ")[0]);
}
public void async(Consumer<MTableModel> success) {
switch (type) {
case INSERT:
ThreadManager.executor.submit(() -> {
db.insert(this.sqlString, this.params);
});
break;
case UPDATE:
ThreadManager.executor.submit(() -> {
db.update(this.sqlString, this.params);
});
break;
case DELETE:
ThreadManager.executor.submit(() -> {
db.delete(this.sqlString, this.params);
});
break;
case SELECT:
ThreadManager.executor.submit(() -> {
ResultSet result = db.prepareAndExecute(this.sqlString, this.params);
MTableModel table = MysqlDatabase.convertToTableModel(result);
success.accept(table);
});
break;
}
}
public void async() {
async(o -> {
});
}
public MTableModel blocking() {
switch (type) {
case INSERT:
db.insert(this.sqlString, this.params);
case UPDATE:
db.update(this.sqlString, this.params);
case DELETE:
db.delete(this.sqlString, this.params);
case SELECT:
ResultSet result = db.prepareAndExecute(this.sqlString, this.params);
return MysqlDatabase.convertToTableModel(result);
}
return null;
}
}
@@ -13,7 +13,7 @@ import org.reflections.Reflections;
/** /**
* When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class * When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class
* A simple thread can't be used in this case because unpredictable errors might happen and some actions might not be executed. * A simple thread can't be used in this case because overlapping actions might happen and won't be executed.
*/ */
public class DBController { public class DBController {
@@ -23,7 +23,7 @@ public class DBController {
private final static HashMap<String, AbstractController> controllers = new HashMap<>(); private final static HashMap<String, AbstractController> controllers = new HashMap<>();
private static MysqlDatabase database = new MysqlDatabase("discord"); private static MysqlDatabase database = new MysqlDatabase("netneutrality");
/** /**
* @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method * @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method
@@ -9,8 +9,10 @@ import java.sql.Statement;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.sql.Types; import java.sql.Types;
import java.util.Calendar; import java.util.Calendar;
import java.util.function.Consumer;
import netneutrality.MusicBot; import netneutrality.MusicBot;
import netneutrality.ThreadManager;
import netneutrality.db.models.MRowModel; import netneutrality.db.models.MRowModel;
import netneutrality.db.models.MTableModel; import netneutrality.db.models.MTableModel;
import netneutrality.exceptions.UnimplementedParameterException; import netneutrality.exceptions.UnimplementedParameterException;
@@ -18,10 +20,24 @@ import netneutrality.handler.LogHandler;
public class MysqlDatabase { public class MysqlDatabase {
protected enum CommandType {
SELECT("SELECT"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE");
private String type;
CommandType(String type) {
this.type = type;
}
public static CommandType stringToType(String str) {
return CommandType.valueOf(str);
}
}
private Connection connection; private Connection connection;
private String dbName; private String dbName;
MysqlDatabase(String dbName) { protected MysqlDatabase(String dbName) {
this.dbName = dbName; this.dbName = dbName;
try { try {
MusicBot.LOGGER.info("Connecting to database..."); MusicBot.LOGGER.info("Connecting to database...");
@@ -100,7 +116,6 @@ public class MysqlDatabase {
} }
private int executeUpdate(String sql, Object[] params) { private int executeUpdate(String sql, Object[] params) {
MusicBot.LOGGER.debug("Query: " + sql);
try { try {
PreparedStatement query = connection.prepareStatement(sql); PreparedStatement query = connection.prepareStatement(sql);
@@ -119,7 +134,7 @@ public class MysqlDatabase {
* *
* @param sql The SQL query to execute * @param sql The SQL query to execute
* @param params The parameters to include in the query * @param params The parameters to include in the query
* @return a ResultSet object, which can be converted to an model using {@link MysqlDatabase#convertToTableModel(ResultSet)} * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)}
*/ */
public ResultSet prepareAndExecute(String sql, Object... params) { public ResultSet prepareAndExecute(String sql, Object... params) {
MusicBot.LOGGER.debug("Query: " + sql); MusicBot.LOGGER.debug("Query: " + sql);
@@ -129,12 +144,25 @@ public class MysqlDatabase {
resolveParameters(query, params); resolveParameters(query, params);
return query.executeQuery(); return query.executeQuery();
} catch (SQLException e) { } catch (SQLException e) {
MusicBot.LOGGER.error(e.toString());
e.printStackTrace(); e.printStackTrace();
} }
return null; return null;
} }
/**
* Execute a SELECT statement with the specified parameters.
* In the SQL query, where there is a parameter to be included, you need to replace it with ?
*
* @param sql The SQL query to execute
* @param params The parameters to include in the query
* @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)}
*/
public AsyncMySqlAction prepareAndExecuteAsync(String sql, Object... params) {
return new AsyncMySqlAction(this, sql, params);
}
/** /**
* Insert parameters (specified with a ?) in the SQL statement * Insert parameters (specified with a ?) in the SQL statement
* Taken from https://github.com/Kaaz/DiscordBot/blob/master/src/main/java/emily/db/MySQLAdapter.java#resolveParameters * Taken from https://github.com/Kaaz/DiscordBot/blob/master/src/main/java/emily/db/MySQLAdapter.java#resolveParameters
@@ -182,7 +210,7 @@ public class MysqlDatabase {
* @throws SQLException * @throws SQLException
*/ */
public void close() throws SQLException { public void close() throws SQLException {
System.out.println("Closing database..."); MusicBot.LOGGER.info("Closing database...");
connection.close(); connection.close();
} }
@@ -3,8 +3,10 @@ package netneutrality.db.controllers;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer; import java.util.function.Consumer;
import netneutrality.MusicBot;
import netneutrality.ThreadManager; import netneutrality.ThreadManager;
import netneutrality.db.AbstractController; import netneutrality.db.AbstractController;
import netneutrality.db.DBController; import netneutrality.db.DBController;
@@ -28,26 +30,25 @@ public class DBBlacklist extends AbstractController {
} }
public void add(MBlacklist obj, Consumer<Boolean> success) { public void add(MBlacklist obj, Consumer<Boolean> success) {
ThreadManager.executor.submit(() -> { isAlreadyBlacklisted(obj.getWord(), obj.getServerId(), blacklisted -> {
if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { if (blacklisted == 0) {
database.insert("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()); database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()).async();
success.accept(true); success.accept(true);
} else { } else {
success.accept(false); success.accept(false);
} }
}); });
} }
public void delete(String word, String serverId, Consumer<Boolean> success) { public void delete(String word, String serverId, Consumer<Boolean> success) {
ThreadManager.executor.submit(() -> { isAlreadyBlacklisted(word, serverId, blacklisted -> {
if (isAlreadyBlacklisted(word, serverId)) { if (blacklisted >= 1) {
System.out.println("true"); database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async();
database.delete("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); MusicBot.LOGGER.info("blacklisted");
success.accept(true); success.accept(true);
} else { } else {
MusicBot.LOGGER.info("not blacklisted");
success.accept(false); success.accept(false);
} }
}); });
@@ -56,26 +57,32 @@ public class DBBlacklist extends AbstractController {
public void enable(String word, String serverId, Consumer<Boolean> success) { public void enable(String word, String serverId, Consumer<Boolean> success) {
isAlreadyBlacklisted(word, serverId, blacklisted -> {
ThreadManager.executor.submit(() -> { if (blacklisted >= 1) {
if (isAlreadyBlacklisted(word, serverId)) { database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId).async();
database.update("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId); MusicBot.LOGGER.info("enabled");
success.accept(true); success.accept(true);
} else { } else {
MusicBot.LOGGER.info("error enabling");
success.accept(false); success.accept(false);
} }
}); });
} }
public void disable(String word, String serverId, Consumer<Boolean> success) { public void disable(String word, String serverId, Consumer<Boolean> success) {
ThreadManager.executor.submit(() -> {
if (isAlreadyBlacklisted(word, serverId)) { isAlreadyBlacklisted(word, serverId, blacklisted -> {
database.update("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId); if (blacklisted >= 1) {
database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId).async();
MusicBot.LOGGER.info("disabled");
success.accept(true); success.accept(true);
} else { } else {
MusicBot.LOGGER.info("error disabled");
success.accept(false); success.accept(false);
} }
}); });
} }
public void getBlacklistForWord(String word, String serverId, Consumer<MBlacklist> success) { public void getBlacklistForWord(String word, String serverId, Consumer<MBlacklist> success) {
@@ -84,7 +91,7 @@ public class DBBlacklist extends AbstractController {
if (isAlreadyBlacklisted(word, serverId)) { if (isAlreadyBlacklisted(word, serverId)) {
ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId);
MTableModel table = database.convertToTableModel(rs); MTableModel table = MysqlDatabase.convertToTableModel(rs);
if (table.getNbRows() > 0) { if (table.getNbRows() > 0) {
blacklisted = new MBlacklist((String) table.getRow(0).get(0), (Boolean) table.getRow(0).get(2), (String) table.getRow(0).get(3), blacklisted = new MBlacklist((String) table.getRow(0).get(0), (Boolean) table.getRow(0).get(2), (String) table.getRow(0).get(3),
@@ -98,42 +105,44 @@ public class DBBlacklist extends AbstractController {
} }
public void getBlacklistFromServer(String serverId, Consumer<ArrayList<MBlacklist>> success) { public void getBlacklistFromServer(String serverId, Consumer<ArrayList<MBlacklist>> success) {
ThreadManager.executor.submit(() -> {
database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).async(model -> {
ArrayList<MBlacklist> output = new ArrayList<>(); ArrayList<MBlacklist> output = new ArrayList<>();
try { if (model.getNbRows() != 0) {
ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId); for (int row = 0; row < model.getNbRows(); row++) {
MTableModel model = MysqlDatabase.convertToTableModel(rs); output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3),
(String) model.getRow(row).get(1)));
if (model.getNbRows() != 0) {
for (int row = 0; row < model.getNbRows(); row++) {
output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3),
(String) model.getRow(row).get(1)));
}
} else {
throw new RuntimeException("Blacklist is empty");
} }
}
} catch (NullPointerException | IndexOutOfBoundsException ignored) { }
success.accept(output); success.accept(output);
}); });
} }
public boolean isAlreadyBlacklisted(String word, String serverId) { @Deprecated
ResultSet rs = database.prepareAndExecute("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); private boolean isAlreadyBlacklisted(String word, String serverId) {
AtomicBoolean result = new AtomicBoolean();
try { database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> {
if (rs.next()) { if (!table.isEmpty()) {
return rs.getInt(1) != 0; result.set((int) table.getRowModel(0).getItem(0) != 0);
} }
} catch (SQLException e) { });
//TODO: error log
e.printStackTrace();
}
return false; return result.get();
}
private void isAlreadyBlacklisted(String word, String serverId, Consumer<Integer> result) {
database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> {
if (!table.isEmpty()) {
int count = Integer.parseInt(table.getRowModel(0).getItem(0).toString());
result.accept(count);
}
});
} }
@Override @Override
@@ -28,18 +28,12 @@ public class DBMessage extends AbstractController {
} }
public void log(String servername, String channelname, String username, String datesent, String messageId, String message) { public void log(String servername, String channelname, String username, String datesent, String messageId, String message) {
database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null).async();
ThreadManager.executor.submit(() -> {
database.insert("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null);
});
} }
public void logEdit(String messageId, String newMessage) { public void logEdit(String messageId, String newMessage) {
database.prepareAndExecuteAsync("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId).async();
ThreadManager.executor.submit(() -> {
database.update("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId);
});
} }
@@ -1,10 +1,8 @@
package netneutrality.db.controllers; package netneutrality.db.controllers;
import java.sql.ResultSet; import java.util.concurrent.atomic.AtomicReference;
import java.sql.SQLException;
import java.util.function.Consumer; import java.util.function.Consumer;
import netneutrality.ThreadManager;
import netneutrality.db.AbstractController; import netneutrality.db.AbstractController;
import netneutrality.db.MysqlDatabase; import netneutrality.db.MysqlDatabase;
import netneutrality.db.models.MTableModel; import netneutrality.db.models.MTableModel;
@@ -13,26 +11,21 @@ public class DBSettings extends AbstractController {
public void getSettingsByKey(String key, Consumer<Object> success) { public void getSettingsByKey(String key, Consumer<Object> success) {
ThreadManager.executor.submit(() -> { database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).async(table -> {
Object value = null; Object value = null;
ResultSet rs; if (table.getNbRows() == 1) {
rs = database.prepareAndExecute("SELECT value FROM settings WHERE skey = ?", key); value = table.getRowModel(0).getItem(0);
MTableModel table = MysqlDatabase.convertToTableModel(rs); }
if (table.getNbRows() == 1) { success.accept(value);
value = table.getRowModel(0).getItem(0); });
}
success.accept(value);
});
} }
@Deprecated
public String getSettingsByKey(String key) { public String getSettingsByKey(String key) {
ResultSet rs; MTableModel table = database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).blocking();
rs = database.prepareAndExecute("SELECT value FROM settings WHERE skey = ?", key);
MTableModel table = MysqlDatabase.convertToTableModel(rs);
if (table.getNbRows() == 1) { if (table.getNbRows() == 1) {
return table.getRow(0).get(0).toString(); return table.getRow(0).get(0).toString();