diff --git a/Emulator/src/main/java/com/eu/habbo/core/DatabaseLogger.java b/Emulator/src/main/java/com/eu/habbo/core/DatabaseLogger.java index 2f8806a9..47d8c73f 100644 --- a/Emulator/src/main/java/com/eu/habbo/core/DatabaseLogger.java +++ b/Emulator/src/main/java/com/eu/habbo/core/DatabaseLogger.java @@ -7,6 +7,10 @@ import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; public class DatabaseLogger { @@ -24,19 +28,41 @@ public class DatabaseLogger { return; } - if (this.loggables.isEmpty()) { + // Drain the queue into a local snapshot so new loggables that arrive + // during this save cycle roll into the next flush instead of extending + // the current one indefinitely. + List snapshot = new ArrayList<>(); + DatabaseLoggable next; + while ((next = this.loggables.poll()) != null) { + snapshot.add(next); + } + + if (snapshot.isEmpty()) { return; } + // Group by SQL query so each distinct statement only prepares and + // executeBatches once. LinkedHashMap preserves first-seen order so + // auto-increment ids on chat/log tables correlate with the time the + // events actually happened. + Map> byQuery = new LinkedHashMap<>(); + for (DatabaseLoggable loggable : snapshot) { + byQuery.computeIfAbsent(loggable.getQuery(), k -> new ArrayList<>()).add(loggable); + } + try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) { - while (!this.loggables.isEmpty()) { - DatabaseLoggable loggable = this.loggables.remove(); - - try (PreparedStatement statement = connection.prepareStatement(loggable.getQuery())) { - loggable.log(statement); + for (Map.Entry> group : byQuery.entrySet()) { + List entries = group.getValue(); + try (PreparedStatement statement = connection.prepareStatement(group.getKey())) { + for (DatabaseLoggable loggable : entries) { + loggable.log(statement); + } statement.executeBatch(); + } catch (SQLException e) { + // One bad group shouldn't prevent other groups from flushing. + LOGGER.error("Exception caught while saving loggable group of size {}: {}", + entries.size(), group.getKey(), e); } - } } catch (SQLException e) { LOGGER.error("Exception caught while saving loggables to database.", e); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/messenger/Message.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/messenger/Message.java index a081bfc5..727729b6 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/messenger/Message.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/messenger/Message.java @@ -1,15 +1,14 @@ package com.eu.habbo.habbohotel.messenger; import com.eu.habbo.Emulator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.eu.habbo.core.DatabaseLoggable; -import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; -public class Message implements Runnable { - private static final Logger LOGGER = LoggerFactory.getLogger(Message.class); +public class Message implements Runnable, DatabaseLoggable { + + private static final String QUERY = "INSERT INTO chatlogs_private (user_from_id, user_to_id, message, timestamp) VALUES (?, ?, ?, ?)"; private final int fromId; private final int toId; @@ -26,20 +25,25 @@ public class Message implements Runnable { @Override public void run() { - //TODO Turn into scheduler if (Messenger.SAVE_PRIVATE_CHATS) { - try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO chatlogs_private (user_from_id, user_to_id, message, timestamp) VALUES (?, ?, ?, ?)")) { - statement.setInt(1, this.fromId); - statement.setInt(2, this.toId); - statement.setString(3, this.message); - statement.setInt(4, this.timestamp); - statement.execute(); - } catch (SQLException e) { - LOGGER.error("Caught SQL exception", e); - } + Emulator.getDatabaseLogger().store(this); } } + @Override + public String getQuery() { + return QUERY; + } + + @Override + public void log(PreparedStatement statement) throws SQLException { + statement.setInt(1, this.fromId); + statement.setInt(2, this.toId); + statement.setString(3, this.message); + statement.setInt(4, this.timestamp); + statement.addBatch(); + } + public int getToId() { return this.toId; } diff --git a/Latest_Compiled_Version/Habbo-4.1.1-jar-with-dependencies.jar b/Latest_Compiled_Version/Habbo-4.1.1-jar-with-dependencies.jar index e6499656..20cecfc3 100644 Binary files a/Latest_Compiled_Version/Habbo-4.1.1-jar-with-dependencies.jar and b/Latest_Compiled_Version/Habbo-4.1.1-jar-with-dependencies.jar differ