Archiviert
1
0

Merge pull request 'Allow sql connection parallelity' (#335) from multiSQLConnections into master

Reviewed-on: SteamWar/BungeeCore#335
Reviewed-by: YoyoNow <jwsteam@nidido.de>
Dieser Commit ist enthalten in:
Lixfel 2022-04-03 08:50:31 +02:00
Commit 271ce76897
7 geänderte Dateien mit 180 neuen und 138 gelöschten Zeilen

Datei anzeigen

@ -272,12 +272,6 @@ public class BungeeCore extends Plugin {
Persistent.setChatPrefix(CHAT_PREFIX); Persistent.setChatPrefix(CHAT_PREFIX);
Persistent.setLobbyServer(LOBBY_SERVER); Persistent.setLobbyServer(LOBBY_SERVER);
Statement.connect(
config.getString("db.url"),
config.getString("db.username"),
config.getString("db.password")
);
if (config.contains("discord")) { if (config.contains("discord")) {
SteamwarDiscordBotConfig.loadConfig(config.getSection("discord")); SteamwarDiscordBotConfig.loadConfig(config.getSection("discord"));
} }

Datei anzeigen

@ -20,7 +20,6 @@
package de.steamwar.bungeecore; package de.steamwar.bungeecore;
import de.steamwar.bungeecore.sql.SWException; import de.steamwar.bungeecore.sql.SWException;
import de.steamwar.bungeecore.sql.Statement;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintStream; import java.io.PrintStream;
@ -63,7 +62,7 @@ public class ErrorLogger extends Handler {
SWException.log("Bungee", "DDOS", ddosRate + ""); SWException.log("Bungee", "DDOS", ddosRate + "");
} }
return; return;
} else if (!Statement.connectionStable()) { } else if (stacktrace.contains("ErrorLogger")) {
return; return;
} }
@ -88,6 +87,7 @@ public class ErrorLogger extends Handler {
contains.add("Error authenticating "); contains.add("Error authenticating ");
contains.add("read timed out"); contains.add("read timed out");
contains.add("Connection reset by peer"); contains.add("Connection reset by peer");
contains.add("No client connected for pending server");
ignoreContains = Collections.unmodifiableList(contains); ignoreContains = Collections.unmodifiableList(contains);
} }
} }

Datei anzeigen

@ -21,9 +21,10 @@ package de.steamwar.bungeecore.comms;
import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.comms.handlers.*; import de.steamwar.bungeecore.comms.handlers.*;
import de.steamwar.bungeecore.comms.packets.FightEndsPacket;
import de.steamwar.bungeecore.listeners.BasicListener; import de.steamwar.bungeecore.listeners.BasicListener;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.PluginMessageEvent; import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
@ -46,7 +47,7 @@ public class SpigotReceiver extends BasicListener {
ByteArrayDataInput in = ByteStreams.newDataInput(event.getData()); ByteArrayDataInput in = ByteStreams.newDataInput(event.getData());
Byte handler = in.readByte(); Byte handler = in.readByte();
handlerMap.get(handler).handle(in, ((Server) event.getSender()).getInfo()); ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> handlerMap.get(handler).handle(in, ((Server) event.getSender()).getInfo()));
} }
public static void registerHandler(Byte id, SpigotHandler handler) { public static void registerHandler(Byte id, SpigotHandler handler) {

Datei anzeigen

@ -19,6 +19,7 @@
package de.steamwar.bungeecore.listeners; package de.steamwar.bungeecore.listeners;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.Message; import de.steamwar.bungeecore.Message;
import de.steamwar.bungeecore.sql.BannedUserIPs; import de.steamwar.bungeecore.sql.BannedUserIPs;
import de.steamwar.bungeecore.sql.Punishment; import de.steamwar.bungeecore.sql.Punishment;
@ -40,6 +41,8 @@ public class BanListener extends BasicListener {
@EventHandler @EventHandler
public void onLogin(LoginEvent event) { public void onLogin(LoginEvent event) {
event.registerIntent(BungeeCore.get());
ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> {
SteamwarUser user = SteamwarUser.getOrCreate(event.getConnection()); SteamwarUser user = SteamwarUser.getOrCreate(event.getConnection());
if (user.isPunished(Punishment.PunishmentType.Ban)) { if (user.isPunished(Punishment.PunishmentType.Ban)) {
user.updateBanIP(event.getConnection().getAddress().getAddress().getHostAddress()); user.updateBanIP(event.getConnection().getAddress().getAddress().getHostAddress());
@ -89,5 +92,7 @@ public class BanListener extends BasicListener {
} }
} }
} }
event.completeIntent(BungeeCore.get());
});
} }
} }

Datei anzeigen

@ -167,7 +167,7 @@ public class ChatListener extends BasicListener {
return; return;
e.setCancelled(true); e.setCancelled(true);
publicChat(user, sender, e.getMessage()); ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> publicChat(user, sender, e.getMessage()));
} }
} }

Datei anzeigen

@ -19,8 +19,10 @@
package de.steamwar.bungeecore.listeners; package de.steamwar.bungeecore.listeners;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.sql.Session; import de.steamwar.bungeecore.sql.Session;
import de.steamwar.bungeecore.sql.SteamwarUser; import de.steamwar.bungeecore.sql.SteamwarUser;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent; import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
@ -40,7 +42,8 @@ public class SessionManager extends BasicListener {
@EventHandler @EventHandler
public void onDisconnect(PlayerDisconnectEvent e){ public void onDisconnect(PlayerDisconnectEvent e){
Timestamp timestamp = sessions.remove(e.getPlayer()); Timestamp timestamp = sessions.remove(e.getPlayer());
if(timestamp != null) if(timestamp != null) {
Session.insertSession(SteamwarUser.get(e.getPlayer()).getId(), timestamp); ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> Session.insertSession(SteamwarUser.get(e.getPlayer()).getId(), timestamp));
}
} }
} }

Datei anzeigen

@ -21,128 +21,167 @@ package de.steamwar.bungeecore.sql;
import de.steamwar.bungeecore.BungeeCore; import de.steamwar.bungeecore.BungeeCore;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.sql.*; import java.sql.*;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger;
public class Statement implements AutoCloseable { public class Statement implements AutoCloseable {
private static final Logger logger = BungeeCore.get().getLogger();
private static final List<Statement> statements = new ArrayList<>(); private static final List<Statement> statements = new ArrayList<>();
private static final Deque<Connection> connections = new ArrayDeque<>();
private static Connection con; private static final String URL;
private static String url; private static final String USER;
private static String user; private static final String PASSWORD;
private static String password;
public static void connect(String url, String user, String password) { static {
Statement.url = url; File file = new File(BungeeCore.get().getDataFolder(), "MySQL.yml");
Statement.user = user; Configuration config;
Statement.password = password;
try { try {
con = DriverManager.getConnection(url + "?autoReconnect=true&useServerPrepStmts=true", user, password); config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(file);
} catch (SQLException e) { } catch (IOException e) {
ProxyServer.getInstance().stop(); ProxyServer.getInstance().stop();
throw new SecurityException("Could not start SQL-Connection", e); throw new SecurityException("Could not load SQL connection", e);
}
} }
private static void reset() { URL = "jdbc:mysql://" + config.getString("HOST") + ":" + config.getString("PORT") + "/" + config.getString("DATABASE");
closeAll(); USER = config.getString("USER");
connect(url, user, password); PASSWORD = config.getString("PASSWORD");
try {
for (Statement statement : statements) {
statement.init();
}
} catch (SQLException e) {
throw new SecurityException("Could not reprepare SQL statements", e);
}
}
@Override
public void close() {
try {
st.close();
} catch (SQLException e) {
BungeeCore.get().getLogger().log(Level.INFO, "Could not close statement", e);
}
statements.remove(this);
} }
public static void closeAll() { public static void closeAll() {
synchronized (connections) {
for(Connection connection : connections) {
try {
synchronized (statements) { synchronized (statements) {
for (Statement statement : statements) { statements.forEach(statement -> statement.close(connection));
try { }
statement.st.close(); connection.close();
} catch (SQLException e) { } catch (SQLException e) {
BungeeCore.get().getLogger().log(Level.INFO, "Could not close statement", e); logger.log(Level.INFO, "Could not close SQL connection", e);
} }
} }
connections.clear();
try {
con.close();
} catch (SQLException e) {
BungeeCore.get().getLogger().log(Level.INFO, "Could not close SQL connection", e);
}
}
}
public static boolean connectionStable() {
try {
return !con.isClosed();
} catch (SQLException e) {
return false;
} }
} }
private final String sql; private final String sql;
private PreparedStatement st; private final Map<Connection, PreparedStatement> cachedStatements = new HashMap<>();
public Statement(String sql) { public Statement(String sql) {
this.sql = sql; this.sql = sql;
synchronized (statements) {
statements.add(this); statements.add(this);
try {
init();
} catch (SQLException e) {
throw new SecurityException("Could not init SQL statement", e);
} }
} }
private void init() throws SQLException {
st = con.prepareStatement(sql);
}
public <T> T select(ResultSetUser<T> user, Object... objects) { public <T> T select(ResultSetUser<T> user, Object... objects) {
synchronized (statements) { return withConnection(st -> {
return prepare(() -> {
ResultSet rs = st.executeQuery(); ResultSet rs = st.executeQuery();
T result = user.use(rs); T result = user.use(rs);
rs.close(); rs.close();
return result; return result;
}, objects); }, objects);
} }
}
public void update(Object... objects) { public void update(Object... objects) {
synchronized (statements) { withConnection(PreparedStatement::executeUpdate, objects);
prepare(st::executeUpdate, objects);
}
} }
private <T> T prepare(SQLRunnable<T> runnable, Object... objects) { private <T> T withConnection(SQLRunnable<T> runnable, Object... objects) {
Connection connection = aquireConnection();
T result;
try { try {
setObjects(objects); result = tryWithConnection(connection, runnable, objects);
return runnable.run();
} catch (SQLException e) { } catch (SQLException e) {
reset(); closeConnection(connection);
throw new SecurityException("Could not execute SQL statement", e); connection = aquireConnection();
try {
result = tryWithConnection(connection, runnable, objects);
} catch (SQLException ex) {
closeConnection(connection);
throw new SecurityException("Could not execute statement", ex);
} }
} }
private void setObjects(Object... objects) throws SQLException { synchronized (connections) {
connections.push(connection);
}
return result;
}
private <T> T tryWithConnection(Connection connection, SQLRunnable<T> runnable, Object... objects) throws SQLException {
PreparedStatement st = cachedStatements.get(connection);
if(st == null) {
st = connection.prepareStatement(sql);
cachedStatements.put(connection, st);
}
for (int i = 0; i < objects.length; i++) { for (int i = 0; i < objects.length; i++) {
st.setObject(i + 1, objects[i]); st.setObject(i + 1, objects[i]);
} }
return runnable.run(st);
}
@Override
public void close() {
cachedStatements.values().forEach(st -> closeStatement(st, false));
cachedStatements.clear();
synchronized (statements) {
statements.remove(this);
}
}
private void close(Connection connection) {
PreparedStatement st = cachedStatements.remove(connection);
if(st != null)
closeStatement(st, true);
}
private static Connection aquireConnection() {
synchronized (connections) {
if(!connections.isEmpty())
return connections.pop();
}
try {
return DriverManager.getConnection(URL + "?autoReconnect=true&useServerPrepStmts=true", USER, PASSWORD);
} catch (SQLException e) {
throw new SecurityException("Could not open connection", e);
}
}
private static void closeConnection(Connection connection) {
synchronized (statements) {
for (Statement statement : statements) {
statement.close(connection);
}
}
try {
connection.close();
} catch (SQLException e) {
logger.log(Level.INFO, "Could not close connection", e);
}
}
private static void closeStatement(PreparedStatement st, boolean silent) {
try {
st.close();
} catch (SQLException e) {
if(!silent)
logger.log(Level.INFO, "Could not close statement", e);
}
} }
public interface ResultSetUser<T> { public interface ResultSetUser<T> {
@ -150,6 +189,6 @@ public class Statement implements AutoCloseable {
} }
private interface SQLRunnable<T> { private interface SQLRunnable<T> {
T run() throws SQLException; T run(PreparedStatement st) throws SQLException;
} }
} }