From 96a579ee4afda74f52330847b381a3e40b274c84 Mon Sep 17 00:00:00 2001 From: MobiusDevelopment Date: Wed, 12 Jul 2023 00:45:47 +0300 Subject: [PATCH] Addition of ExecuteThread executor for running packets. --- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../java/org/l2jmobius/Config.java | 6 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- .../dist/game/config/Network.ini | 8 +- .../dist/game/config/Server.ini | 6 -- .../dist/login/config/LoginServer.ini | 5 -- .../java/org/l2jmobius/Config.java | 7 +- .../commons/network/ExecuteThread.java | 80 ++++++++++++++----- .../l2jmobius/commons/network/NetClient.java | 20 +++++ .../l2jmobius/commons/network/SendThread.java | 18 ++--- .../gameserver/network/PacketHandler.java | 54 ++----------- .../network/LoginPacketHandler.java | 54 ++----------- 277 files changed, 3248 insertions(+), 4504 deletions(-) diff --git a/L2J_Mobius_01.0_Ertheia/dist/game/config/Network.ini b/L2J_Mobius_01.0_Ertheia/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_01.0_Ertheia/dist/game/config/Network.ini +++ b/L2J_Mobius_01.0_Ertheia/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_01.0_Ertheia/dist/game/config/Server.ini b/L2J_Mobius_01.0_Ertheia/dist/game/config/Server.ini index 6b51d4a1cf..e20b7983d6 100644 --- a/L2J_Mobius_01.0_Ertheia/dist/game/config/Server.ini +++ b/L2J_Mobius_01.0_Ertheia/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_01.0_Ertheia/dist/login/config/LoginServer.ini b/L2J_Mobius_01.0_Ertheia/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_01.0_Ertheia/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_01.0_Ertheia/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/Config.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/Config.java index cdff6b3abe..c9f17471ec 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/Config.java @@ -463,7 +463,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1444,7 +1443,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1470,8 +1468,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3606,7 +3604,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_02.5_Underground/dist/game/config/Network.ini b/L2J_Mobius_02.5_Underground/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_02.5_Underground/dist/game/config/Network.ini +++ b/L2J_Mobius_02.5_Underground/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_02.5_Underground/dist/game/config/Server.ini b/L2J_Mobius_02.5_Underground/dist/game/config/Server.ini index 588098b5b0..076d092e91 100644 --- a/L2J_Mobius_02.5_Underground/dist/game/config/Server.ini +++ b/L2J_Mobius_02.5_Underground/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_02.5_Underground/dist/login/config/LoginServer.ini b/L2J_Mobius_02.5_Underground/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_02.5_Underground/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_02.5_Underground/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/Config.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/Config.java index aba46b15c7..41087a686b 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/Config.java @@ -470,7 +470,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1456,7 +1455,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1482,8 +1480,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3632,7 +3630,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_03.0_Helios/dist/game/config/Network.ini b/L2J_Mobius_03.0_Helios/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_03.0_Helios/dist/game/config/Network.ini +++ b/L2J_Mobius_03.0_Helios/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_03.0_Helios/dist/game/config/Server.ini b/L2J_Mobius_03.0_Helios/dist/game/config/Server.ini index 22eb7ec83d..41d4f92c6d 100644 --- a/L2J_Mobius_03.0_Helios/dist/game/config/Server.ini +++ b/L2J_Mobius_03.0_Helios/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_03.0_Helios/dist/login/config/LoginServer.ini b/L2J_Mobius_03.0_Helios/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_03.0_Helios/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_03.0_Helios/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/Config.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/Config.java index cbd489567b..3f40bc8ba6 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/Config.java @@ -470,7 +470,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1469,7 +1468,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1495,8 +1493,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3654,7 +3652,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_04.0_GrandCrusade/dist/game/config/Network.ini b/L2J_Mobius_04.0_GrandCrusade/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_04.0_GrandCrusade/dist/game/config/Network.ini +++ b/L2J_Mobius_04.0_GrandCrusade/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_04.0_GrandCrusade/dist/game/config/Server.ini b/L2J_Mobius_04.0_GrandCrusade/dist/game/config/Server.ini index 9b67e641f1..d9fbf96f56 100644 --- a/L2J_Mobius_04.0_GrandCrusade/dist/game/config/Server.ini +++ b/L2J_Mobius_04.0_GrandCrusade/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_04.0_GrandCrusade/dist/login/config/LoginServer.ini b/L2J_Mobius_04.0_GrandCrusade/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_04.0_GrandCrusade/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_04.0_GrandCrusade/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/Config.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/Config.java index 1d24626093..c4afb1e5f5 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/Config.java @@ -464,7 +464,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1456,7 +1455,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1482,8 +1480,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3628,7 +3626,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_05.0_Salvation/dist/game/config/Network.ini b/L2J_Mobius_05.0_Salvation/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_05.0_Salvation/dist/game/config/Network.ini +++ b/L2J_Mobius_05.0_Salvation/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_05.0_Salvation/dist/game/config/Server.ini b/L2J_Mobius_05.0_Salvation/dist/game/config/Server.ini index 4ff9e457b5..b45d889405 100644 --- a/L2J_Mobius_05.0_Salvation/dist/game/config/Server.ini +++ b/L2J_Mobius_05.0_Salvation/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_05.0_Salvation/dist/login/config/LoginServer.ini b/L2J_Mobius_05.0_Salvation/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_05.0_Salvation/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_05.0_Salvation/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/Config.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/Config.java index 8b4583f4d5..3ee637d093 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/Config.java @@ -463,7 +463,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1455,7 +1454,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1481,8 +1479,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3637,7 +3635,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_05.5_EtinasFate/dist/game/config/Network.ini b/L2J_Mobius_05.5_EtinasFate/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_05.5_EtinasFate/dist/game/config/Network.ini +++ b/L2J_Mobius_05.5_EtinasFate/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_05.5_EtinasFate/dist/game/config/Server.ini b/L2J_Mobius_05.5_EtinasFate/dist/game/config/Server.ini index ff26a89f1d..54b465d65e 100644 --- a/L2J_Mobius_05.5_EtinasFate/dist/game/config/Server.ini +++ b/L2J_Mobius_05.5_EtinasFate/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_05.5_EtinasFate/dist/login/config/LoginServer.ini b/L2J_Mobius_05.5_EtinasFate/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_05.5_EtinasFate/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_05.5_EtinasFate/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/Config.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/Config.java index 751218796a..df92b2f6e1 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/Config.java @@ -463,7 +463,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1462,7 +1461,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1488,8 +1486,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3649,7 +3647,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_06.0_Fafurion/dist/game/config/Network.ini b/L2J_Mobius_06.0_Fafurion/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_06.0_Fafurion/dist/game/config/Network.ini +++ b/L2J_Mobius_06.0_Fafurion/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_06.0_Fafurion/dist/game/config/Server.ini b/L2J_Mobius_06.0_Fafurion/dist/game/config/Server.ini index 13055df456..c5c1d46a8d 100644 --- a/L2J_Mobius_06.0_Fafurion/dist/game/config/Server.ini +++ b/L2J_Mobius_06.0_Fafurion/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_06.0_Fafurion/dist/login/config/LoginServer.ini b/L2J_Mobius_06.0_Fafurion/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_06.0_Fafurion/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_06.0_Fafurion/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/Config.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/Config.java index 9dd4dea93a..ea002445eb 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/Config.java @@ -464,7 +464,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1483,7 +1482,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1509,8 +1507,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3691,7 +3689,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_07.0_PreludeOfWar/dist/game/config/Network.ini b/L2J_Mobius_07.0_PreludeOfWar/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/dist/game/config/Network.ini +++ b/L2J_Mobius_07.0_PreludeOfWar/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_07.0_PreludeOfWar/dist/game/config/Server.ini b/L2J_Mobius_07.0_PreludeOfWar/dist/game/config/Server.ini index 818e4cb246..054a48af9b 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/dist/game/config/Server.ini +++ b/L2J_Mobius_07.0_PreludeOfWar/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_07.0_PreludeOfWar/dist/login/config/LoginServer.ini b/L2J_Mobius_07.0_PreludeOfWar/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_07.0_PreludeOfWar/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/Config.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/Config.java index c7230ec7bc..3eef3af20c 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/Config.java @@ -464,7 +464,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1491,7 +1490,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1517,8 +1515,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3707,7 +3705,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_08.2_Homunculus/dist/game/config/Network.ini b/L2J_Mobius_08.2_Homunculus/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_08.2_Homunculus/dist/game/config/Network.ini +++ b/L2J_Mobius_08.2_Homunculus/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_08.2_Homunculus/dist/game/config/Server.ini b/L2J_Mobius_08.2_Homunculus/dist/game/config/Server.ini index fbf65aa0d3..2c3fb3c55e 100644 --- a/L2J_Mobius_08.2_Homunculus/dist/game/config/Server.ini +++ b/L2J_Mobius_08.2_Homunculus/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_08.2_Homunculus/dist/login/config/LoginServer.ini b/L2J_Mobius_08.2_Homunculus/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_08.2_Homunculus/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_08.2_Homunculus/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/Config.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/Config.java index 6ba042ea7a..e34c8653f8 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/Config.java @@ -457,7 +457,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1482,7 +1481,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1508,8 +1506,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3682,7 +3680,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/game/config/Network.ini b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/game/config/Network.ini +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/game/config/Server.ini b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/game/config/Server.ini index 921ed2c12f..dc229baa88 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/game/config/Server.ini +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/login/config/LoginServer.ini b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/Config.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/Config.java index c94e0cd901..fa0e2d7fda 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/Config.java @@ -457,7 +457,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1484,7 +1483,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1510,8 +1508,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3686,7 +3684,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_10.2_MasterClass/dist/game/config/Network.ini b/L2J_Mobius_10.2_MasterClass/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_10.2_MasterClass/dist/game/config/Network.ini +++ b/L2J_Mobius_10.2_MasterClass/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_10.2_MasterClass/dist/game/config/Server.ini b/L2J_Mobius_10.2_MasterClass/dist/game/config/Server.ini index 7ec5a6009f..f571776169 100644 --- a/L2J_Mobius_10.2_MasterClass/dist/game/config/Server.ini +++ b/L2J_Mobius_10.2_MasterClass/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_10.2_MasterClass/dist/login/config/LoginServer.ini b/L2J_Mobius_10.2_MasterClass/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_10.2_MasterClass/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_10.2_MasterClass/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/Config.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/Config.java index ca6e92dc23..badeaff6f6 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/Config.java @@ -457,7 +457,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1485,7 +1484,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1511,8 +1509,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3688,7 +3686,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_10.3_MasterClass/dist/game/config/Network.ini b/L2J_Mobius_10.3_MasterClass/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_10.3_MasterClass/dist/game/config/Network.ini +++ b/L2J_Mobius_10.3_MasterClass/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_10.3_MasterClass/dist/game/config/Server.ini b/L2J_Mobius_10.3_MasterClass/dist/game/config/Server.ini index 3fd4ec544b..5ea7ad8e67 100644 --- a/L2J_Mobius_10.3_MasterClass/dist/game/config/Server.ini +++ b/L2J_Mobius_10.3_MasterClass/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_10.3_MasterClass/dist/login/config/LoginServer.ini b/L2J_Mobius_10.3_MasterClass/dist/login/config/LoginServer.ini index f214d42150..80020fc5f0 100644 --- a/L2J_Mobius_10.3_MasterClass/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_10.3_MasterClass/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/Config.java b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/Config.java index 85e9395266..897fd1221f 100644 --- a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/Config.java @@ -459,7 +459,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1519,7 +1518,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1545,8 +1543,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3746,7 +3744,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_10.3_MasterClass/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/Network.ini b/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/Network.ini index d2d1778b98..8f766dcb14 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/Network.ini +++ b/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/Server.ini b/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/Server.ini index 5a572dbeb5..d055d80282 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/Server.ini +++ b/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/Server.ini @@ -170,12 +170,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Dead Lock Detector (separate thread for detecting deadlocks) diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/Config.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/Config.java index 389f4fdb33..26f98c0c66 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/Config.java @@ -1048,7 +1048,6 @@ public class Config public static int MAX_PROTOCOL_REVISION; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; public static boolean RESTART_ON_DEADLOCK; @@ -1161,7 +1160,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); RESTART_ON_DEADLOCK = serverConfig.getBoolean("RestartOnDeadlock", false); @@ -1193,8 +1191,8 @@ public class Config { final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_C6_Interlude/dist/game/config/Network.ini b/L2J_Mobius_C6_Interlude/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_C6_Interlude/dist/game/config/Network.ini +++ b/L2J_Mobius_C6_Interlude/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_C6_Interlude/dist/game/config/Server.ini b/L2J_Mobius_C6_Interlude/dist/game/config/Server.ini index 36445306f4..b336977bca 100644 --- a/L2J_Mobius_C6_Interlude/dist/game/config/Server.ini +++ b/L2J_Mobius_C6_Interlude/dist/game/config/Server.ini @@ -126,12 +126,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Dead Lock Detector (separate thread for detecting deadlocks) diff --git a/L2J_Mobius_C6_Interlude/dist/login/config/LoginServer.ini b/L2J_Mobius_C6_Interlude/dist/login/config/LoginServer.ini index 39c49991ba..3f71af8d9e 100644 --- a/L2J_Mobius_C6_Interlude/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_C6_Interlude/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/Config.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/Config.java index 90e24ebb20..d703ca420e 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/Config.java @@ -1095,7 +1095,6 @@ public class Config public static int MAX_PROTOCOL_REVISION; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; public static boolean RESTART_ON_DEADLOCK; @@ -1202,7 +1201,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); RESTART_ON_DEADLOCK = serverConfig.getBoolean("RestartOnDeadlock", false); @@ -1234,8 +1232,8 @@ public class Config { final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -2913,7 +2911,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = serverSettings.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = serverSettings.getBoolean("ShowLicence", false); AUTO_CREATE_ACCOUNTS = serverSettings.getBoolean("AutoCreateAccounts", true); FLOOD_PROTECTION = serverSettings.getBoolean("EnableFloodProtection", true); diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_CT_0_Interlude/dist/game/config/Network.ini b/L2J_Mobius_CT_0_Interlude/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_CT_0_Interlude/dist/game/config/Network.ini +++ b/L2J_Mobius_CT_0_Interlude/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_CT_0_Interlude/dist/game/config/Server.ini b/L2J_Mobius_CT_0_Interlude/dist/game/config/Server.ini index 30f8451bc3..428aea0c3c 100644 --- a/L2J_Mobius_CT_0_Interlude/dist/game/config/Server.ini +++ b/L2J_Mobius_CT_0_Interlude/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_CT_0_Interlude/dist/login/config/LoginServer.ini b/L2J_Mobius_CT_0_Interlude/dist/login/config/LoginServer.ini index 2921a80789..064960375e 100644 --- a/L2J_Mobius_CT_0_Interlude/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_CT_0_Interlude/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/Config.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/Config.java index c7ab272855..a0b250d3f8 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/Config.java @@ -515,7 +515,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1408,7 +1407,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1434,8 +1432,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3080,7 +3078,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); FLOOD_PROTECTION = loginConfig.getBoolean("EnableFloodProtection", true); diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/Network.ini b/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/Network.ini +++ b/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/Server.ini b/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/Server.ini index 307ca45c67..55ee6d9fb8 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/Server.ini +++ b/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_CT_2.4_Epilogue/dist/login/config/LoginServer.ini b/L2J_Mobius_CT_2.4_Epilogue/dist/login/config/LoginServer.ini index ae9f149b42..24a6585763 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_CT_2.4_Epilogue/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/Config.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/Config.java index b1ac9ea061..f30085569b 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/Config.java @@ -523,7 +523,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1461,7 +1460,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1487,8 +1485,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3196,7 +3194,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); FLOOD_PROTECTION = loginConfig.getBoolean("EnableFloodProtection", true); diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Network.ini b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Network.ini +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Server.ini b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Server.ini index e46a7cbe2a..df59917d77 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Server.ini +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/login/config/LoginServer.ini b/L2J_Mobius_CT_2.6_HighFive/dist/login/config/LoginServer.ini index 5bb394c9da..a93717d061 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_CT_2.6_HighFive/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/Config.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/Config.java index 46704c5821..2dff060aa3 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/Config.java @@ -528,7 +528,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1461,7 +1460,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1487,8 +1485,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3203,7 +3201,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); FLOOD_PROTECTION = loginConfig.getBoolean("EnableFloodProtection", true); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_1.0/dist/game/config/Network.ini b/L2J_Mobius_Classic_1.0/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_1.0/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_1.0/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_1.0/dist/game/config/Server.ini b/L2J_Mobius_Classic_1.0/dist/game/config/Server.ini index e4641ec915..dd7d85c318 100644 --- a/L2J_Mobius_Classic_1.0/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_1.0/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_1.0/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_1.0/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_1.0/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_1.0/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/Config.java index 64eed87129..6e9edb57e3 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/Config.java @@ -475,7 +475,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1384,7 +1383,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1410,8 +1408,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3483,7 +3481,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_1.0/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_1.0/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/game/config/Network.ini b/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/game/config/Server.ini b/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/game/config/Server.ini index b496dab339..da23feab1c 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/Config.java index 9cc6dee8a0..02025197b5 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/Config.java @@ -485,7 +485,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1402,7 +1401,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1428,8 +1426,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3529,7 +3527,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_1.5_AgeOfSplendor/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Network.ini b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Server.ini b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Server.ini index 0de2f1d2f8..4e5c57d5d0 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_2.0_Saviors/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/Config.java index 099c3822e5..080a0eb9d4 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/Config.java @@ -485,7 +485,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1405,7 +1404,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1431,8 +1429,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3535,7 +3533,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.5_Zaken/dist/game/config/Network.ini b/L2J_Mobius_Classic_2.5_Zaken/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_2.5_Zaken/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_2.5_Zaken/dist/game/config/Server.ini b/L2J_Mobius_Classic_2.5_Zaken/dist/game/config/Server.ini index 22da7056e2..d6315235b6 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_2.5_Zaken/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_2.5_Zaken/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_2.5_Zaken/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_2.5_Zaken/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/Config.java index a18e7c9727..d962ed392c 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/Config.java @@ -485,7 +485,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1409,7 +1408,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1435,8 +1433,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3541,7 +3539,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_2.5_Zaken/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.7_Antharas/dist/game/config/Network.ini b/L2J_Mobius_Classic_2.7_Antharas/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_2.7_Antharas/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_2.7_Antharas/dist/game/config/Server.ini b/L2J_Mobius_Classic_2.7_Antharas/dist/game/config/Server.ini index 1d9fee26b7..6efb898560 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_2.7_Antharas/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_2.7_Antharas/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_2.7_Antharas/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_2.7_Antharas/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/Config.java index a18e7c9727..d962ed392c 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/Config.java @@ -485,7 +485,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1409,7 +1408,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1435,8 +1433,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3541,7 +3539,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_2.7_Antharas/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/dist/game/config/Network.ini b/L2J_Mobius_Classic_2.8_SevenSigns/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_2.8_SevenSigns/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/dist/game/config/Server.ini b/L2J_Mobius_Classic_2.8_SevenSigns/dist/game/config/Server.ini index 6f590a77cf..9f9ec6fae6 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_2.8_SevenSigns/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_2.8_SevenSigns/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_2.8_SevenSigns/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/Config.java index a18e7c9727..d962ed392c 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/Config.java @@ -485,7 +485,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1409,7 +1408,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1435,8 +1433,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3541,7 +3539,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_2.8_SevenSigns/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/dist/game/config/Network.ini b/L2J_Mobius_Classic_2.9.5_Saviors/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_2.9.5_Saviors/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/dist/game/config/Server.ini b/L2J_Mobius_Classic_2.9.5_Saviors/dist/game/config/Server.ini index 538e4b323a..a3f1ec3ec9 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_2.9.5_Saviors/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_2.9.5_Saviors/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_2.9.5_Saviors/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/Config.java index 6c58723842..48b48c24a5 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/Config.java @@ -486,7 +486,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1420,7 +1419,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1446,8 +1444,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3563,7 +3561,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_2.9.5_Saviors/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/game/config/Network.ini b/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/game/config/Server.ini b/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/game/config/Server.ini index 02b8634df5..947d2e6741 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/Config.java index 3a8916b5bd..0f5a3d482c 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/Config.java @@ -485,7 +485,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1413,7 +1412,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1439,8 +1437,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3549,7 +3547,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_2.9_SecretOfEmpire/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/dist/game/config/Network.ini b/L2J_Mobius_Classic_3.0_TheKamael/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_3.0_TheKamael/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_3.0_TheKamael/dist/game/config/Server.ini b/L2J_Mobius_Classic_3.0_TheKamael/dist/game/config/Server.ini index 5687b2dd36..24fcc7906e 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_3.0_TheKamael/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_3.0_TheKamael/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_3.0_TheKamael/dist/login/config/LoginServer.ini index 9140d98ec4..b0eba521cb 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_3.0_TheKamael/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/Config.java index 00c5dd97fc..f5fc7fe5c3 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/Config.java @@ -485,7 +485,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1420,7 +1419,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1446,8 +1444,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3563,7 +3561,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_Interlude/dist/game/config/Network.ini b/L2J_Mobius_Classic_Interlude/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Classic_Interlude/dist/game/config/Network.ini +++ b/L2J_Mobius_Classic_Interlude/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Classic_Interlude/dist/game/config/Server.ini b/L2J_Mobius_Classic_Interlude/dist/game/config/Server.ini index 8bac8947e7..f765cdd005 100644 --- a/L2J_Mobius_Classic_Interlude/dist/game/config/Server.ini +++ b/L2J_Mobius_Classic_Interlude/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Classic_Interlude/dist/login/config/LoginServer.ini b/L2J_Mobius_Classic_Interlude/dist/login/config/LoginServer.ini index 8205ae9b97..b35fd7551e 100644 --- a/L2J_Mobius_Classic_Interlude/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Classic_Interlude/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/Config.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/Config.java index 9cfe0b163c..b58f0f1825 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/Config.java @@ -485,7 +485,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1413,7 +1412,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1439,8 +1437,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3538,7 +3536,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/game/config/Network.ini b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/game/config/Network.ini +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/game/config/Server.ini b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/game/config/Server.ini index d7deaa4615..a8e40f4140 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/game/config/Server.ini +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/login/config/LoginServer.ini b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/login/config/LoginServer.ini index 5c9774cc27..9df3067d4d 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/Config.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/Config.java index d80b3602de..64655a4198 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/Config.java @@ -486,7 +486,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1445,7 +1444,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1471,8 +1469,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3617,7 +3615,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Essence_5.2_FrostLord/dist/game/config/Network.ini b/L2J_Mobius_Essence_5.2_FrostLord/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/dist/game/config/Network.ini +++ b/L2J_Mobius_Essence_5.2_FrostLord/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Essence_5.2_FrostLord/dist/game/config/Server.ini b/L2J_Mobius_Essence_5.2_FrostLord/dist/game/config/Server.ini index 3a49f7b865..32cd937e38 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/dist/game/config/Server.ini +++ b/L2J_Mobius_Essence_5.2_FrostLord/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Essence_5.2_FrostLord/dist/login/config/LoginServer.ini b/L2J_Mobius_Essence_5.2_FrostLord/dist/login/config/LoginServer.ini index 5c9774cc27..9df3067d4d 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Essence_5.2_FrostLord/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/Config.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/Config.java index 29a2a4a4bf..cb03b3da52 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/Config.java @@ -489,7 +489,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1464,7 +1463,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1490,8 +1488,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3733,7 +3731,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/config/Network.ini b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/config/Network.ini +++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/config/Server.ini b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/config/Server.ini index 2ad6f2431c..50600768d8 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/config/Server.ini +++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/login/config/LoginServer.ini b/L2J_Mobius_Essence_6.2_Vanguard/dist/login/config/LoginServer.ini index 5c9774cc27..9df3067d4d 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/Config.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/Config.java index f39102f67c..60fb16886a 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/Config.java @@ -491,7 +491,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1494,7 +1493,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1520,8 +1518,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3792,7 +3790,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Essence_6.3_Crusader/dist/game/config/Network.ini b/L2J_Mobius_Essence_6.3_Crusader/dist/game/config/Network.ini index 68114fafb9..0d36490c18 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/dist/game/config/Network.ini +++ b/L2J_Mobius_Essence_6.3_Crusader/dist/game/config/Network.ini @@ -11,13 +11,13 @@ ClientReadPoolSize = 100 # Client pool size for sending server packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientSendPoolSize = 50 +# Default: 100 +ClientSendPoolSize = 100 # Client pool size for executing client packets. # Each pool is executed on a separate thread. -# Default: 50 -ClientExecutePoolSize = 50 +# Default: 100 +ClientExecutePoolSize = 100 # Expected client packet count queued by the server. # Default: 80 diff --git a/L2J_Mobius_Essence_6.3_Crusader/dist/game/config/Server.ini b/L2J_Mobius_Essence_6.3_Crusader/dist/game/config/Server.ini index 27f9e6e08e..667234b2a2 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/dist/game/config/Server.ini +++ b/L2J_Mobius_Essence_6.3_Crusader/dist/game/config/Server.ini @@ -134,12 +134,6 @@ ScheduledThreadPoolSize = -1 # If set to -1, this will be determined by available processors multiplied by 2. InstantThreadPoolSize = -1 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Can try disabling it when server is highly populated and CPU is high. -# Default: True -ThreadsForClientPackets = True - # Use threads to decrease startup time. # Default: False ThreadsForLoading = False diff --git a/L2J_Mobius_Essence_6.3_Crusader/dist/login/config/LoginServer.ini b/L2J_Mobius_Essence_6.3_Crusader/dist/login/config/LoginServer.ini index 5c9774cc27..9df3067d4d 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/dist/login/config/LoginServer.ini +++ b/L2J_Mobius_Essence_6.3_Crusader/dist/login/config/LoginServer.ini @@ -84,11 +84,6 @@ ScheduledThreadPoolSize = 2 # If set to -1, this will be determined by available processors divided by 2. InstantThreadPoolSize = 2 -# Use threads to run client packets individually. -# Less lag when using threads, but more CPU consumption. -# Default: True -ThreadsForClientPackets = True - # --------------------------------------------------------------------------- # Security diff --git a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/Config.java b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/Config.java index 9b89c5d7d2..7c1c733507 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/Config.java @@ -491,7 +491,6 @@ public class Config public static Set ALT_DEV_EXCLUDED_PACKETS; public static int SCHEDULED_THREAD_POOL_SIZE; public static int INSTANT_THREAD_POOL_SIZE; - public static boolean THREADS_FOR_CLIENT_PACKETS; public static boolean THREADS_FOR_LOADING; public static boolean DEADLOCK_DETECTOR; public static int DEADLOCK_CHECK_INTERVAL; @@ -1504,7 +1503,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; } - THREADS_FOR_CLIENT_PACKETS = serverConfig.getBoolean("ThreadsForClientPackets", true); THREADS_FOR_LOADING = serverConfig.getBoolean("ThreadsForLoading", false); DEADLOCK_DETECTOR = serverConfig.getBoolean("DeadLockDetector", true); DEADLOCK_CHECK_INTERVAL = serverConfig.getInt("DeadLockCheckInterval", 20); @@ -1530,8 +1528,8 @@ public class Config final PropertiesParser networkConfig = new PropertiesParser(NETWORK_CONFIG_FILE); CLIENT_READ_POOL_SIZE = networkConfig.getInt("ClientReadPoolSize", 100); - CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 50); - CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 50); + CLIENT_SEND_POOL_SIZE = networkConfig.getInt("ClientSendPoolSize", 100); + CLIENT_EXECUTE_POOL_SIZE = networkConfig.getInt("ClientExecutePoolSize", 100); PACKET_QUEUE_LIMIT = networkConfig.getInt("PacketQueueLimit", 80); PACKET_FLOOD_DISCONNECT = networkConfig.getBoolean("PacketFloodDisconnect", false); PACKET_FLOOD_DROP = networkConfig.getBoolean("PacketFloodDrop", false); @@ -3802,7 +3800,6 @@ public class Config { INSTANT_THREAD_POOL_SIZE = Math.max(2, Runtime.getRuntime().availableProcessors() / 2); } - THREADS_FOR_CLIENT_PACKETS = loginConfig.getBoolean("ThreadsForClientPackets", true); SHOW_LICENCE = loginConfig.getBoolean("ShowLicence", true); SHOW_PI_AGREEMENT = loginConfig.getBoolean("ShowPIAgreement", false); AUTO_CREATE_ACCOUNTS = loginConfig.getBoolean("AutoCreateAccounts", true); diff --git a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/ExecuteThread.java b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/ExecuteThread.java index 5c88d4bb9c..3966f58ed7 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/ExecuteThread.java +++ b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/ExecuteThread.java @@ -1,8 +1,12 @@ package org.l2jmobius.commons.network; import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import org.l2jmobius.commons.threads.ThreadProvider; import org.l2jmobius.commons.util.CommonUtil; /** @@ -12,10 +16,16 @@ import org.l2jmobius.commons.util.CommonUtil; */ public class ExecuteThread implements Runnable { - private static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); + protected static final Logger LOGGER = Logger.getLogger(ExecuteThread.class.getName()); - private final Set _pool; - private final PacketHandlerInterface _packetHandler; + // The core pool size for the ThreadPoolExecutor. + private static final int EXECUTOR_POOL_SIZE = 2; + + // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("ExecuteThread Executor", Thread.MAX_PRIORITY)); + + protected final Set _pool; + protected final PacketHandlerInterface _packetHandler; private boolean _idle; public ExecuteThread(Set pool, PacketHandlerInterface packetHandler) @@ -43,30 +53,19 @@ public class ExecuteThread implements Runnable continue ITERATE; } + if (client.isRunning()) + { + continue ITERATE; + } + final byte[] data = client.getReceivedData().poll(); if (data == null) { continue ITERATE; } - if (client.getEncryption() != null) - { - try - { - client.getEncryption().decrypt(data, 0, data.length); - } - catch (Exception e) - { - if (client.getNetConfig().isFailedDecryptionLogged()) - { - LOGGER.warning("ExecuteThread: Problem with " + client + " data decryption."); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - client.disconnect(); - continue ITERATE; - } - } - _packetHandler.handle(client, new ReadablePacket(data)); + client.setRunning(true); + _executor.execute(new ExecuteTask(client, data)); _idle = false; } @@ -93,4 +92,43 @@ public class ExecuteThread implements Runnable } } } + + private class ExecuteTask implements Runnable + { + private final E _client; + private final byte[] _data; + + public ExecuteTask(E client, byte[] data) + { + _client = client; + _data = data; + } + + @Override + public void run() + { + if (_client.getEncryption() != null) + { + try + { + _client.getEncryption().decrypt(_data, 0, _data.length); + } + catch (Exception e) + { + if (_client.getNetConfig().isFailedDecryptionLogged()) + { + LOGGER.warning("ExecuteThread: Problem with " + _client + " data decryption."); + LOGGER.warning(CommonUtil.getStackTrace(e)); + } + + _pool.remove(_client); + _client.disconnect(); + return; + } + } + + _packetHandler.handle(_client, new ReadablePacket(_data)); + _client.setRunning(false); + } + } } diff --git a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/NetClient.java b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/NetClient.java index 280465d122..0b8f7839b0 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/NetClient.java +++ b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/NetClient.java @@ -19,6 +19,7 @@ public class NetClient private final Queue _receivedData = new ConcurrentLinkedQueue<>(); private final Queue _sendPacketQueue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean _isSending = new AtomicBoolean(); + private final AtomicBoolean _isRunning = new AtomicBoolean(); private String _ip; private Socket _socket; @@ -65,6 +66,7 @@ public class NetClient */ public void onDisconnection() { + disconnect(); } /** @@ -272,6 +274,24 @@ public class NetClient _isSending.set(value); } + /** + * Checks if the client is currently in the process of running a client packet. + * @return {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public boolean isRunning() + { + return _isRunning.get(); + } + + /** + * Sets the running state of the client. + * @param value the sending state to set. {@code true} if the client is running a client packet, {@code false} otherwise. + */ + public void setRunning(boolean value) + { + _isRunning.set(value); + } + /** * @return the network configurations of this client. */ diff --git a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/SendThread.java b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/SendThread.java index 3f0e2d6578..48cc88b899 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/SendThread.java +++ b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/commons/network/SendThread.java @@ -7,6 +7,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.l2jmobius.commons.threads.ThreadProvider; + /** * @author Pantelis Andrianakis * @since June 22nd 2023 @@ -14,14 +16,11 @@ import java.util.concurrent.TimeUnit; */ public class SendThread implements Runnable { - // Throttle packets sent per cycle to limit flooding from waiting one client. - private static final int MAX_PACKETS_SENT_PER_CYCLE = 2000; - // The core pool size for the ThreadPoolExecutor. - private static final int EXECUTOR_POOL_SIZE = 2; + private static final int EXECUTOR_POOL_SIZE = 5; // ThreadPoolExecutor used to execute tasks concurrently, avoiding delays caused by waiting for a single client. - private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>()); + private final ThreadPoolExecutor _executor = new ThreadPoolExecutor(EXECUTOR_POOL_SIZE, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadProvider("SendThread Executor", Thread.MAX_PRIORITY)); protected final Set _pool; private boolean _idle; @@ -104,15 +103,10 @@ public class SendThread implements Runnable @Override public void run() { + WritablePacket writablePacket; final OutputStream outputStream = _client.getOutputStream(); - for (int count = 0; count < MAX_PACKETS_SENT_PER_CYCLE; count++) + while ((writablePacket = _packetQueue.poll()) != null) { - final WritablePacket writablePacket = _packetQueue.poll(); - if (writablePacket == null) - { - break; - } - final byte[] sendableBytes = writablePacket.getSendableBytes(_client.getEncryption()); if (sendableBytes == null) { diff --git a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/network/PacketHandler.java b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/network/PacketHandler.java index bc6b604b26..e4a4274b26 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/network/PacketHandler.java +++ b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/gameserver/network/PacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.gameserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.gameserver.network.clientpackets.ClientPacket; @@ -75,54 +73,16 @@ public class PacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final GameClient _client; - private final ReadablePacket _packet; - private final ClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(GameClient client, ReadablePacket packet, ClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("PacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("PacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } } diff --git a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java index 03e3a9c097..3a393699f7 100644 --- a/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java +++ b/L2J_Mobius_Essence_6.3_Crusader/java/org/l2jmobius/loginserver/network/LoginPacketHandler.java @@ -18,10 +18,8 @@ package org.l2jmobius.loginserver.network; import java.util.logging.Logger; -import org.l2jmobius.Config; import org.l2jmobius.commons.network.PacketHandlerInterface; import org.l2jmobius.commons.network.ReadablePacket; -import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.CommonUtil; import org.l2jmobius.loginserver.network.clientpackets.LoginClientPacket; @@ -75,54 +73,16 @@ public class LoginPacketHandler implements PacketHandlerInterface return; } - // Continue on another thread. - if (Config.THREADS_FOR_CLIENT_PACKETS) + // Packet read and run. + try { - ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId)); + newPacket.read(packet); + newPacket.run(client); } - else // Wait for execution. + catch (Exception e) { - try - { - newPacket.read(packet); - newPacket.run(client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } - } - } - - private class ExecuteTask implements Runnable - { - private final LoginClient _client; - private final ReadablePacket _packet; - private final LoginClientPacket _newPacket; - private final int _packetId; - - public ExecuteTask(LoginClient client, ReadablePacket packet, LoginClientPacket newPacket, int packetId) - { - _client = client; - _packet = packet; - _newPacket = newPacket; - _packetId = packetId; - } - - @Override - public void run() - { - try - { - _newPacket.read(_packet); - _newPacket.run(_client); - } - catch (Exception e) - { - LOGGER.warning("LoginPacketHandler->ExecuteTask: Problem with " + _client + " [Packet: 0x" + Integer.toHexString(_packetId).toUpperCase() + "]"); - LOGGER.warning(CommonUtil.getStackTrace(e)); - } + LOGGER.warning("LoginPacketHandler: Problem with " + client + " [Packet: 0x" + Integer.toHexString(packetId).toUpperCase() + "]"); + LOGGER.warning(CommonUtil.getStackTrace(e)); } } }