ThreadTracker + Attempt on NPC Disappearing fix
Engineered the ThreadTracker: server-embedded deadlock auditing tool, which will print error messages in case of found deadlocks (also showing all in-use locks on the time of the issue). Changed the player's id on DB now starting from 20mil, thus preventing players from overwriting NPC/mobs with same oid in-game. Requires proper testing to see if the issue has been cleared.
This commit is contained in:
1 parent
aecc3e300a
commit
2b38b62683
50 files changed
+1097
-121
No files matched your search
Vendored
BIN
Binary file not shown.
@@ -103,5 +103,6 @@ Project:
|
|||||||
* Fixed/added some missing packets for MoveEnvironment, summons and others.
|
* Fixed/added some missing packets for MoveEnvironment, summons and others.
|
||||||
* Reviewed many Java object aspects that needed concurrency protection.
|
* Reviewed many Java object aspects that needed concurrency protection.
|
||||||
* Heavily reviewed future task management inside the project. Way less trivial schedules are spawned now, relieving task overload on the TimerManager.
|
* Heavily reviewed future task management inside the project. Way less trivial schedules are spawned now, relieving task overload on the TimerManager.
|
||||||
|
* ThreadTracker: embedded auditing tool for run-time deadlock scanning throughout the server source (relies heavily on memory usage, designed only for debugging purposes).
|
||||||
|
|
||||||
---------------------------
|
---------------------------
|
||||||
@@ -670,3 +670,8 @@ Corrigido GM shop sendo liberado pra jogadores em Amherst.
|
|||||||
Modificado ID de jogador agora começando em 20,000,000, evitando assim clash de id de jogador (que tb representa seu OID) com OIDs de objetos do mapa.
|
Modificado ID de jogador agora começando em 20,000,000, evitando assim clash de id de jogador (que tb representa seu OID) com OIDs de objetos do mapa.
|
||||||
Nova ferramenta: MapleSkillMakerFetcher. A ferramenta lê info pertinente às descrições de itens feitos pelo Maker e as compila numa tabela, pra ser usada na DB.
|
Nova ferramenta: MapleSkillMakerFetcher. A ferramenta lê info pertinente às descrições de itens feitos pelo Maker e as compila numa tabela, pra ser usada na DB.
|
||||||
Corrigida questline de mounts e skills de Aran.
|
Corrigida questline de mounts e skills de Aran.
|
||||||
|
|
||||||
|
15 Novembro 2017,
|
||||||
|
Implementado sistema de auditoria de deadlocks: ThreadTracker.
|
||||||
|
Corrigido bug onde jogadores recebem dano de mobs de mapas anteriores (que acarretavam em problemas com OID e natureza dos objetos).
|
||||||
|
Corrigido alguns problemas com exceção sendo lançada ao tentar desligar o server.
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
||||||
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="2"/>
|
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="2"/>
|
||||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||||
<group/>
|
<group>
|
||||||
|
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/command/Commands.java</file>
|
||||||
|
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/ServerConstants.java</file>
|
||||||
|
</group>
|
||||||
</open-files>
|
</open-files>
|
||||||
</project-private>
|
</project-private>
|
||||||
@@ -22,7 +22,7 @@ function start(mode, type, selection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (status == 0)
|
if (status == 0)
|
||||||
qm.sendYesNo("In order to rescue the princess, you must first navigate the Mushroom Forest. King Pepe set up a powerful barrier forbidding anyone from entering the castle. Please investigate this matter for us.");
|
qm.sendAcceptDecline("In order to rescue the princess, you must first navigate the Mushroom Forest. King Pepe set up a powerful barrier forbidding anyone from entering the castle. Please investigate this matter for us.");
|
||||||
if (status == 1)
|
if (status == 1)
|
||||||
qm.sendNext("You'll run into the barrier at the Mushroom Forest by heading east of where you are standing right now. Please be careful. I hear that the area is infested with crazy, fear-inducing monsters.");
|
qm.sendNext("You'll run into the barrier at the Mushroom Forest by heading east of where you are standing right now. Please be careful. I hear that the area is infested with crazy, fear-inducing monsters.");
|
||||||
if(status == 2){
|
if(status == 2){
|
||||||
|
|||||||
+25
-6
@@ -18793,7 +18793,6 @@ USE `maplesolaxia`;
|
|||||||
(3400004,4000542,1,1,0,400000),
|
(3400004,4000542,1,1,0,400000),
|
||||||
(3400005,4032508,1,1,2273,999999),
|
(3400005,4032508,1,1,2273,999999),
|
||||||
(3400006,4000543,1,1,0,400000),
|
(3400006,4000543,1,1,0,400000),
|
||||||
(3400007,4032508,1,1,2273,999999),
|
|
||||||
(3400008,4000544,1,1,0,400000),
|
(3400008,4000544,1,1,0,400000),
|
||||||
(4300001,1302009,1,1,0,700),
|
(4300001,1302009,1,1,0,700),
|
||||||
(4300001,1312007,1,1,0,700),
|
(4300001,1312007,1,1,0,700),
|
||||||
@@ -18939,7 +18938,7 @@ USE `maplesolaxia`;
|
|||||||
(4300006,4000525,1,1,0,600000),
|
(4300006,4000525,1,1,0,600000),
|
||||||
(4300006,4004000,1,1,0,10000),
|
(4300006,4004000,1,1,0,10000),
|
||||||
(4300006,4020008,1,1,0,9000),
|
(4300006,4020008,1,1,0,9000),
|
||||||
(4300006,4032506,1,1,2277,999999),
|
(4300006,4032506,1,1,2277,80000),
|
||||||
(4300007,1302009,1,1,0,700),
|
(4300007,1302009,1,1,0,700),
|
||||||
(4300007,1312007,1,1,0,700),
|
(4300007,1312007,1,1,0,700),
|
||||||
(4300007,1322016,1,1,0,700),
|
(4300007,1322016,1,1,0,700),
|
||||||
@@ -18976,7 +18975,7 @@ USE `maplesolaxia`;
|
|||||||
(4300007,4000526,1,1,0,600000),
|
(4300007,4000526,1,1,0,600000),
|
||||||
(4300007,4004000,1,1,0,10000),
|
(4300007,4004000,1,1,0,10000),
|
||||||
(4300007,4020008,1,1,0,9000),
|
(4300007,4020008,1,1,0,9000),
|
||||||
(4300007,4032506,1,1,2277,999999),
|
(4300007,4032506,1,1,2277,80000),
|
||||||
(4300008,1302009,1,1,0,700),
|
(4300008,1302009,1,1,0,700),
|
||||||
(4300008,1312007,1,1,0,700),
|
(4300008,1312007,1,1,0,700),
|
||||||
(4300008,1322016,1,1,0,700),
|
(4300008,1322016,1,1,0,700),
|
||||||
@@ -19013,7 +19012,7 @@ USE `maplesolaxia`;
|
|||||||
(4300008,4000527,1,1,0,400000),
|
(4300008,4000527,1,1,0,400000),
|
||||||
(4300008,4004000,1,1,0,10000),
|
(4300008,4004000,1,1,0,10000),
|
||||||
(4300008,4020008,1,1,0,9000),
|
(4300008,4020008,1,1,0,9000),
|
||||||
(4300008,4032506,1,1,2277,999999),
|
(4300008,4032506,1,1,2277,80000),
|
||||||
(4300009,1302009,1,1,0,700),
|
(4300009,1302009,1,1,0,700),
|
||||||
(4300009,1312007,1,1,0,700),
|
(4300009,1312007,1,1,0,700),
|
||||||
(4300009,1322016,1,1,0,700),
|
(4300009,1322016,1,1,0,700),
|
||||||
@@ -19207,7 +19206,6 @@ USE `maplesolaxia`;
|
|||||||
(3400004,0,60,80,0,400000),
|
(3400004,0,60,80,0,400000),
|
||||||
(3400005,0,80,85,0,400000),
|
(3400005,0,80,85,0,400000),
|
||||||
(3400006,0,80,90,0,400000),
|
(3400006,0,80,90,0,400000),
|
||||||
(3400007,0,90,100,0,400000),
|
|
||||||
(3400008,0,100,110,0,400000),
|
(3400008,0,100,110,0,400000),
|
||||||
(4300001,0,100,120,0,400000),
|
(4300001,0,100,120,0,400000),
|
||||||
(4300003,0,100,120,0,400000),
|
(4300003,0,100,120,0,400000),
|
||||||
@@ -19792,7 +19790,28 @@ USE `maplesolaxia`;
|
|||||||
(2230111, 4032147, 1, 1, 20723, 40000),
|
(2230111, 4032147, 1, 1, 20723, 40000),
|
||||||
(9300378, 4001272, 1, 1, 0, 400000),
|
(9300378, 4001272, 1, 1, 0, 400000),
|
||||||
(9300378, 4032324, 1, 1, 21736, 40000),
|
(9300378, 4032324, 1, 1, 21736, 40000),
|
||||||
(9300344, 4032322, 1, 1, 21731, 999999);
|
(9300344, 4032322, 1, 1, 21731, 999999),
|
||||||
|
(3400008, 1302008, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1412004, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1422007, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1442009, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1332010, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1372001, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1382002, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1002013, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1002152, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1061047, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1072090, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1002137, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1040023, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1040072, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1060062, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1082049, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1082072, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1072081, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1332031, 1, 1, 0, 8500),
|
||||||
|
(3400008, 1482003, 1, 1, 0, 8500),
|
||||||
|
(3400008, 4032508, 1, 1, 2273, 80000);
|
||||||
|
|
||||||
# (dropperid, itemid, minqty, maxqty, questid, chance)
|
# (dropperid, itemid, minqty, maxqty, questid, chance)
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -154,6 +154,7 @@ import constants.skills.ThunderBreaker;
|
|||||||
import net.server.channel.handlers.PartyOperationHandler;
|
import net.server.channel.handlers.PartyOperationHandler;
|
||||||
import scripting.item.ItemScriptManager;
|
import scripting.item.ItemScriptManager;
|
||||||
import server.maps.MapleMapItem;
|
import server.maps.MapleMapItem;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||||
private static NumberFormat nf = new DecimalFormat("#,###,###,###");
|
private static NumberFormat nf = new DecimalFormat("#,###,###,###");
|
||||||
@@ -270,10 +271,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
|||||||
private ScheduledFuture<?> extraRecoveryTask = null;
|
private ScheduledFuture<?> extraRecoveryTask = null;
|
||||||
private ScheduledFuture<?> chairRecoveryTask = null;
|
private ScheduledFuture<?> chairRecoveryTask = null;
|
||||||
private ScheduledFuture<?> pendantOfSpirit = null; //1122017
|
private ScheduledFuture<?> pendantOfSpirit = null; //1122017
|
||||||
private Lock chrLock = new ReentrantLock(true);
|
private Lock chrLock = new MonitoredReentrantLock(MonitoredEnums.CHR, true);
|
||||||
private Lock effLock = new ReentrantLock(true);
|
private Lock effLock = new MonitoredReentrantLock(MonitoredEnums.EFF, true);
|
||||||
private Lock petLock = new ReentrantLock(true); // for quest tasks as well
|
private Lock petLock = new MonitoredReentrantLock(MonitoredEnums.PET, true); // for quest tasks as well
|
||||||
private Lock prtLock = new ReentrantLock();
|
private Lock prtLock = new MonitoredReentrantLock(MonitoredEnums.PRT);
|
||||||
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
|
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
|
||||||
private Set<Integer> excludedItems = new LinkedHashSet<>();
|
private Set<Integer> excludedItems = new LinkedHashSet<>();
|
||||||
private List<MapleRing> crushRings = new ArrayList<>();
|
private List<MapleRing> crushRings = new ArrayList<>();
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
|
||||||
import javax.script.ScriptEngine;
|
import javax.script.ScriptEngine;
|
||||||
|
|
||||||
@@ -77,6 +77,7 @@ import tools.FilePrinter;
|
|||||||
import tools.HexTool;
|
import tools.HexTool;
|
||||||
import tools.MapleAESOFB;
|
import tools.MapleAESOFB;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleClient {
|
public class MapleClient {
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ public class MapleClient {
|
|||||||
private int picattempt = 0;
|
private int picattempt = 0;
|
||||||
private byte gender = -1;
|
private byte gender = -1;
|
||||||
private boolean disconnecting = false;
|
private boolean disconnecting = false;
|
||||||
private final Lock lock = new ReentrantLock(true);
|
private final Lock lock = new MonitoredReentrantLock(MonitoredEnums.CLIENT, true);
|
||||||
private int votePoints;
|
private int votePoints;
|
||||||
private int voteTime = -1;
|
private int voteTime = -1;
|
||||||
private long lastNpcClick;
|
private long lastNpcClick;
|
||||||
@@ -832,7 +833,7 @@ public class MapleClient {
|
|||||||
|
|
||||||
removePlayer();
|
removePlayer();
|
||||||
player.saveCooldowns();
|
player.saveCooldowns();
|
||||||
player.saveToDB();
|
player.saveToDB(true);
|
||||||
|
|
||||||
player = null;
|
player = null;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -31,16 +31,17 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public final class MonsterBook {
|
public final class MonsterBook {
|
||||||
private int specialCard = 0;
|
private int specialCard = 0;
|
||||||
private int normalCard = 0;
|
private int normalCard = 0;
|
||||||
private int bookLevel = 1;
|
private int bookLevel = 1;
|
||||||
private Map<Integer, Integer> cards = new LinkedHashMap<>();
|
private Map<Integer, Integer> cards = new LinkedHashMap<>();
|
||||||
private Lock lock = new ReentrantLock();
|
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.BOOK);
|
||||||
|
|
||||||
private Set<Entry<Integer, Integer>> getCardSet() {
|
private Set<Entry<Integer, Integer>> getCardSet() {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ public class Commands {
|
|||||||
|
|
||||||
case "time":
|
case "time":
|
||||||
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
|
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
|
||||||
dateFormat.setTimeZone(TimeZone.getTimeZone("-GMT3"));
|
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||||
player.yellowMessage("Solaxia Server Time: " + dateFormat.format(new Date()));
|
player.yellowMessage("Solaxia Server Time: " + dateFormat.format(new Date()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -741,7 +741,7 @@ public class Commands {
|
|||||||
player.yellowMessage("Players on this map:");
|
player.yellowMessage("Players on this map:");
|
||||||
for (MapleMapObject mmo : player.getMap().getPlayers()) {
|
for (MapleMapObject mmo : player.getMap().getPlayers()) {
|
||||||
MapleCharacter chr = (MapleCharacter) mmo;
|
MapleCharacter chr = (MapleCharacter) mmo;
|
||||||
player.dropMessage(5, ">> " + chr.getName());
|
player.dropMessage(5, ">> " + chr.getName() + " - " + chr.getId() + " - Oid: " + chr.getObjectId());
|
||||||
}
|
}
|
||||||
player.yellowMessage("NPCs on this map:");
|
player.yellowMessage("NPCs on this map:");
|
||||||
for (MapleMapObject npcs : player.getMap().getMapObjects()) {
|
for (MapleMapObject npcs : player.getMap().getMapObjects()) {
|
||||||
@@ -755,7 +755,7 @@ public class Commands {
|
|||||||
if (mobs instanceof MapleMonster) {
|
if (mobs instanceof MapleMonster) {
|
||||||
MapleMonster mob = (MapleMonster) mobs;
|
MapleMonster mob = (MapleMonster) mobs;
|
||||||
if(mob.isAlive()){
|
if(mob.isAlive()){
|
||||||
player.dropMessage(5, ">> " + mob.getName() + " - " + mob.getId());
|
player.dropMessage(5, ">> " + mob.getName() + " - " + mob.getId() + " - Oid: " + mob.getObjectId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ import java.sql.SQLException;
|
|||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -45,7 +47,7 @@ public enum ItemFactory {
|
|||||||
MERCHANT(6, false);
|
MERCHANT(6, false);
|
||||||
private final int value;
|
private final int value;
|
||||||
private final boolean account;
|
private final boolean account;
|
||||||
private static final ReentrantLock lock = new ReentrantLock(true);
|
private static final Lock lock = new MonitoredReentrantLock(MonitoredEnums.ITEM, true);
|
||||||
|
|
||||||
private ItemFactory(int value, boolean account) {
|
private ItemFactory(int value, boolean account) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import java.util.List;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
import client.MapleCharacter;
|
import client.MapleCharacter;
|
||||||
@@ -39,6 +39,7 @@ import constants.ItemConstants;
|
|||||||
import server.MapleItemInformationProvider;
|
import server.MapleItemInformationProvider;
|
||||||
import server.MapleInventoryManipulator;
|
import server.MapleInventoryManipulator;
|
||||||
import tools.FilePrinter;
|
import tools.FilePrinter;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -50,7 +51,7 @@ public class MapleInventory implements Iterable<Item> {
|
|||||||
private byte slotLimit;
|
private byte slotLimit;
|
||||||
private MapleInventoryType type;
|
private MapleInventoryType type;
|
||||||
private boolean checked = false;
|
private boolean checked = false;
|
||||||
private Lock lock = new ReentrantLock(true);
|
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.INVENTORY, true);
|
||||||
|
|
||||||
public MapleInventory(MapleCharacter mc, MapleInventoryType type, byte slotLimit) {
|
public MapleInventory(MapleCharacter mc, MapleInventoryType type, byte slotLimit) {
|
||||||
this.owner = mc;
|
this.owner = mc;
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ public class ServerConstants {
|
|||||||
public static String DB_URL = "";
|
public static String DB_URL = "";
|
||||||
public static String DB_USER = "";
|
public static String DB_USER = "";
|
||||||
public static String DB_PASS = "";
|
public static String DB_PASS = "";
|
||||||
public static final boolean DB_EXPERIMENTAL_POOL = true; //[EXPERIMENTAL] Installs a connection pool to hub DB connections. Set false to default.
|
public static final boolean DB_EXPERIMENTAL_POOL = true; //[EXPERIMENTAL] Installs a connection pool to hub DB connections. Set false to default.
|
||||||
|
public static final boolean USE_THREAD_TRACKER = true; //[WARNING] This deadlock auditing thing will bloat the memory as fast as the time frame one takes to lose track of a raindrop on a tempesting day. Only for debug purposes.
|
||||||
|
|
||||||
//World And Version
|
//World And Version
|
||||||
public static short VERSION = 83;
|
public static short VERSION = 83;
|
||||||
|
public static String TIMEZONE = "-GMT3";
|
||||||
public static String[] WORLD_NAMES = {"Scania", "Bera", "Broa", "Windia", "Khaini", "Bellocan", "Mardia", "Kradia", "Yellonde", "Demethos", "Galicia", "El Nido", "Zenith", "Arcenia", "Kastia", "Judis", "Plana", "Kalluna", "Stius", "Croa", "Medere"};
|
public static String[] WORLD_NAMES = {"Scania", "Bera", "Broa", "Windia", "Khaini", "Bellocan", "Mardia", "Kradia", "Yellonde", "Demethos", "Galicia", "El Nido", "Zenith", "Arcenia", "Kastia", "Judis", "Plana", "Kalluna", "Stius", "Croa", "Medere"};
|
||||||
|
|
||||||
//Login Configuration
|
//Login Configuration
|
||||||
@@ -85,6 +87,7 @@ public class ServerConstants {
|
|||||||
//Dangling Items Configuration
|
//Dangling Items Configuration
|
||||||
public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes.
|
public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes.
|
||||||
public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
|
public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
|
||||||
|
public static final int LOCK_MONITOR_TIME = 30 * 1000; //Waiting time for a lock to be released. If it reach timed out, a critical server deadlock has made present.
|
||||||
public static final int ITEM_EXPIRE_CHECK = 10 * 1000; //Interval between item expiring tasks on maps, which checks and makes disappear expired items.
|
public static final int ITEM_EXPIRE_CHECK = 10 * 1000; //Interval between item expiring tasks on maps, which checks and makes disappear expired items.
|
||||||
public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
|
public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
|
||||||
|
|
||||||
|
|||||||
@@ -43,13 +43,14 @@ import client.MapleClient;
|
|||||||
import constants.ServerConstants;
|
import constants.ServerConstants;
|
||||||
|
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import server.TimerManager;
|
import server.TimerManager;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleServerHandler extends IoHandlerAdapter {
|
public class MapleServerHandler extends IoHandlerAdapter {
|
||||||
|
|
||||||
@@ -58,8 +59,8 @@ public class MapleServerHandler extends IoHandlerAdapter {
|
|||||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
|
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
|
||||||
private static AtomicLong sessionId = new AtomicLong(7777);
|
private static AtomicLong sessionId = new AtomicLong(7777);
|
||||||
|
|
||||||
private Lock idleLock = new ReentrantLock(true);
|
private Lock idleLock = new MonitoredReentrantLock(MonitoredEnums.SHANDLER_IDLE, true);
|
||||||
private Lock tempLock = new ReentrantLock(true);
|
private Lock tempLock = new MonitoredReentrantLock(MonitoredEnums.SHANDLER_TEMP, true);
|
||||||
private Map<MapleClient, Long> idleSessions = new HashMap<>(100);
|
private Map<MapleClient, Long> idleSessions = new HashMap<>(100);
|
||||||
private Map<MapleClient, Long> tempIdleSessions = new HashMap<>();
|
private Map<MapleClient, Long> tempIdleSessions = new HashMap<>();
|
||||||
private ScheduledFuture<?> idleManager = null;
|
private ScheduledFuture<?> idleManager = null;
|
||||||
|
|||||||
@@ -35,27 +35,28 @@ public class MaplePacketEncoder implements ProtocolEncoder {
|
|||||||
public void encode(final IoSession session, final Object message, final ProtocolEncoderOutput out) throws Exception {
|
public void encode(final IoSession session, final Object message, final ProtocolEncoderOutput out) throws Exception {
|
||||||
final MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
final MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
||||||
|
|
||||||
if (client != null) {
|
try {
|
||||||
final MapleAESOFB send_crypto = client.getSendCrypto();
|
|
||||||
final byte[] input = (byte[]) message;
|
|
||||||
final byte[] unencrypted = new byte[input.length];
|
|
||||||
System.arraycopy(input, 0, unencrypted, 0, input.length);
|
|
||||||
final byte[] ret = new byte[unencrypted.length + 4];
|
|
||||||
final byte[] header = send_crypto.getPacketHeader(unencrypted.length);
|
|
||||||
MapleCustomEncryption.encryptData(unencrypted);
|
|
||||||
|
|
||||||
client.lockClient();
|
client.lockClient();
|
||||||
try {
|
try {
|
||||||
|
final MapleAESOFB send_crypto = client.getSendCrypto();
|
||||||
|
final byte[] input = (byte[]) message;
|
||||||
|
final byte[] unencrypted = new byte[input.length];
|
||||||
|
System.arraycopy(input, 0, unencrypted, 0, input.length);
|
||||||
|
final byte[] ret = new byte[unencrypted.length + 4];
|
||||||
|
final byte[] header = send_crypto.getPacketHeader(unencrypted.length);
|
||||||
|
MapleCustomEncryption.encryptData(unencrypted);
|
||||||
|
|
||||||
send_crypto.crypt(unencrypted);
|
send_crypto.crypt(unencrypted);
|
||||||
System.arraycopy(header, 0, ret, 0, 4);
|
System.arraycopy(header, 0, ret, 0, 4);
|
||||||
System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
|
System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
|
||||||
|
|
||||||
out.write(IoBuffer.wrap(ret));
|
out.write(IoBuffer.wrap(ret));
|
||||||
} finally {
|
} finally {
|
||||||
client.unlockClient();
|
client.unlockClient();
|
||||||
}
|
}
|
||||||
// System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
|
// System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
|
||||||
// out.write(ByteBuffer.wrap(ret));
|
// out.write(ByteBuffer.wrap(ret));
|
||||||
} else {
|
} catch (NullPointerException npe) {
|
||||||
out.write(IoBuffer.wrap(((byte[]) message)));
|
out.write(IoBuffer.wrap(((byte[]) message)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredEnums;
|
||||||
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -33,7 +34,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
*/
|
*/
|
||||||
public class PlayerBuffStorage {
|
public class PlayerBuffStorage {
|
||||||
private int id = (int) (Math.random() * 100);
|
private int id = (int) (Math.random() * 100);
|
||||||
private final Lock lock = new ReentrantLock(true);
|
private final Lock lock = new MonitoredReentrantLock(MonitoredEnums.BUFF_STORAGE, true);
|
||||||
private Map<Integer, List<PlayerBuffValueHolder>> buffs = new HashMap<>();
|
private Map<Integer, List<PlayerBuffValueHolder>> buffs = new HashMap<>();
|
||||||
|
|
||||||
public void addBuffsToStorage(int chrid, List<PlayerBuffValueHolder> toStore) {
|
public void addBuffsToStorage(int chrid, List<PlayerBuffValueHolder> toStore) {
|
||||||
|
|||||||
@@ -26,12 +26,14 @@ import java.util.Collection;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class PlayerStorage {
|
public class PlayerStorage {
|
||||||
private final ReentrantReadWriteLock locks = new ReentrantReadWriteLock(true);
|
private final ReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredEnums.PLAYER_STORAGE, true);
|
||||||
private final ReadLock rlock = locks.readLock();
|
private final ReadLock rlock = locks.readLock();
|
||||||
private final WriteLock wlock = locks.writeLock();
|
private final WriteLock wlock = locks.writeLock();
|
||||||
private final Map<Integer, MapleCharacter> storage = new LinkedHashMap<>();
|
private final Map<Integer, MapleCharacter> storage = new LinkedHashMap<>();
|
||||||
|
|||||||
@@ -33,15 +33,16 @@ import java.sql.SQLException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
import net.MapleServerHandler;
|
import net.MapleServerHandler;
|
||||||
import net.mina.MapleCodecFactory;
|
import net.mina.MapleCodecFactory;
|
||||||
@@ -70,11 +71,13 @@ import client.SkillFactory;
|
|||||||
import constants.ItemConstants;
|
import constants.ItemConstants;
|
||||||
import constants.ServerConstants;
|
import constants.ServerConstants;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import net.server.audit.ThreadTracker;
|
||||||
import server.quest.MapleQuest;
|
import server.quest.MapleQuest;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class Server implements Runnable {
|
public class Server implements Runnable {
|
||||||
private static final Set<Integer> activeFly = new HashSet<>();
|
private static final Set<Integer> activeFly = new HashSet<>();
|
||||||
private static final Map<Integer, Integer> couponRates = new LinkedHashMap<>();
|
private static final Map<Integer, Integer> couponRates = new HashMap<>(30);
|
||||||
private static final List<Integer> activeCoupons = new LinkedList<>();
|
private static final List<Integer> activeCoupons = new LinkedList<>();
|
||||||
|
|
||||||
private IoAcceptor acceptor;
|
private IoAcceptor acceptor;
|
||||||
@@ -83,11 +86,12 @@ public class Server implements Runnable {
|
|||||||
private final Properties subnetInfo = new Properties();
|
private final Properties subnetInfo = new Properties();
|
||||||
private static Server instance = null;
|
private static Server instance = null;
|
||||||
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
|
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
|
||||||
private final Map<Integer, MapleGuild> guilds = new LinkedHashMap<>();
|
private final Map<Integer, MapleGuild> guilds = new HashMap<>(100);
|
||||||
private final Map<MapleClient, Long> inLoginState = new LinkedHashMap<>();
|
private final Map<MapleClient, Long> inLoginState = new HashMap<>(100);
|
||||||
private final Lock srvLock = new ReentrantLock();
|
private final Lock srvLock = new MonitoredReentrantLock(MonitoredEnums.SERVER);
|
||||||
private final PlayerBuffStorage buffStorage = new PlayerBuffStorage();
|
private final PlayerBuffStorage buffStorage = new PlayerBuffStorage();
|
||||||
private final Map<Integer, MapleAlliance> alliances = new LinkedHashMap<>();
|
private final Map<Integer, MapleAlliance> alliances = new HashMap<>(100);
|
||||||
|
|
||||||
private boolean online = false;
|
private boolean online = false;
|
||||||
public static long uptime = System.currentTimeMillis();
|
public static long uptime = System.currentTimeMillis();
|
||||||
|
|
||||||
@@ -302,6 +306,8 @@ public class Server implements Runnable {
|
|||||||
MapleQuest.loadAllQuest();
|
MapleQuest.loadAllQuest();
|
||||||
System.out.println("Quest loaded in " + ((System.currentTimeMillis() - timeToTake) / 1000.0) + " seconds\r\n");
|
System.out.println("Quest loaded in " + ((System.currentTimeMillis() - timeToTake) / 1000.0) + " seconds\r\n");
|
||||||
|
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) ThreadTracker.getInstance().registerThreadTrackerTask();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Integer worldCount = Math.min(ServerConstants.WORLD_NAMES.length, Integer.parseInt(p.getProperty("worlds")));
|
Integer worldCount = Math.min(ServerConstants.WORLD_NAMES.length, Integer.parseInt(p.getProperty("worlds")));
|
||||||
|
|
||||||
@@ -317,7 +323,7 @@ public class Server implements Runnable {
|
|||||||
|
|
||||||
worldRecommendedList.add(new Pair<>(i, p.getProperty("whyamirecommended" + i)));
|
worldRecommendedList.add(new Pair<>(i, p.getProperty("whyamirecommended" + i)));
|
||||||
worlds.add(world);
|
worlds.add(world);
|
||||||
channels.add(new LinkedHashMap<Integer, String>());
|
channels.add(new HashMap<Integer, String>());
|
||||||
for (int j = 0; j < Integer.parseInt(p.getProperty("channels" + i)); j++) {
|
for (int j = 0; j < Integer.parseInt(p.getProperty("channels" + i)); j++) {
|
||||||
int channelid = j + 1;
|
int channelid = j + 1;
|
||||||
Channel channel = new Channel(i, channelid);
|
Channel channel = new Channel(i, channelid);
|
||||||
@@ -808,6 +814,8 @@ public class Server implements Runnable {
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) ThreadTracker.getInstance().cancelThreadTrackerTask();
|
||||||
|
|
||||||
TimerManager.getInstance().purge();
|
TimerManager.getInstance().purge();
|
||||||
TimerManager.getInstance().stop();
|
TimerManager.getInstance().stop();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,281 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MapleSolaxiaV2 Maple Story Server
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 RonanLana
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package net.server.audit;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import server.TimerManager;
|
||||||
|
import tools.FilePrinter;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
import constants.ServerConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author RonanLana
|
||||||
|
*
|
||||||
|
* This tool has the main purpose of auditing deadlocks throughout the server and must be used only for debugging. The flag is USE_THREAD_TRACKER.
|
||||||
|
*/
|
||||||
|
public class ThreadTracker {
|
||||||
|
private static ThreadTracker instance = null;
|
||||||
|
private final Lock ttLock = new ReentrantLock(true);
|
||||||
|
|
||||||
|
private final Map<Long, List<MonitoredEnums>> threadTracker = new HashMap<>();
|
||||||
|
private final Map<Long, Integer> threadUpdate = new HashMap<>();
|
||||||
|
private final Map<Long, Thread> threads = new HashMap<>();
|
||||||
|
|
||||||
|
private final Map<Long, AtomicInteger> lockCount = new HashMap<>();
|
||||||
|
private final Map<Long, MonitoredEnums> lockIds = new HashMap<>();
|
||||||
|
private final Map<Long, Long> lockThreads = new HashMap<>();
|
||||||
|
private final Map<Long, Byte> lockUpdate = new HashMap<>();
|
||||||
|
|
||||||
|
private final Map<MonitoredEnums, Map<Long, Integer>> locks = new HashMap<>();
|
||||||
|
ScheduledFuture<?> threadTrackerSchedule;
|
||||||
|
|
||||||
|
private String printThreadTrackerState(String dateFormat) {
|
||||||
|
|
||||||
|
Map<MonitoredEnums, List<Integer>> lockValues = new HashMap<>();
|
||||||
|
Set<Long> executingThreads = new HashSet<>();
|
||||||
|
|
||||||
|
for(Map.Entry<Long, AtomicInteger> lock : lockCount.entrySet()) {
|
||||||
|
if(lock.getValue().get() != 0) {
|
||||||
|
executingThreads.add(lockThreads.get(lock.getKey()));
|
||||||
|
|
||||||
|
MonitoredEnums lockId = lockIds.get(lock.getKey());
|
||||||
|
List<Integer> list = lockValues.get(lockId);
|
||||||
|
|
||||||
|
if(list == null) {
|
||||||
|
list = new ArrayList<>();
|
||||||
|
lockValues.put(lockId, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.add(lock.getValue().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String s = "----------------------------\r\n" + dateFormat + "\r\n ";
|
||||||
|
s += "Lock-thread usage count:";
|
||||||
|
for(Map.Entry<MonitoredEnums, List<Integer>> lock : lockValues.entrySet()) {
|
||||||
|
s += ("\r\n " + lock.getKey().name() + ": ");
|
||||||
|
|
||||||
|
for(Integer i : lock.getValue()) {
|
||||||
|
s += (i + " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s += "\r\n\r\nThread opened lock path:";
|
||||||
|
|
||||||
|
for(Long tid : executingThreads) {
|
||||||
|
s += "\r\n";
|
||||||
|
for(MonitoredEnums lockid : threadTracker.get(tid)) {
|
||||||
|
s += (lockid.name() + " ");
|
||||||
|
}
|
||||||
|
s += "|";
|
||||||
|
}
|
||||||
|
|
||||||
|
s += "\r\n\r\n";
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String printThreadLog(List<MonitoredEnums> stillLockedPath, String dateFormat) {
|
||||||
|
String s = "----------------------------\r\n" + dateFormat + "\r\n ";
|
||||||
|
for(MonitoredEnums lock : stillLockedPath) {
|
||||||
|
s += (lock.name() + " ");
|
||||||
|
}
|
||||||
|
s += "\r\n\r\n";
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String printThreadStack(StackTraceElement[] list, String dateFormat) {
|
||||||
|
String s = "----------------------------\r\n" + dateFormat + "\r\n";
|
||||||
|
for(int i = 0; i < list.length; i++) {
|
||||||
|
s += (" " + list[i].toString() + "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accessThreadTracker(boolean update, boolean lock, MonitoredEnums lockId, long lockOid) {
|
||||||
|
ttLock.lock();
|
||||||
|
try {
|
||||||
|
if(update) {
|
||||||
|
if(!lock) { // update tracker
|
||||||
|
List<Long> toRemove = new ArrayList<>();
|
||||||
|
|
||||||
|
for(Long l : threadUpdate.keySet()) {
|
||||||
|
int next = threadUpdate.get(l) + 1;
|
||||||
|
if(next == 4) {
|
||||||
|
List<MonitoredEnums> tt = threadTracker.get(l);
|
||||||
|
|
||||||
|
if(tt.isEmpty()) {
|
||||||
|
toRemove.add(l);
|
||||||
|
} else {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||||
|
String df = dateFormat.format(new Date());
|
||||||
|
|
||||||
|
FilePrinter.print(FilePrinter.DEADLOCK_LOCKS, printThreadLog(tt, df));
|
||||||
|
FilePrinter.print(FilePrinter.DEADLOCK_STACK, printThreadStack(threads.get(l).getStackTrace(), df));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
threadUpdate.put(l, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Long l : toRemove) {
|
||||||
|
threadTracker.remove(l);
|
||||||
|
threadUpdate.remove(l);
|
||||||
|
threads.remove(l);
|
||||||
|
|
||||||
|
for(Map<Long, Integer> threadLock : locks.values()) {
|
||||||
|
threadLock.remove(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toRemove.clear();
|
||||||
|
|
||||||
|
for(Entry<Long, Byte> it : lockUpdate.entrySet()) {
|
||||||
|
byte val = (byte)(it.getValue() + 1);
|
||||||
|
|
||||||
|
if(val < 60) { // free the structure after 60 silent updates
|
||||||
|
lockUpdate.put(it.getKey(), val);
|
||||||
|
} else {
|
||||||
|
toRemove.add(it.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Long l : toRemove) {
|
||||||
|
lockCount.remove(l);
|
||||||
|
lockIds.remove(l);
|
||||||
|
lockThreads.remove(l);
|
||||||
|
lockUpdate.remove(l);
|
||||||
|
}
|
||||||
|
} else { // print status
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||||
|
|
||||||
|
FilePrinter.printError(FilePrinter.DEADLOCK_STATE, printThreadTrackerState(dateFormat.format(new Date())));
|
||||||
|
//FilePrinter.printError(FilePrinter.DEADLOCK_STATE, "[" + dateFormat.format(new Date()) + "] Presenting current lock path for lockid " + lockId.name() + ".\r\n" + printLockStatus(lockId) + "\r\n-------------------------------\r\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
long tid = Thread.currentThread().getId();
|
||||||
|
|
||||||
|
if(lock) {
|
||||||
|
AtomicInteger c = lockCount.get(lockOid);
|
||||||
|
if(c == null) {
|
||||||
|
c = new AtomicInteger(0);
|
||||||
|
lockCount.put(lockOid, c);
|
||||||
|
lockIds.put(lockOid, lockId);
|
||||||
|
lockThreads.put(lockOid, tid);
|
||||||
|
lockUpdate.put(lockOid, (byte) 0);
|
||||||
|
}
|
||||||
|
c.incrementAndGet();
|
||||||
|
|
||||||
|
List<MonitoredEnums> list = threadTracker.get(tid);
|
||||||
|
if(list == null) {
|
||||||
|
list = new ArrayList<>(20);
|
||||||
|
threadTracker.put(tid, list);
|
||||||
|
threadUpdate.put(tid, 0);
|
||||||
|
threads.put(tid, Thread.currentThread());
|
||||||
|
}
|
||||||
|
list.add(lockId);
|
||||||
|
|
||||||
|
Map<Long, Integer> threadLock = locks.get(lockId);
|
||||||
|
if(threadLock == null) {
|
||||||
|
threadLock = new HashMap<>(5);
|
||||||
|
locks.put(lockId, threadLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer lc = threadLock.get(tid);
|
||||||
|
if(lc != null) {
|
||||||
|
threadLock.put(tid, lc + 1);
|
||||||
|
} else {
|
||||||
|
threadLock.put(tid, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AtomicInteger c = lockCount.get(lockOid);
|
||||||
|
c.decrementAndGet();
|
||||||
|
lockUpdate.put(lockOid, (byte) 0);
|
||||||
|
|
||||||
|
List<MonitoredEnums> list = threadTracker.get(tid);
|
||||||
|
for(int i = list.size() - 1; i >= 0; i--) {
|
||||||
|
if(lockId.getValue() == list.get(i).getValue()) {
|
||||||
|
list.remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, Integer> threadLock = locks.get(lockId);
|
||||||
|
threadLock.put(tid, threadLock.get(tid) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
ttLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String printLockStatus(MonitoredEnums lockId) {
|
||||||
|
String s = "";
|
||||||
|
|
||||||
|
for(Long threadid : locks.get(lockId).keySet()) {
|
||||||
|
for(MonitoredEnums lockid : threadTracker.get(threadid)) {
|
||||||
|
s += (" " + lockid.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
s += " |\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerThreadTrackerTask() {
|
||||||
|
threadTrackerSchedule = TimerManager.getInstance().register(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
accessThreadTracker(true, false, MonitoredEnums.UNDEFINED, -1);
|
||||||
|
}
|
||||||
|
}, 10000, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelThreadTrackerTask() {
|
||||||
|
threadTrackerSchedule.cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ThreadTracker getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new ThreadTracker();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,7 +33,8 @@ import java.util.Map.Entry;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||||
@@ -67,6 +68,7 @@ import tools.MaplePacketCreator;
|
|||||||
import client.MapleCharacter;
|
import client.MapleCharacter;
|
||||||
import constants.ServerConstants;
|
import constants.ServerConstants;
|
||||||
import server.maps.MapleMiniDungeonInfo;
|
import server.maps.MapleMiniDungeonInfo;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public final class Channel {
|
public final class Channel {
|
||||||
|
|
||||||
@@ -90,11 +92,11 @@ public final class Channel {
|
|||||||
private Map<Integer, Integer> dojoParty = new HashMap<>();
|
private Map<Integer, Integer> dojoParty = new HashMap<>();
|
||||||
private Map<Integer, MapleMiniDungeon> dungeons = new HashMap<>();
|
private Map<Integer, MapleMiniDungeon> dungeons = new HashMap<>();
|
||||||
|
|
||||||
private ReentrantReadWriteLock merchantLock = new ReentrantReadWriteLock(true);
|
private ReentrantReadWriteLock merchantLock = new MonitoredReentrantReadWriteLock(MonitoredEnums.MERCHANT, true);
|
||||||
private ReadLock merchRlock = merchantLock.readLock();
|
private ReadLock merchRlock = merchantLock.readLock();
|
||||||
private WriteLock merchWlock = merchantLock.writeLock();
|
private WriteLock merchWlock = merchantLock.writeLock();
|
||||||
|
|
||||||
private Lock lock = new ReentrantLock(true);
|
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.CHANNEL, true);
|
||||||
|
|
||||||
public Channel(final int world, final int channel) {
|
public Channel(final int world, final int channel) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public final class ReportHandler extends AbstractMaplePacketHandler {
|
|||||||
public void addReport(int reporterid, int victimid, int reason, String description, String chatlog) {
|
public void addReport(int reporterid, int victimid, int reason, String description, String chatlog) {
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
Timestamp currentTimestamp = new java.sql.Timestamp(calendar.getTime().getTime());
|
Timestamp currentTimestamp = new java.sql.Timestamp(calendar.getTime().getTime());
|
||||||
Connection con = null;
|
Connection con;
|
||||||
try {
|
try {
|
||||||
con = DatabaseConnection.getConnection();
|
con = DatabaseConnection.getConnection();
|
||||||
PreparedStatement ps = con.prepareStatement("INSERT INTO reports (`reporttime`, `reporterid`, `victimid`, `reason`, `chatlog`, `description`) VALUES (?, ?, ?, ?, ?, ?)");
|
PreparedStatement ps = con.prepareStatement("INSERT INTO reports (`reporttime`, `reporterid`, `victimid`, `reason`, `chatlog`, `description`) VALUES (?, ?, ?, ?, ?, ?)");
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import server.life.MobAttackInfoFactory;
|
|||||||
import server.life.MobSkill;
|
import server.life.MobSkill;
|
||||||
import server.life.MobSkillFactory;
|
import server.life.MobSkillFactory;
|
||||||
import server.maps.MapleMap;
|
import server.maps.MapleMap;
|
||||||
|
import server.maps.MapleMapObject;
|
||||||
import tools.FilePrinter;
|
import tools.FilePrinter;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import tools.Randomizer;
|
import tools.Randomizer;
|
||||||
@@ -78,9 +79,17 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
|
|||||||
oid = slea.readInt();
|
oid = slea.readInt();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
attacker = (MapleMonster) map.getMapObject(oid);
|
MapleMapObject mmo = map.getMapObject(oid);
|
||||||
List<loseItem> loseItems;
|
if(mmo instanceof MapleMonster) {
|
||||||
|
attacker = (MapleMonster) mmo;
|
||||||
|
if(attacker.getId() != monsteridfrom) {
|
||||||
|
attacker = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (attacker != null) {
|
if (attacker != null) {
|
||||||
|
List<loseItem> loseItems;
|
||||||
|
|
||||||
if (attacker.isBuffed(MonsterStatus.NEUTRALISE)) {
|
if (attacker.isBuffed(MonsterStatus.NEUTRALISE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -119,10 +128,8 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
|
|||||||
} catch(ClassCastException e) {
|
} catch(ClassCastException e) {
|
||||||
//this happens due to mob on last map damaging player just before changing maps
|
//this happens due to mob on last map damaging player just before changing maps
|
||||||
|
|
||||||
if(ServerConstants.USE_DEBUG) {
|
e.printStackTrace();
|
||||||
e.printStackTrace();
|
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Attacker is not a mob-type, rather is a " + map.getMapObject(oid).getClass().getName() + " entity.");
|
||||||
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Attacker is not a mob-type, rather is a " + map.getMapObject(oid).getClass().getName() + " entity.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,12 +36,13 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
|
||||||
import net.server.Server;
|
import net.server.Server;
|
||||||
import net.server.channel.Channel;
|
import net.server.channel.Channel;
|
||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleGuild {
|
public class MapleGuild {
|
||||||
public final static int CREATE_GUILD_COST = 1500000;
|
public final static int CREATE_GUILD_COST = 1500000;
|
||||||
@@ -52,7 +53,7 @@ public class MapleGuild {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final List<MapleGuildCharacter> members;
|
private final List<MapleGuildCharacter> members;
|
||||||
private final Lock membersLock = new ReentrantLock(true);
|
private final Lock membersLock = new MonitoredReentrantLock(MonitoredEnums.GUILD, true);
|
||||||
|
|
||||||
private String rankTitles[] = new String[5]; // 1 = master, 2 = jr, 5 = lowest member
|
private String rankTitles[] = new String[5]; // 1 = master, 2 = jr, 5 = lowest member
|
||||||
private String name, notice;
|
private String name, notice;
|
||||||
|
|||||||
@@ -30,8 +30,9 @@ import java.util.HashMap;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleParty {
|
public class MapleParty {
|
||||||
private int id;
|
private int id;
|
||||||
@@ -43,7 +44,7 @@ public class MapleParty {
|
|||||||
private Map<Integer, Integer> histMembers = new HashMap<>();
|
private Map<Integer, Integer> histMembers = new HashMap<>();
|
||||||
private int nextEntry = 0;
|
private int nextEntry = 0;
|
||||||
|
|
||||||
private Lock lock = new ReentrantLock(true);
|
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.PARTY, true);
|
||||||
|
|
||||||
public MapleParty(int id, MaplePartyCharacter chrfor) {
|
public MapleParty(int id, MaplePartyCharacter chrfor) {
|
||||||
this.leaderId = chrfor.getId();
|
this.leaderId = chrfor.getId();
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
@@ -68,6 +68,7 @@ import server.maps.AbstractMapleMapObject;
|
|||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -89,25 +90,25 @@ public class World {
|
|||||||
|
|
||||||
private Map<Integer, MapleParty> parties = new HashMap<>();
|
private Map<Integer, MapleParty> parties = new HashMap<>();
|
||||||
private AtomicInteger runningPartyId = new AtomicInteger();
|
private AtomicInteger runningPartyId = new AtomicInteger();
|
||||||
private Lock partyLock = new ReentrantLock(true);
|
private Lock partyLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_PARTY, true);
|
||||||
|
|
||||||
private Map<Integer, Integer> owlSearched = new LinkedHashMap<>();
|
private Map<Integer, Integer> owlSearched = new LinkedHashMap<>();
|
||||||
private Lock owlLock = new ReentrantLock();
|
private Lock owlLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_OWL);
|
||||||
|
|
||||||
private Lock activePetsLock = new ReentrantLock(true);
|
private Lock activePetsLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_PETS, true);
|
||||||
private Map<Integer, Byte> activePets = new LinkedHashMap<>();
|
private Map<Integer, Byte> activePets = new LinkedHashMap<>();
|
||||||
private ScheduledFuture<?> petsSchedule;
|
private ScheduledFuture<?> petsSchedule;
|
||||||
private long petUpdate;
|
private long petUpdate;
|
||||||
|
|
||||||
private Lock activeMountsLock = new ReentrantLock(true);
|
private Lock activeMountsLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_MOUNTS, true);
|
||||||
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
|
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
|
||||||
private ScheduledFuture<?> mountsSchedule;
|
private ScheduledFuture<?> mountsSchedule;
|
||||||
private long mountUpdate;
|
private long mountUpdate;
|
||||||
|
|
||||||
private Lock activePlayerShopsLock = new ReentrantLock(true);
|
private Lock activePlayerShopsLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_PSHOPS, true);
|
||||||
private Map<Integer, MaplePlayerShop> activePlayerShops = new LinkedHashMap<>();
|
private Map<Integer, MaplePlayerShop> activePlayerShops = new LinkedHashMap<>();
|
||||||
|
|
||||||
private Lock activeMerchantsLock = new ReentrantLock(true);
|
private Lock activeMerchantsLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_MERCHS, true);
|
||||||
private Map<Integer, Pair<MapleHiredMerchant, Byte>> activeMerchants = new LinkedHashMap<>();
|
private Map<Integer, Pair<MapleHiredMerchant, Byte>> activeMerchants = new LinkedHashMap<>();
|
||||||
private long merchantUpdate;
|
private long merchantUpdate;
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ import java.util.Set;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||||
@@ -69,6 +70,7 @@ import server.MapleItemInformationProvider;
|
|||||||
import server.life.MapleLifeFactory;
|
import server.life.MapleLifeFactory;
|
||||||
import server.life.MapleNPC;
|
import server.life.MapleNPC;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -90,12 +92,12 @@ public class EventInstanceManager {
|
|||||||
private List<Integer> mapIds = new LinkedList<>();
|
private List<Integer> mapIds = new LinkedList<>();
|
||||||
private List<Boolean> isInstanced = new LinkedList<>();
|
private List<Boolean> isInstanced = new LinkedList<>();
|
||||||
|
|
||||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
|
private final ReentrantReadWriteLock lock = new MonitoredReentrantReadWriteLock(MonitoredEnums.EIM, true);
|
||||||
private final ReadLock rL = lock.readLock();
|
private final ReadLock rL = lock.readLock();
|
||||||
private final WriteLock wL = lock.writeLock();
|
private final WriteLock wL = lock.writeLock();
|
||||||
|
|
||||||
private final Lock pL = new ReentrantLock(true);
|
private final Lock pL = new MonitoredReentrantLock(MonitoredEnums.EIM_PARTY, true);
|
||||||
private final Lock sL = new ReentrantLock();
|
private final Lock sL = new MonitoredReentrantLock(MonitoredEnums.EIM_SCRIPT, true);
|
||||||
|
|
||||||
private ScheduledFuture<?> event_schedule = null;
|
private ScheduledFuture<?> event_schedule = null;
|
||||||
private boolean disposed = false;
|
private boolean disposed = false;
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredEnums;
|
||||||
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -74,8 +75,8 @@ public class EventManager {
|
|||||||
private Integer readyId = 0;
|
private Integer readyId = 0;
|
||||||
private Properties props = new Properties();
|
private Properties props = new Properties();
|
||||||
private String name;
|
private String name;
|
||||||
private Lock lobbyLock = new ReentrantLock();
|
private Lock lobbyLock = new MonitoredReentrantLock(MonitoredEnums.EM_LOBBY);
|
||||||
private Lock queueLock = new ReentrantLock();
|
private Lock queueLock = new MonitoredReentrantLock(MonitoredEnums.EM_QUEUE);
|
||||||
|
|
||||||
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
|
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
|
||||||
import provider.MapleData;
|
import provider.MapleData;
|
||||||
import provider.MapleDataProvider;
|
import provider.MapleDataProvider;
|
||||||
@@ -46,6 +46,7 @@ import client.inventory.MapleInventoryType;
|
|||||||
import client.inventory.MaplePet;
|
import client.inventory.MaplePet;
|
||||||
import constants.ItemConstants;
|
import constants.ItemConstants;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @author Flav
|
* @author Flav
|
||||||
@@ -241,7 +242,7 @@ public class CashShop {
|
|||||||
private List<Item> inventory = new ArrayList<>();
|
private List<Item> inventory = new ArrayList<>();
|
||||||
private List<Integer> wishList = new ArrayList<>();
|
private List<Integer> wishList = new ArrayList<>();
|
||||||
private int notes = 0;
|
private int notes = 0;
|
||||||
private Lock lock = new ReentrantLock();
|
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.CASHSHOP);
|
||||||
|
|
||||||
public CashShop(int accountId, int characterId, int jobType) throws SQLException {
|
public CashShop(int accountId, int characterId, int jobType) throws SQLException {
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
|
|||||||
@@ -32,13 +32,14 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import net.SendOpcode;
|
import net.SendOpcode;
|
||||||
import server.maps.AbstractMapleMapObject;
|
import server.maps.AbstractMapleMapObject;
|
||||||
import server.maps.MapleMapObjectType;
|
import server.maps.MapleMapObjectType;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
import tools.data.output.MaplePacketLittleEndianWriter;
|
import tools.data.output.MaplePacketLittleEndianWriter;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -55,7 +56,7 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
|||||||
private List<String> bannedList = new ArrayList<>();
|
private List<String> bannedList = new ArrayList<>();
|
||||||
private List<Pair<MapleCharacter, String>> chatLog = new LinkedList<>();
|
private List<Pair<MapleCharacter, String>> chatLog = new LinkedList<>();
|
||||||
private Map<Integer, Byte> chatSlot = new LinkedHashMap<>();
|
private Map<Integer, Byte> chatSlot = new LinkedHashMap<>();
|
||||||
private Lock visitorLock = new ReentrantLock(true);
|
private Lock visitorLock = new MonitoredReentrantLock(MonitoredEnums.VISITOR_PSHOP, true);
|
||||||
|
|
||||||
public MaplePlayerShop(MapleCharacter owner, String description) {
|
public MaplePlayerShop(MapleCharacter owner, String description) {
|
||||||
this.setPosition(owner.getPosition());
|
this.setPosition(owner.getPosition());
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -50,7 +51,7 @@ public class MapleStorage {
|
|||||||
private byte slots;
|
private byte slots;
|
||||||
private Map<MapleInventoryType, List<Item>> typeItems = new HashMap<>();
|
private Map<MapleInventoryType, List<Item>> typeItems = new HashMap<>();
|
||||||
private List<Item> items;
|
private List<Item> items;
|
||||||
private Lock lock = new ReentrantLock(true);
|
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.STORAGE, true);
|
||||||
|
|
||||||
private MapleStorage(int id, byte slots, int meso) {
|
private MapleStorage(int id, byte slots, int meso) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import net.server.world.MapleParty;
|
import net.server.world.MapleParty;
|
||||||
import net.server.world.MaplePartyCharacter;
|
import net.server.world.MaplePartyCharacter;
|
||||||
import server.TimerManager;
|
import server.TimerManager;
|
||||||
@@ -62,6 +63,7 @@ import server.maps.MapleMapObjectType;
|
|||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
import tools.Randomizer;
|
import tools.Randomizer;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleMonster extends AbstractLoadedMapleLife {
|
public class MapleMonster extends AbstractLoadedMapleLife {
|
||||||
private ChangeableStats ostats = null; //unused, v83 WZs offers no support for changeable stats.
|
private ChangeableStats ostats = null; //unused, v83 WZs offers no support for changeable stats.
|
||||||
@@ -84,9 +86,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
|||||||
private int team;
|
private int team;
|
||||||
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
|
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
|
||||||
|
|
||||||
private ReentrantLock externalLock = new ReentrantLock();
|
private Lock externalLock = new MonitoredReentrantLock(MonitoredEnums.MOB_EXT);
|
||||||
private ReentrantLock monsterLock = new ReentrantLock(true);
|
private Lock monsterLock = new MonitoredReentrantLock(MonitoredEnums.MOB, true);
|
||||||
private ReentrantLock statiLock = new ReentrantLock();
|
private Lock statiLock = new MonitoredReentrantLock(MonitoredEnums.MOB_STATI);
|
||||||
|
|
||||||
public MapleMonster(int id, MapleMonsterStats stats) {
|
public MapleMonster(int id, MapleMonsterStats stats) {
|
||||||
super(id);
|
super(id);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||||
@@ -34,6 +35,7 @@ import provider.MapleData;
|
|||||||
import provider.MapleDataProvider;
|
import provider.MapleDataProvider;
|
||||||
import provider.MapleDataProviderFactory;
|
import provider.MapleDataProviderFactory;
|
||||||
import provider.MapleDataTool;
|
import provider.MapleDataTool;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -44,7 +46,7 @@ public class MobSkillFactory {
|
|||||||
private static Map<String, MobSkill> mobSkills = new HashMap<String, MobSkill>();
|
private static Map<String, MobSkill> mobSkills = new HashMap<String, MobSkill>();
|
||||||
private final static MapleDataProvider dataSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Skill.wz"));
|
private final static MapleDataProvider dataSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Skill.wz"));
|
||||||
private static MapleData skillRoot = dataSource.getData("MobSkill.img");
|
private static MapleData skillRoot = dataSource.getData("MobSkill.img");
|
||||||
private final static ReentrantReadWriteLock dataLock = new ReentrantReadWriteLock();
|
private final static ReentrantReadWriteLock dataLock = new MonitoredReentrantReadWriteLock(MonitoredEnums.MOBSKILL_FACTORY);
|
||||||
private final static ReadLock rL = dataLock.readLock();
|
private final static ReadLock rL = dataLock.readLock();
|
||||||
private final static WriteLock wL = dataLock.writeLock();
|
private final static WriteLock wL = dataLock.writeLock();
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ import scripting.portal.PortalScriptManager;
|
|||||||
import server.MaplePortal;
|
import server.MaplePortal;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredEnums;
|
||||||
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
|
||||||
public class MapleGenericPortal implements MaplePortal {
|
public class MapleGenericPortal implements MaplePortal {
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ public class MapleGenericPortal implements MaplePortal {
|
|||||||
|
|
||||||
if(scriptName != null) {
|
if(scriptName != null) {
|
||||||
if(scriptLock == null) {
|
if(scriptLock == null) {
|
||||||
scriptLock = new ReentrantLock(false);
|
scriptLock = new MonitoredReentrantLock(MonitoredEnums.PORTAL, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scriptLock = null;
|
scriptLock = null;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import net.server.Server;
|
import net.server.Server;
|
||||||
import server.MapleInventoryManipulator;
|
import server.MapleInventoryManipulator;
|
||||||
import server.MapleItemInformationProvider;
|
import server.MapleItemInformationProvider;
|
||||||
@@ -45,6 +45,7 @@ import server.MaplePlayerShopItem;
|
|||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -63,7 +64,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
|||||||
private List<SoldItem> sold = new LinkedList<>();
|
private List<SoldItem> sold = new LinkedList<>();
|
||||||
private AtomicBoolean open = new AtomicBoolean();
|
private AtomicBoolean open = new AtomicBoolean();
|
||||||
private MapleMap map;
|
private MapleMap map;
|
||||||
private Lock visitorLock = new ReentrantLock(true);
|
private Lock visitorLock = new MonitoredReentrantLock(MonitoredEnums.VISITOR_MERCH, true);
|
||||||
|
|
||||||
public MapleHiredMerchant(final MapleCharacter owner, int itemId, String desc) {
|
public MapleHiredMerchant(final MapleCharacter owner, int itemId, String desc) {
|
||||||
this.setPosition(owner.getPosition());
|
this.setPosition(owner.getPosition());
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import java.util.Map.Entry;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||||
@@ -78,13 +79,14 @@ import server.life.MonsterGlobalDropEntry;
|
|||||||
import server.life.SpawnPoint;
|
import server.life.SpawnPoint;
|
||||||
import server.partyquest.MonsterCarnival;
|
import server.partyquest.MonsterCarnival;
|
||||||
import server.partyquest.MonsterCarnivalParty;
|
import server.partyquest.MonsterCarnivalParty;
|
||||||
import server.partyquest.Pyramid;
|
//import server.partyquest.Pyramid;
|
||||||
import scripting.event.EventInstanceManager;
|
import scripting.event.EventInstanceManager;
|
||||||
import server.life.MonsterListener;
|
import server.life.MonsterListener;
|
||||||
import tools.FilePrinter;
|
import tools.FilePrinter;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
import tools.Randomizer;
|
import tools.Randomizer;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleMap {
|
public class MapleMap {
|
||||||
private static final List<MapleMapObjectType> rangedMapobjectTypes = Arrays.asList(MapleMapObjectType.SHOP, MapleMapObjectType.ITEM, MapleMapObjectType.NPC, MapleMapObjectType.MONSTER, MapleMapObjectType.DOOR, MapleMapObjectType.SUMMON, MapleMapObjectType.REACTOR);
|
private static final List<MapleMapObjectType> rangedMapobjectTypes = Arrays.asList(MapleMapObjectType.SHOP, MapleMapObjectType.ITEM, MapleMapObjectType.NPC, MapleMapObjectType.MONSTER, MapleMapObjectType.DOOR, MapleMapObjectType.SUMMON, MapleMapObjectType.REACTOR);
|
||||||
@@ -161,11 +163,11 @@ public class MapleMap {
|
|||||||
if (this.monsterRate == 0) {
|
if (this.monsterRate == 0) {
|
||||||
this.monsterRate = 1;
|
this.monsterRate = 1;
|
||||||
}
|
}
|
||||||
final ReentrantReadWriteLock chrLock = new ReentrantReadWriteLock(true);
|
final ReentrantReadWriteLock chrLock = new MonitoredReentrantReadWriteLock(MonitoredEnums.MAP_CHRS, true);
|
||||||
chrRLock = chrLock.readLock();
|
chrRLock = chrLock.readLock();
|
||||||
chrWLock = chrLock.writeLock();
|
chrWLock = chrLock.writeLock();
|
||||||
|
|
||||||
final ReentrantReadWriteLock objectLock = new ReentrantReadWriteLock(true);
|
final ReentrantReadWriteLock objectLock = new MonitoredReentrantReadWriteLock(MonitoredEnums.MAP_OBJS, true);
|
||||||
objectRLock = objectLock.readLock();
|
objectRLock = objectLock.readLock();
|
||||||
objectWLock = objectLock.writeLock();
|
objectWLock = objectLock.writeLock();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||||
@@ -46,6 +47,7 @@ import server.life.MapleMonster;
|
|||||||
import scripting.event.EventInstanceManager;
|
import scripting.event.EventInstanceManager;
|
||||||
import tools.DatabaseConnection;
|
import tools.DatabaseConnection;
|
||||||
import tools.StringUtil;
|
import tools.StringUtil;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleMapFactory {
|
public class MapleMapFactory {
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ public class MapleMapFactory {
|
|||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
this.event = eim;
|
this.event = eim;
|
||||||
|
|
||||||
ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock();
|
ReentrantReadWriteLock rrwl = new MonitoredReentrantReadWriteLock(MonitoredEnums.MAP_FACTORY);
|
||||||
this.mapsRLock = rrwl.readLock();
|
this.mapsRLock = rrwl.readLock();
|
||||||
this.mapsWLock = rrwl.writeLock();
|
this.mapsWLock = rrwl.writeLock();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ import client.MapleCharacter;
|
|||||||
import client.MapleClient;
|
import client.MapleClient;
|
||||||
import client.inventory.Item;
|
import client.inventory.Item;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
public class MapleMapItem extends AbstractMapleMapObject {
|
public class MapleMapItem extends AbstractMapleMapObject {
|
||||||
|
|
||||||
@@ -35,7 +37,7 @@ public class MapleMapItem extends AbstractMapleMapObject {
|
|||||||
protected byte type;
|
protected byte type;
|
||||||
protected boolean pickedUp = false, playerDrop;
|
protected boolean pickedUp = false, playerDrop;
|
||||||
protected long dropTime;
|
protected long dropTime;
|
||||||
private ReentrantLock itemLock = new ReentrantLock();
|
private Lock itemLock = new MonitoredReentrantLock(MonitoredEnums.MAP_ITEM);
|
||||||
|
|
||||||
public MapleMapItem(Item item, Point position, MapleMapObject dropper, MapleCharacter owner, byte type, boolean playerDrop) {
|
public MapleMapItem(Item item, Point position, MapleMapObject dropper, MapleCharacter owner, byte type, boolean playerDrop) {
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ import java.util.List;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -35,7 +36,7 @@ import tools.MaplePacketCreator;
|
|||||||
public class MapleMiniDungeon {
|
public class MapleMiniDungeon {
|
||||||
List<MapleCharacter> players = new ArrayList<>();
|
List<MapleCharacter> players = new ArrayList<>();
|
||||||
ScheduledFuture<?> timeoutTask = null;
|
ScheduledFuture<?> timeoutTask = null;
|
||||||
Lock lock = new ReentrantLock(true);
|
Lock lock = new MonitoredReentrantLock(MonitoredEnums.MINIDUNGEON, true);
|
||||||
|
|
||||||
int baseMap;
|
int baseMap;
|
||||||
long expireTime;
|
long expireTime;
|
||||||
|
|||||||
@@ -29,12 +29,13 @@ import java.util.List;
|
|||||||
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import tools.locks.MonitoredReentrantLock;
|
||||||
|
|
||||||
import scripting.reactor.ReactorScriptManager;
|
import scripting.reactor.ReactorScriptManager;
|
||||||
import server.TimerManager;
|
import server.TimerManager;
|
||||||
import tools.MaplePacketCreator;
|
import tools.MaplePacketCreator;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
|
import tools.locks.MonitoredEnums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -53,7 +54,7 @@ public class MapleReactor extends AbstractMapleMapObject {
|
|||||||
private boolean shouldCollect;
|
private boolean shouldCollect;
|
||||||
private boolean attackHit;
|
private boolean attackHit;
|
||||||
private ScheduledFuture<?> timeoutTask = null;
|
private ScheduledFuture<?> timeoutTask = null;
|
||||||
private Lock reactorLock = new ReentrantLock(true);
|
private Lock reactorLock = new MonitoredReentrantLock(MonitoredEnums.REACTOR, true);
|
||||||
|
|
||||||
public MapleReactor(MapleReactorStats stats, int rid) {
|
public MapleReactor(MapleReactorStats stats, int rid) {
|
||||||
this.evstate = (byte)0;
|
this.evstate = (byte)0;
|
||||||
|
|||||||
@@ -44,7 +44,11 @@ public class FilePrinter {
|
|||||||
QUEST_UNCODED = "uncodedQuests.txt",
|
QUEST_UNCODED = "uncodedQuests.txt",
|
||||||
AUTOSAVING_CHARACTER = "saveCharAuto.txt",
|
AUTOSAVING_CHARACTER = "saveCharAuto.txt",
|
||||||
SAVING_CHARACTER = "saveChar.txt",
|
SAVING_CHARACTER = "saveChar.txt",
|
||||||
USED_COMMANDS = "usedCommands.txt";//more to come (maps)
|
USED_COMMANDS = "usedCommands.txt",
|
||||||
|
DEADLOCK_ERROR = "deadlocks.txt",
|
||||||
|
DEADLOCK_STACK = "deadlocks/path.txt",
|
||||||
|
DEADLOCK_LOCKS = "deadlocks/locks.txt",
|
||||||
|
DEADLOCK_STATE = "deadlocks/state.txt";
|
||||||
|
|
||||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //for file system purposes, it's nice to use yyyy-MM-dd
|
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //for file system purposes, it's nice to use yyyy-MM-dd
|
||||||
private static final String FILE_PATH = "logs/" + sdf.format(Calendar.getInstance().getTime()) + "/"; // + sdf.format(Calendar.getInstance().getTime()) + "/"
|
private static final String FILE_PATH = "logs/" + sdf.format(Calendar.getInstance().getTime()) + "/"; // + sdf.format(Calendar.getInstance().getTime()) + "/"
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MapleSolaxiaV2 Maple Story Server
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 RonanLana
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package tools.locks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author RonanLana
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum MonitoredEnums {
|
||||||
|
UNDEFINED(-1),
|
||||||
|
CHR(0),
|
||||||
|
EFF(1),
|
||||||
|
PET(2),
|
||||||
|
PRT(3),
|
||||||
|
CLIENT(4),
|
||||||
|
BOOK(5),
|
||||||
|
ITEM(6),
|
||||||
|
INVENTORY(7),
|
||||||
|
SHANDLER_IDLE(8),
|
||||||
|
SHANDLER_TEMP(9),
|
||||||
|
BUFF_STORAGE(10),
|
||||||
|
PLAYER_STORAGE(11),
|
||||||
|
SERVER(12),
|
||||||
|
MERCHANT(13),
|
||||||
|
CHANNEL(14),
|
||||||
|
GUILD(15),
|
||||||
|
PARTY(16),
|
||||||
|
WORLD_PARTY(17),
|
||||||
|
WORLD_OWL(18),
|
||||||
|
WORLD_PETS(19),
|
||||||
|
WORLD_MOUNTS(20),
|
||||||
|
WORLD_PSHOPS(21),
|
||||||
|
WORLD_MERCHS(21),
|
||||||
|
EIM(22),
|
||||||
|
EIM_PARTY(23),
|
||||||
|
EIM_SCRIPT(24),
|
||||||
|
EM_LOBBY(25),
|
||||||
|
EM_QUEUE(26),
|
||||||
|
CASHSHOP(27),
|
||||||
|
VISITOR_PSHOP(28),
|
||||||
|
STORAGE(29),
|
||||||
|
MOB_EXT(30),
|
||||||
|
MOB(31),
|
||||||
|
MOB_STATI(32),
|
||||||
|
MOBSKILL_FACTORY(33),
|
||||||
|
PORTAL(34),
|
||||||
|
VISITOR_MERCH(35),
|
||||||
|
MAP_CHRS(36),
|
||||||
|
MAP_OBJS(37),
|
||||||
|
MAP_FACTORY(38),
|
||||||
|
MAP_ITEM(39),
|
||||||
|
MINIDUNGEON(40),
|
||||||
|
REACTOR(41);
|
||||||
|
|
||||||
|
private final int i;
|
||||||
|
|
||||||
|
private MonitoredEnums(int val) {
|
||||||
|
this.i = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MapleSolaxiaV2 Maple Story Server
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 RonanLana
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package tools.locks;
|
||||||
|
|
||||||
|
import constants.ServerConstants;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import server.TimerManager;
|
||||||
|
import net.server.Server;
|
||||||
|
import net.server.audit.ThreadTracker;
|
||||||
|
|
||||||
|
import tools.FilePrinter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author RonanLana
|
||||||
|
*/
|
||||||
|
public class MonitoredReadLock extends ReentrantReadWriteLock.ReadLock {
|
||||||
|
private ScheduledFuture<?> timeoutSchedule = null;
|
||||||
|
private StackTraceElement[] deadlockedState = null;
|
||||||
|
private final MonitoredEnums id;
|
||||||
|
private final int hashcode;
|
||||||
|
private final Lock state = new ReentrantLock(true);
|
||||||
|
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||||
|
|
||||||
|
public MonitoredReadLock(MonitoredReentrantReadWriteLock lock) {
|
||||||
|
super(lock);
|
||||||
|
this.id = lock.id;
|
||||||
|
hashcode = this.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lock() {
|
||||||
|
super.lock();
|
||||||
|
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
if(deadlockedState != null) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||||
|
|
||||||
|
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||||
|
deadlockedState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLocking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlock() {
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
unregisterLocking();
|
||||||
|
}
|
||||||
|
super.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryLock() {
|
||||||
|
if(super.tryLock()) {
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
if(deadlockedState != null) {
|
||||||
|
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||||
|
deadlockedState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLocking();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerLocking() {
|
||||||
|
state.lock();
|
||||||
|
try {
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
|
||||||
|
|
||||||
|
if(reentrantCount.incrementAndGet() == 1) {
|
||||||
|
final Thread t = Thread.currentThread();
|
||||||
|
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
issueDeadlock(t);
|
||||||
|
}
|
||||||
|
}, ServerConstants.LOCK_MONITOR_TIME);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
state.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterLocking() {
|
||||||
|
state.lock();
|
||||||
|
try {
|
||||||
|
if(reentrantCount.decrementAndGet() == 0) {
|
||||||
|
if(timeoutSchedule != null) {
|
||||||
|
timeoutSchedule.cancel(false);
|
||||||
|
timeoutSchedule = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
|
||||||
|
} finally {
|
||||||
|
state.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void issueDeadlock(Thread t) {
|
||||||
|
deadlockedState = t.getStackTrace();
|
||||||
|
//super.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String printStackTrace(StackTraceElement[] list) {
|
||||||
|
String s = "";
|
||||||
|
for(int i = 0; i < list.length; i++) {
|
||||||
|
s += (" " + list[i].toString() + "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MapleSolaxiaV2 Maple Story Server
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 RonanLana
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package tools.locks;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import constants.ServerConstants;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import server.TimerManager;
|
||||||
|
import net.server.Server;
|
||||||
|
import net.server.audit.ThreadTracker;
|
||||||
|
import tools.FilePrinter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author RonanLana
|
||||||
|
*/
|
||||||
|
public class MonitoredReentrantLock extends ReentrantLock {
|
||||||
|
private ScheduledFuture<?> timeoutSchedule = null;
|
||||||
|
private StackTraceElement[] deadlockedState = null;
|
||||||
|
private final MonitoredEnums id;
|
||||||
|
private final int hashcode;
|
||||||
|
private final Lock state = new ReentrantLock(true);
|
||||||
|
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||||
|
|
||||||
|
public MonitoredReentrantLock(MonitoredEnums id) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
hashcode = this.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoredReentrantLock(MonitoredEnums id, boolean fair) {
|
||||||
|
super(fair);
|
||||||
|
this.id = id;
|
||||||
|
hashcode = this.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lock() {
|
||||||
|
super.lock();
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
if(deadlockedState != null) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||||
|
|
||||||
|
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||||
|
deadlockedState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLocking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlock() {
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
unregisterLocking();
|
||||||
|
}
|
||||||
|
super.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryLock() {
|
||||||
|
if(super.tryLock()) {
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
if(deadlockedState != null) {
|
||||||
|
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||||
|
deadlockedState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLocking();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerLocking() {
|
||||||
|
state.lock();
|
||||||
|
try {
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
|
||||||
|
|
||||||
|
if(reentrantCount.incrementAndGet() == 1) {
|
||||||
|
final Thread t = Thread.currentThread();
|
||||||
|
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
issueDeadlock(t);
|
||||||
|
}
|
||||||
|
}, ServerConstants.LOCK_MONITOR_TIME);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
state.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterLocking() {
|
||||||
|
state.lock();
|
||||||
|
try {
|
||||||
|
if(reentrantCount.decrementAndGet() == 0) {
|
||||||
|
if(timeoutSchedule != null) {
|
||||||
|
timeoutSchedule.cancel(false);
|
||||||
|
timeoutSchedule = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
|
||||||
|
} finally {
|
||||||
|
state.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void issueDeadlock(Thread t) {
|
||||||
|
deadlockedState = t.getStackTrace();
|
||||||
|
//super.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String printStackTrace(StackTraceElement[] list) {
|
||||||
|
String s = "";
|
||||||
|
for(int i = 0; i < list.length; i++) {
|
||||||
|
s += (" " + list[i].toString() + "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MapleSolaxiaV2 Maple Story Server
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 RonanLana
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package tools.locks;
|
||||||
|
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author RonanLana
|
||||||
|
*/
|
||||||
|
public class MonitoredReentrantReadWriteLock extends ReentrantReadWriteLock {
|
||||||
|
public final MonitoredEnums id;
|
||||||
|
|
||||||
|
public MonitoredReentrantReadWriteLock(MonitoredEnums id) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonitoredReentrantReadWriteLock(MonitoredEnums id, boolean fair) {
|
||||||
|
super(fair);
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReadLock readLock() {
|
||||||
|
return super.readLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WriteLock writeLock() {
|
||||||
|
return super.writeLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MapleSolaxiaV2 Maple Story Server
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 RonanLana
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package tools.locks;
|
||||||
|
|
||||||
|
import constants.ServerConstants;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import server.TimerManager;
|
||||||
|
import net.server.Server;
|
||||||
|
import net.server.audit.ThreadTracker;
|
||||||
|
import tools.FilePrinter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author RonanLana
|
||||||
|
*/
|
||||||
|
public class MonitoredWriteLock extends ReentrantReadWriteLock.WriteLock {
|
||||||
|
private ScheduledFuture<?> timeoutSchedule = null;
|
||||||
|
private StackTraceElement[] deadlockedState = null;
|
||||||
|
private final MonitoredEnums id;
|
||||||
|
private final int hashcode;
|
||||||
|
private final Lock state = new ReentrantLock(true);
|
||||||
|
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||||
|
|
||||||
|
public MonitoredWriteLock(MonitoredReentrantReadWriteLock lock) {
|
||||||
|
super(lock);
|
||||||
|
this.id = lock.id;
|
||||||
|
hashcode = this.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lock() {
|
||||||
|
super.lock();
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
if(deadlockedState != null) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||||
|
|
||||||
|
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||||
|
deadlockedState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLocking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlock() {
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
unregisterLocking();
|
||||||
|
}
|
||||||
|
super.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryLock() {
|
||||||
|
if(super.tryLock()) {
|
||||||
|
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||||
|
if(deadlockedState != null) {
|
||||||
|
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||||
|
deadlockedState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLocking();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerLocking() {
|
||||||
|
state.lock();
|
||||||
|
try {
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
|
||||||
|
|
||||||
|
if(reentrantCount.incrementAndGet() == 1) {
|
||||||
|
final Thread t = Thread.currentThread();
|
||||||
|
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
issueDeadlock(t);
|
||||||
|
}
|
||||||
|
}, ServerConstants.LOCK_MONITOR_TIME);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
state.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterLocking() {
|
||||||
|
state.lock();
|
||||||
|
try {
|
||||||
|
if(reentrantCount.decrementAndGet() == 0) {
|
||||||
|
if(timeoutSchedule != null) {
|
||||||
|
timeoutSchedule.cancel(false);
|
||||||
|
timeoutSchedule = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
|
||||||
|
} finally {
|
||||||
|
state.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void issueDeadlock(Thread t) {
|
||||||
|
deadlockedState = t.getStackTrace();
|
||||||
|
//super.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String printStackTrace(StackTraceElement[] list) {
|
||||||
|
String s = "";
|
||||||
|
for(int i = 0; i < list.length; i++) {
|
||||||
|
s += (" " + list[i].toString() + "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -1,14 +1,24 @@
|
|||||||
Red Potion
|
Gladius
|
||||||
Lemon
|
Niam
|
||||||
W. Ramen
|
Titan
|
||||||
Elixir
|
Crescent Polearm
|
||||||
Mana Elixir
|
Iron Dagger
|
||||||
Mushroom Miso Ramen
|
White Crusader Chainmail (Male)
|
||||||
Power Elixir
|
Wizard Wand
|
||||||
Lunar Gloves
|
Wizard Staff
|
||||||
LeFay Jester
|
Golden Pride
|
||||||
Eclipse Earrings
|
Blue Guiltian
|
||||||
Herculean Crown
|
Red Amorian Skirt (Female)
|
||||||
Lockewood Hat
|
Red Salt Shoes
|
||||||
Pickpocket Pilfer
|
Green Pole-Feather Hat
|
||||||
Eclipse Cloak
|
Black Bennis Chainmail (Male)
|
||||||
|
Red Legolier (Male)
|
||||||
|
Blue Legolier Pants (Male)
|
||||||
|
Green Marker
|
||||||
|
Gold Brace
|
||||||
|
Green Hunter Boots
|
||||||
|
Dragon Toenail
|
||||||
|
Rouge Way
|
||||||
|
Guardian Katara
|
||||||
|
Justice Katara
|
||||||
|
Norman Grip
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
1302008
|
||||||
|
1412004
|
||||||
|
1422007
|
||||||
|
1442009
|
||||||
|
1332010
|
||||||
|
1372001
|
||||||
|
1382002
|
||||||
|
1002013
|
||||||
|
1002152
|
||||||
|
1061047
|
||||||
|
1072090
|
||||||
|
1002137
|
||||||
|
1040023
|
||||||
|
1040072
|
||||||
|
1060062
|
||||||
|
1082049
|
||||||
|
1082072
|
||||||
|
1072081
|
||||||
|
1332031
|
||||||
|
1482003
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
compile.on.save=true
|
compile.on.save=true
|
||||||
user.properties.file=C:\\Users\\USER\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
|
user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
|
||||||
@@ -41,9 +41,11 @@ import java.util.ArrayList;
|
|||||||
* Set whether you are first installing the handbook on the SQL Server (TRUE) or just fetching whatever is on your "fetch.txt"
|
* Set whether you are first installing the handbook on the SQL Server (TRUE) or just fetching whatever is on your "fetch.txt"
|
||||||
* file (FALSE) on the INSTALL_SQLTABLE property and build the project. With all done, run the Java executable.
|
* file (FALSE) on the INSTALL_SQLTABLE property and build the project. With all done, run the Java executable.
|
||||||
*
|
*
|
||||||
|
* Expected installing time: 30 minutes
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class MapleIdRetriever {
|
public class MapleIdRetriever {
|
||||||
private final static boolean INSTALL_SQLTABLE = true;
|
private final static boolean INSTALL_SQLTABLE = false;
|
||||||
|
|
||||||
static String host = "jdbc:mysql://localhost:3306/maplesolaxia";
|
static String host = "jdbc:mysql://localhost:3306/maplesolaxia";
|
||||||
static String driver = "com.mysql.jdbc.Driver";
|
static String driver = "com.mysql.jdbc.Driver";
|
||||||
@@ -83,7 +85,12 @@ public class MapleIdRetriever {
|
|||||||
|
|
||||||
if(tokens.length > 1) {
|
if(tokens.length > 1) {
|
||||||
PreparedStatement ps = con.prepareStatement("INSERT INTO `handbook` (`id`, `name`) VALUES (?, ?)");
|
PreparedStatement ps = con.prepareStatement("INSERT INTO `handbook` (`id`, `name`) VALUES (?, ?)");
|
||||||
ps.setInt(1, Integer.parseInt(tokens[0]));
|
try {
|
||||||
|
ps.setInt(1, Integer.parseInt(tokens[0]));
|
||||||
|
} catch (NumberFormatException npe) { // odd...
|
||||||
|
String num = tokens[0].substring(1);
|
||||||
|
ps.setInt(1, Integer.parseInt(num));
|
||||||
|
}
|
||||||
ps.setString(2, tokens[1]);
|
ps.setString(2, tokens[1]);
|
||||||
ps.execute();
|
ps.execute();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user