@@ -158,9 +158,6 @@ worlds:
|
||||
|
||||
|
||||
server:
|
||||
#Thread Tracker Configuration
|
||||
USE_THREAD_TRACKER: false #[SEVERE] 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 debugging purposes.
|
||||
|
||||
#Database Configuration
|
||||
DB_URL_FORMAT: "jdbc:mysql://%s:3306/cosmic"
|
||||
DB_HOST: "localhost"
|
||||
|
||||
@@ -21,13 +21,6 @@ package client;
|
||||
|
||||
import config.YamlConfig;
|
||||
import constants.game.GameConstants;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import server.maps.AbstractAnimatedMapObject;
|
||||
import server.maps.MapleMap;
|
||||
|
||||
@@ -35,6 +28,9 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
@@ -50,14 +46,14 @@ public abstract class AbstractCharacterObject extends AbstractAnimatedMapObject
|
||||
private AbstractCharacterListener listener = null;
|
||||
protected Map<Stat, Integer> statUpdates = new HashMap<>();
|
||||
|
||||
protected Lock effLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EFF, true);
|
||||
protected MonitoredReadLock statRlock;
|
||||
protected MonitoredWriteLock statWlock;
|
||||
protected final Lock effLock = new ReentrantLock(true);
|
||||
protected final Lock statRlock;
|
||||
protected final Lock statWlock;
|
||||
|
||||
protected AbstractCharacterObject() {
|
||||
MonitoredReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.CHARACTER_STA, true);
|
||||
statRlock = MonitoredReadLockFactory.createLock(locks);
|
||||
statWlock = MonitoredWriteLockFactory.createLock(locks);
|
||||
ReadWriteLock statLock = new ReentrantReadWriteLock(true);
|
||||
this.statRlock = statLock.readLock();
|
||||
this.statWlock = statLock.writeLock();
|
||||
|
||||
for (int i = 0; i < remainingSp.length; i++) {
|
||||
remainingSp[i] = 0;
|
||||
|
||||
@@ -45,16 +45,12 @@ import net.packet.Packet;
|
||||
import net.server.PlayerBuffValueHolder;
|
||||
import net.server.PlayerCoolDownValueHolder;
|
||||
import net.server.Server;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.coordinator.world.InviteCoordinator;
|
||||
import net.server.guild.Alliance;
|
||||
import net.server.guild.Guild;
|
||||
import net.server.guild.GuildCharacter;
|
||||
import net.server.guild.GuildPackets;
|
||||
import net.server.services.task.channel.FaceExpressionService;
|
||||
import net.server.services.task.world.CharacterSaveService;
|
||||
import net.server.services.type.ChannelServices;
|
||||
import net.server.services.type.WorldServices;
|
||||
import net.server.world.*;
|
||||
import org.slf4j.Logger;
|
||||
@@ -96,6 +92,7 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -218,11 +215,11 @@ public class Character extends AbstractCharacterObject {
|
||||
private ScheduledFuture<?> chairRecoveryTask = null;
|
||||
private ScheduledFuture<?> pendantOfSpirit = null; //1122017
|
||||
private ScheduledFuture<?> cpqSchedule = null;
|
||||
private final Lock chrLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_CHR, true);
|
||||
private final Lock evtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EVT, true);
|
||||
private final Lock petLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PET, true);
|
||||
private final Lock prtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PRT);
|
||||
private final Lock cpnLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_CPN);
|
||||
private final Lock chrLock = new ReentrantLock(true);
|
||||
private final Lock evtLock = new ReentrantLock(true);
|
||||
private final Lock petLock = new ReentrantLock(true);
|
||||
private final Lock prtLock = new ReentrantLock();
|
||||
private final Lock cpnLock = new ReentrantLock();
|
||||
private final Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
|
||||
private final Set<Integer> excludedItems = new LinkedHashSet<>();
|
||||
private final Set<Integer> disabledPartySearchInvites = new LinkedHashSet<>();
|
||||
@@ -2754,11 +2751,10 @@ public class Character extends AbstractCharacterObject {
|
||||
|
||||
public void changeFaceExpression(int emote) {
|
||||
long timeNow = Server.getInstance().getCurrentTime();
|
||||
if (timeNow - lastExpression > 2000) {
|
||||
// Client allows changing every 2 seconds. Give it a little bit of overhead for packet delays.
|
||||
if (timeNow - lastExpression > 1500) {
|
||||
lastExpression = timeNow;
|
||||
|
||||
FaceExpressionService service = (FaceExpressionService) client.getChannelServer().getServiceAccess(ChannelServices.FACE_EXPRESSION);
|
||||
service.registerFaceExpression(map, this, emote);
|
||||
getMap().broadcastMessage(this, PacketCreator.facialExpression(this, emote), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ import net.packet.Packet;
|
||||
import net.packet.logging.LoggingUtil;
|
||||
import net.packet.logging.MonitoredChrLogger;
|
||||
import net.server.Server;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.coordinator.login.LoginBypassCoordinator;
|
||||
import net.server.coordinator.session.Hwid;
|
||||
@@ -81,6 +79,7 @@ import java.util.Date;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
@@ -122,9 +121,9 @@ public class Client extends ChannelInboundHandlerAdapter {
|
||||
private byte gender = -1;
|
||||
private boolean disconnecting = false;
|
||||
private final Semaphore actionsSemaphore = new Semaphore(7);
|
||||
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true);
|
||||
private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true);
|
||||
private final Lock announcerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ANNOUNCER, true);
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
private final Lock encoderLock = new ReentrantLock(true);
|
||||
private final Lock announcerLock = new ReentrantLock(true);
|
||||
// thanks Masterrulax & try2hack for pointing out a bottleneck issue with shared locks, shavit for noticing an opportunity for improvement
|
||||
private Calendar tempBanCalendar;
|
||||
private int votePoints;
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
*/
|
||||
package client;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.PacketCreator;
|
||||
|
||||
@@ -33,13 +31,14 @@ import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public final class MonsterBook {
|
||||
private int specialCard = 0;
|
||||
private int normalCard = 0;
|
||||
private int bookLevel = 1;
|
||||
private final Map<Integer, Integer> cards = new LinkedHashMap<>();
|
||||
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.BOOK);
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
public Set<Entry<Integer, Integer>> getCardSet() {
|
||||
lock.lock();
|
||||
|
||||
@@ -126,7 +126,7 @@ public class CommandsExecutor {
|
||||
|
||||
private void addCommandInfo(String name, Class<? extends Command> commandClass) {
|
||||
try {
|
||||
levelCommandsCursor.getRight().add(commandClass.newInstance().getDescription());
|
||||
levelCommandsCursor.getRight().add(commandClass.getDeclaredConstructor().newInstance().getDescription());
|
||||
levelCommandsCursor.getLeft().add(name);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -161,14 +161,12 @@ public class CommandsExecutor {
|
||||
addCommandInfo(commandName, commandClass);
|
||||
|
||||
try {
|
||||
Command commandInstance = commandClass.newInstance(); // thanks Halcyon for noticing commands getting reinstanced every call
|
||||
Command commandInstance = commandClass.getDeclaredConstructor().newInstance(); // thanks Halcyon for noticing commands getting reinstanced every call
|
||||
commandInstance.setRank(rank);
|
||||
|
||||
registeredCommands.put(commandName, commandInstance);
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to create command instance", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ import client.Character;
|
||||
import client.Client;
|
||||
import client.inventory.manipulator.InventoryManipulator;
|
||||
import constants.inventory.ItemConstants;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.ItemInformationProvider;
|
||||
@@ -36,6 +34,7 @@ import tools.Pair;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Matze, Ronan
|
||||
@@ -44,7 +43,7 @@ public class Inventory implements Iterable<Item> {
|
||||
private static final Logger log = LoggerFactory.getLogger(Inventory.class);
|
||||
protected final Map<Short, Item> inventory;
|
||||
protected final InventoryType type;
|
||||
protected final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.INVENTORY, true);
|
||||
protected final Lock lock = new ReentrantLock(true);
|
||||
|
||||
protected Character owner;
|
||||
protected byte slotLimit;
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
*/
|
||||
package client.inventory;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.Pair;
|
||||
|
||||
@@ -29,6 +27,7 @@ import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Flav
|
||||
@@ -52,7 +51,7 @@ public enum ItemFactory {
|
||||
|
||||
static {
|
||||
for (int i = 0; i < lockCount; i++) {
|
||||
locks[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.ITEM, true);
|
||||
locks[i] = new ReentrantLock(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ServerConfig {
|
||||
//Thread Tracker Configuration
|
||||
public boolean USE_THREAD_TRACKER;
|
||||
|
||||
//Database Configuration
|
||||
public String DB_URL_FORMAT;
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
package net.server;
|
||||
|
||||
import client.Disease;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.life.MobSkill;
|
||||
import tools.Pair;
|
||||
|
||||
@@ -31,6 +29,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Danny//changed to map :3
|
||||
@@ -38,7 +37,7 @@ import java.util.concurrent.locks.Lock;
|
||||
*/
|
||||
public class PlayerBuffStorage {
|
||||
private final int id = (int) (Math.random() * 100);
|
||||
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.BUFF_STORAGE, true);
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
private final Map<Integer, List<PlayerBuffValueHolder>> buffs = new HashMap<>();
|
||||
private final Map<Integer, Map<Disease, Pair<Long, MobSkill>>> diseases = new HashMap<>();
|
||||
|
||||
|
||||
@@ -23,21 +23,23 @@ package net.server;
|
||||
|
||||
import client.Character;
|
||||
import client.Client;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class PlayerStorage {
|
||||
private final MonitoredReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.PLAYER_STORAGE, true);
|
||||
private final Map<Integer, Character> storage = new LinkedHashMap<>();
|
||||
private final Map<String, Character> nameStorage = new LinkedHashMap<>();
|
||||
private final MonitoredReadLock rlock = MonitoredReadLockFactory.createLock(locks);
|
||||
private final MonitoredWriteLock wlock = MonitoredWriteLockFactory.createLock(locks);
|
||||
private final Lock rlock;
|
||||
private final Lock wlock;
|
||||
|
||||
public PlayerStorage() {
|
||||
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
|
||||
this.rlock = readWriteLock.readLock();
|
||||
this.wlock = readWriteLock.writeLock();
|
||||
}
|
||||
|
||||
public void addPlayer(Character chr) {
|
||||
wlock.lock();
|
||||
|
||||
@@ -37,14 +37,6 @@ import constants.net.OpcodeConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import net.netty.LoginServer;
|
||||
import net.packet.Packet;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.coordinator.session.IpAddresses;
|
||||
import net.server.coordinator.session.SessionCoordinator;
|
||||
@@ -79,6 +71,9 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.*;
|
||||
|
||||
@@ -117,16 +112,14 @@ public class Server {
|
||||
|
||||
private final List<List<Pair<String, Integer>>> playerRanking = new LinkedList<>();
|
||||
|
||||
private final Lock srvLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.SERVER);
|
||||
private final Lock disLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.SERVER_DISEASES);
|
||||
private final Lock srvLock = new ReentrantLock();
|
||||
private final Lock disLock = new ReentrantLock();
|
||||
|
||||
private final MonitoredReentrantReadWriteLock wldLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.SERVER_WORLDS, true);
|
||||
private final MonitoredReadLock wldRLock = MonitoredReadLockFactory.createLock(wldLock);
|
||||
private final MonitoredWriteLock wldWLock = MonitoredWriteLockFactory.createLock(wldLock);
|
||||
private final Lock wldRLock;
|
||||
private final Lock wldWLock;
|
||||
|
||||
private final MonitoredReentrantReadWriteLock lgnLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.SERVER_LOGIN, true);
|
||||
private final MonitoredReadLock lgnRLock = MonitoredReadLockFactory.createLock(lgnLock);
|
||||
private final MonitoredWriteLock lgnWLock = MonitoredWriteLockFactory.createLock(lgnLock);
|
||||
private final Lock lgnRLock;
|
||||
private final Lock lgnWLock;
|
||||
|
||||
private final AtomicLong currentTime = new AtomicLong(0);
|
||||
private long serverCurrentTime = 0;
|
||||
@@ -135,6 +128,16 @@ public class Server {
|
||||
private boolean online = false;
|
||||
public static long uptime = System.currentTimeMillis();
|
||||
|
||||
private Server() {
|
||||
ReadWriteLock worldLock = new ReentrantReadWriteLock(true);
|
||||
this.wldRLock = worldLock.readLock();
|
||||
this.wldWLock = worldLock.writeLock();
|
||||
|
||||
ReadWriteLock loginLock = new ReentrantReadWriteLock(true);
|
||||
this.lgnRLock = loginLock.readLock();
|
||||
this.lgnWLock = loginLock.writeLock();
|
||||
}
|
||||
|
||||
public int getCurrentTimestamp() {
|
||||
return (int) (Server.getInstance().getCurrentTime() - Server.uptime);
|
||||
}
|
||||
@@ -865,10 +868,6 @@ public class Server {
|
||||
ThreadManager.getInstance().start();
|
||||
initializeTimelyTasks(); // aggregated method for timely tasks thanks to lxconan
|
||||
|
||||
if (YamlConfig.config.server.USE_THREAD_TRACKER) {
|
||||
ThreadTracker.getInstance().registerThreadTrackerTask();
|
||||
}
|
||||
|
||||
try {
|
||||
int worldCount = Math.min(GameConstants.WORLD_NAMES.length, YamlConfig.config.server.WORLDS);
|
||||
|
||||
@@ -941,7 +940,6 @@ public class Server {
|
||||
|
||||
long timeLeft = getTimeLeftForNextHour();
|
||||
tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL);
|
||||
tMan.register(new ReleaseLockTask(), MINUTES.toMillis(2), MINUTES.toMillis(2));
|
||||
tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft);
|
||||
tMan.register(new RankingCommandTask(), MINUTES.toMillis(5), MINUTES.toMillis(5));
|
||||
tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft);
|
||||
@@ -1904,10 +1902,6 @@ public class Server {
|
||||
|
||||
List<Channel> allChannels = getAllChannels();
|
||||
|
||||
if (YamlConfig.config.server.USE_THREAD_TRACKER) {
|
||||
ThreadTracker.getInstance().cancelThreadTrackerTask();
|
||||
}
|
||||
|
||||
for (Channel ch : allChannels) {
|
||||
while (!ch.finishedShutdown()) {
|
||||
try {
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
public class LockCollector {
|
||||
|
||||
private static final LockCollector instance = new LockCollector();
|
||||
|
||||
public static LockCollector getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final Map<Runnable, Integer> disposableLocks = new HashMap<>(200);
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
|
||||
public void registerDisposeAction(Runnable r) {
|
||||
lock.lock();
|
||||
try {
|
||||
disposableLocks.put(r, 0);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void runLockCollector() {
|
||||
List<Runnable> toDispose = new ArrayList<>();
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
for (Entry<Runnable, Integer> e : disposableLocks.entrySet()) {
|
||||
Integer eVal = e.getValue();
|
||||
if (eVal > 5) { // updates each 2min
|
||||
toDispose.add(e.getKey());
|
||||
} else {
|
||||
disposableLocks.put(e.getKey(), ++eVal);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
for (Runnable r : toDispose) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.TimerManager;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
* <p>
|
||||
* 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 final Logger log = LoggerFactory.getLogger(ThreadTracker.class);
|
||||
private static ThreadTracker instance = null;
|
||||
|
||||
public static ThreadTracker getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ThreadTracker();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final Lock ttLock = new ReentrantLock(true);
|
||||
|
||||
private final Map<Long, List<MonitoredLockType>> 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, MonitoredLockType> lockIds = new HashMap<>();
|
||||
private final Map<Long, Long> lockThreads = new HashMap<>();
|
||||
private final Map<Long, Integer> lockUpdate = new HashMap<>();
|
||||
|
||||
private final Map<MonitoredLockType, Map<Long, Integer>> locks = new HashMap<>();
|
||||
ScheduledFuture<?> threadTrackerSchedule;
|
||||
|
||||
private String printThreadTrackerState(String dateFormat) {
|
||||
|
||||
Map<MonitoredLockType, List<Integer>> lockValues = new HashMap<>();
|
||||
Set<Long> executingThreads = new HashSet<>();
|
||||
|
||||
for (Map.Entry<Long, AtomicInteger> lc : lockCount.entrySet()) {
|
||||
if (lc.getValue().get() != 0) {
|
||||
executingThreads.add(lockThreads.get(lc.getKey()));
|
||||
|
||||
MonitoredLockType lockId = lockIds.get(lc.getKey());
|
||||
List<Integer> list = lockValues.get(lockId);
|
||||
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
lockValues.put(lockId, list);
|
||||
}
|
||||
|
||||
list.add(lc.getValue().get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String s = "----------------------------\r\n" + dateFormat + "\r\n ";
|
||||
s += "Lock-thread usage count:";
|
||||
for (Map.Entry<MonitoredLockType, 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 (MonitoredLockType lockid : threadTracker.get(tid)) {
|
||||
s += (lockid.name() + " ");
|
||||
}
|
||||
s += "|";
|
||||
}
|
||||
|
||||
s += "\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private static String printThreadLog(List<MonitoredLockType> stillLockedPath, String dateFormat) {
|
||||
String s = "----------------------------\r\n" + dateFormat + "\r\n ";
|
||||
for (MonitoredLockType 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 (StackTraceElement stackTraceElement : list) {
|
||||
s += (" " + stackTraceElement.toString() + "\r\n");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public void accessThreadTracker(boolean update, boolean lock, MonitoredLockType 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<MonitoredLockType> tt = threadTracker.get(l);
|
||||
|
||||
if (tt.isEmpty()) {
|
||||
toRemove.add(l);
|
||||
} else {
|
||||
StackTraceElement[] ste = threads.get(l).getStackTrace();
|
||||
if (ste.length > 0) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
log.debug("Thread log - {}", printThreadLog(tt, df));
|
||||
log.debug("thread stack - {}", printThreadStack(ste, 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, Integer> it : lockUpdate.entrySet()) {
|
||||
int val = it.getValue() + 1;
|
||||
|
||||
if (val < 60) {
|
||||
lockUpdate.put(it.getKey(), val);
|
||||
} else {
|
||||
toRemove.add(it.getKey()); // free the structure after 60 silent updates
|
||||
}
|
||||
}
|
||||
|
||||
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.getDefault());
|
||||
|
||||
log.error("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-------------------------------");
|
||||
}
|
||||
} 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, 0);
|
||||
}
|
||||
c.incrementAndGet();
|
||||
|
||||
List<MonitoredLockType> list = threadTracker.get(tid);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>(5);
|
||||
threadTracker.put(tid, list);
|
||||
threadUpdate.put(tid, 0);
|
||||
threads.put(tid, Thread.currentThread());
|
||||
} else if (list.isEmpty()) {
|
||||
threadUpdate.put(tid, 0);
|
||||
}
|
||||
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);
|
||||
if (c != null) { // thanks BHB for detecting an NPE here
|
||||
c.decrementAndGet();
|
||||
}
|
||||
|
||||
lockUpdate.put(lockOid, 0);
|
||||
|
||||
List<MonitoredLockType> list = threadTracker.get(tid);
|
||||
for (int i = list.size() - 1; i >= 0; i--) {
|
||||
if (lockId.equals(list.get(i))) {
|
||||
list.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Map<Long, Integer> threadLock = locks.get(lockId);
|
||||
threadLock.put(tid, threadLock.get(tid) - 1);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
ttLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private String printLockStatus(MonitoredLockType lockId) {
|
||||
String s = "";
|
||||
|
||||
for (Long threadid : locks.get(lockId).keySet()) {
|
||||
for (MonitoredLockType lockid : threadTracker.get(threadid)) {
|
||||
s += (" " + lockid.name());
|
||||
}
|
||||
|
||||
s += " |\r\n";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public void registerThreadTrackerTask() {
|
||||
threadTrackerSchedule = TimerManager.getInstance().register(() -> accessThreadTracker(true, false, MonitoredLockType.UNDEFINED, -1), 10000, 10000);
|
||||
}
|
||||
|
||||
public void cancelThreadTrackerTask() {
|
||||
threadTrackerSchedule.cancel(false);
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
|
||||
public enum MonitoredLockType {
|
||||
UNDEFINED,
|
||||
INTERVAL,
|
||||
CHARACTER_CHR,
|
||||
CHARACTER_CPN,
|
||||
CHARACTER_EFF,
|
||||
CHARACTER_PET,
|
||||
CHARACTER_PRT,
|
||||
CHARACTER_EVT,
|
||||
CHARACTER_STA,
|
||||
CLIENT,
|
||||
CLIENT_ANNOUNCER,
|
||||
CLIENT_ENCODER,
|
||||
CLIENT_SESSION,
|
||||
CLIENT_LOGIN,
|
||||
BOOK,
|
||||
ITEM,
|
||||
INVENTORY,
|
||||
SRVHANDLER_IDLE,
|
||||
SRVHANDLER_TEMP,
|
||||
BUFF_STORAGE,
|
||||
PLAYER_STORAGE,
|
||||
PLAYER_DOOR,
|
||||
SERVER,
|
||||
SERVER_DISEASES,
|
||||
SERVER_LOGIN,
|
||||
SERVER_LOGIN_COORD,
|
||||
SERVER_WORLDS,
|
||||
MERCHANT,
|
||||
CHANNEL,
|
||||
CHANNEL_EVENTS,
|
||||
CHANNEL_FACEEXPRS,
|
||||
CHANNEL_FACESCHDL,
|
||||
CHANNEL_MOBACTION,
|
||||
CHANNEL_MOBANIMAT,
|
||||
CHANNEL_MOBMIST,
|
||||
CHANNEL_MOBSKILL,
|
||||
CHANNEL_MOBSTATUS,
|
||||
CHANNEL_OVTSTATUS,
|
||||
CHANNEL_OVERALL,
|
||||
GUILD,
|
||||
PARTY,
|
||||
WORLD_PARTY,
|
||||
WORLD_PARTY_SEARCH_ECHELON,
|
||||
WORLD_PARTY_SEARCH_QUEUE,
|
||||
WORLD_PARTY_SEARCH_STORAGE,
|
||||
WORLD_SRVMESSAGES,
|
||||
WORLD_PETS,
|
||||
WORLD_CHARS,
|
||||
WORLD_CHANNELS,
|
||||
WORLD_MOUNTS,
|
||||
WORLD_PSHOPS,
|
||||
WORLD_MERCHS,
|
||||
WORLD_MAPOBJS,
|
||||
WORLD_SAVECHARS,
|
||||
WORLD_SUGGEST,
|
||||
EIM,
|
||||
EIM_PARTY,
|
||||
EIM_SCRIPT,
|
||||
EM_LOBBY,
|
||||
EM_QUEUE,
|
||||
EM_SCHDL,
|
||||
EM_START,
|
||||
CASHSHOP,
|
||||
VISITOR_PSHOP,
|
||||
STORAGE,
|
||||
MOB,
|
||||
MOB_AGGRO,
|
||||
MOB_ANI,
|
||||
MOB_EXT,
|
||||
MOB_STATI,
|
||||
MOBSKILL_FACTORY,
|
||||
PORTAL,
|
||||
VISITOR_MERCH,
|
||||
MAP_CHRS,
|
||||
MAP_OBJS,
|
||||
MAP_MANAGER,
|
||||
MAP_ITEM,
|
||||
MAP_LOOT,
|
||||
MAP_BOUNDS,
|
||||
MAP_AGGRO,
|
||||
MAP_AGGRO_IDLE,
|
||||
MINIDUNGEON,
|
||||
REACTOR,
|
||||
REACTOR_HIT
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public interface MonitoredReadLock {
|
||||
|
||||
void lock();
|
||||
|
||||
void unlock();
|
||||
|
||||
boolean tryLock();
|
||||
|
||||
MonitoredReadLock dispose();
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public interface MonitoredReentrantLock {
|
||||
|
||||
void lock();
|
||||
|
||||
void unlock();
|
||||
|
||||
boolean tryLock();
|
||||
|
||||
MonitoredReentrantLock dispose();
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredReentrantReadWriteLock extends ReentrantReadWriteLock {
|
||||
public final MonitoredLockType id;
|
||||
|
||||
public MonitoredReentrantReadWriteLock(MonitoredLockType id) {
|
||||
super();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public MonitoredReentrantReadWriteLock(MonitoredLockType id, boolean fair) {
|
||||
super(fair);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadLock readLock() {
|
||||
return super.readLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WriteLock writeLock() {
|
||||
return super.writeLock();
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public interface MonitoredWriteLock {
|
||||
|
||||
void lock();
|
||||
|
||||
void unlock();
|
||||
|
||||
boolean tryLock();
|
||||
|
||||
MonitoredWriteLock dispose();
|
||||
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.active;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.empty.EmptyReadLock;
|
||||
import server.TimerManager;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
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 java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements MonitoredReadLock {
|
||||
private ScheduledFuture<?> timeoutSchedule = null;
|
||||
private StackTraceElement[] deadlockedState = null;
|
||||
private final MonitoredLockType id;
|
||||
private final int hashcode;
|
||||
private final Lock state = new ReentrantLock(true);
|
||||
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||
|
||||
public TrackerReadLock(MonitoredReentrantReadWriteLock lock) {
|
||||
super(lock);
|
||||
this.id = lock.id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
if (YamlConfig.config.server.USE_THREAD_TRACKER) {
|
||||
if (deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//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));
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
|
||||
super.lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if (YamlConfig.config.server.USE_THREAD_TRACKER) {
|
||||
unregisterLocking();
|
||||
}
|
||||
|
||||
super.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
if (super.tryLock()) {
|
||||
if (YamlConfig.config.server.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));
|
||||
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(() -> issueDeadlock(t), YamlConfig.config.server.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 (StackTraceElement stackTraceElement : list) {
|
||||
s += (" " + stackTraceElement.toString() + "\r\n");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredReadLock dispose() {
|
||||
state.lock();
|
||||
try {
|
||||
if (timeoutSchedule != null) {
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
|
||||
reentrantCount.set(Integer.MAX_VALUE);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
|
||||
//unlock();
|
||||
return new EmptyReadLock(id);
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.active;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.empty.EmptyReentrantLock;
|
||||
import server.TimerManager;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class TrackerReentrantLock extends ReentrantLock implements MonitoredReentrantLock {
|
||||
private ScheduledFuture<?> timeoutSchedule = null;
|
||||
private StackTraceElement[] deadlockedState = null;
|
||||
private final MonitoredLockType id;
|
||||
private final int hashcode;
|
||||
private final Lock state = new ReentrantLock(true);
|
||||
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||
|
||||
public TrackerReentrantLock(MonitoredLockType id) {
|
||||
super();
|
||||
this.id = id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
public TrackerReentrantLock(MonitoredLockType id, boolean fair) {
|
||||
super(fair);
|
||||
this.id = id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
if (YamlConfig.config.server.USE_THREAD_TRACKER) {
|
||||
if (deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//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));
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
|
||||
super.lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if (YamlConfig.config.server.USE_THREAD_TRACKER) {
|
||||
unregisterLocking();
|
||||
}
|
||||
|
||||
super.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
if (super.tryLock()) {
|
||||
if (YamlConfig.config.server.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));
|
||||
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(() -> issueDeadlock(t), YamlConfig.config.server.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 (StackTraceElement stackTraceElement : list) {
|
||||
s += (" " + stackTraceElement.toString() + "\r\n");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredReentrantLock dispose() {
|
||||
state.lock();
|
||||
try {
|
||||
if (timeoutSchedule != null) {
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
|
||||
reentrantCount.set(Integer.MAX_VALUE);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
|
||||
//unlock();
|
||||
return new EmptyReentrantLock(id);
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.active;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.empty.EmptyWriteLock;
|
||||
import server.TimerManager;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
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 java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implements MonitoredWriteLock {
|
||||
private ScheduledFuture<?> timeoutSchedule = null;
|
||||
private StackTraceElement[] deadlockedState = null;
|
||||
private final MonitoredLockType id;
|
||||
private final int hashcode;
|
||||
private final Lock state = new ReentrantLock(true);
|
||||
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||
|
||||
public TrackerWriteLock(MonitoredReentrantReadWriteLock lock) {
|
||||
super(lock);
|
||||
this.id = lock.id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
if (YamlConfig.config.server.USE_THREAD_TRACKER) {
|
||||
if (deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//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));
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
|
||||
super.lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if (YamlConfig.config.server.USE_THREAD_TRACKER) {
|
||||
unregisterLocking();
|
||||
}
|
||||
|
||||
super.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
if (super.tryLock()) {
|
||||
if (YamlConfig.config.server.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));
|
||||
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(() -> issueDeadlock(t), YamlConfig.config.server.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 (StackTraceElement stackTraceElement : list) {
|
||||
s += (" " + stackTraceElement.toString() + "\r\n");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredWriteLock dispose() {
|
||||
state.lock();
|
||||
try {
|
||||
if (timeoutSchedule != null) {
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
|
||||
reentrantCount.set(Integer.MAX_VALUE);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
|
||||
//unlock();
|
||||
return new EmptyWriteLock(id);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public abstract class AbstractEmptyLock {
|
||||
|
||||
protected static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); // DRY-code opportunity performed by jtumidanski
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
for (StackTraceElement stackTraceElement : list) {
|
||||
s += (" " + stackTraceElement.toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyReadLock extends AbstractEmptyLock implements MonitoredReadLock {
|
||||
private static final Logger log = LoggerFactory.getLogger(EmptyReadLock.class);
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyReadLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
log.warn("Captured locking tentative on disposed lock {}: {}", id, printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
log.warn("Captured try-locking tentative on disposed lock {}: {}", id, printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredReadLock dispose() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyReentrantLock extends AbstractEmptyLock implements MonitoredReentrantLock {
|
||||
private static final Logger log = LoggerFactory.getLogger(EmptyReentrantLock.class);
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyReentrantLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
log.warn("Captured locking tentative on disposed lock {}: {}", id, printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
log.warn("Captured try-locking tentative on disposed lock {}: {}", id, printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredReentrantLock dispose() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyWriteLock extends AbstractEmptyLock implements MonitoredWriteLock {
|
||||
private static final Logger log = LoggerFactory.getLogger(EmptyWriteLock.class);
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyWriteLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
log.warn("Captured locking tentative on disposed lock {}: {}", id, printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
log.warn("Captured try-locking tentative on dispsoed lock {}: {}", id, printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredWriteLock dispose() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.factory;
|
||||
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.active.TrackerReadLock;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredReadLockFactory {
|
||||
public static TrackerReadLock createLock(MonitoredReentrantReadWriteLock lock) {
|
||||
return new TrackerReadLock(lock);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.factory;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.active.TrackerReentrantLock;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredReentrantLockFactory {
|
||||
public static TrackerReentrantLock createLock(MonitoredLockType id) {
|
||||
return new TrackerReentrantLock(id);
|
||||
}
|
||||
|
||||
public static TrackerReentrantLock createLock(MonitoredLockType id, boolean fair) {
|
||||
return new TrackerReentrantLock(id, fair);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit.locks.factory;
|
||||
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.active.TrackerWriteLock;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredWriteLockFactory {
|
||||
public static TrackerWriteLock createLock(MonitoredReentrantReadWriteLock lock) {
|
||||
return new TrackerWriteLock(lock);
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,6 @@ import net.netty.ChannelServer;
|
||||
import net.packet.Packet;
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.*;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import net.server.services.BaseService;
|
||||
import net.server.services.ServicesManager;
|
||||
import net.server.services.type.ChannelServices;
|
||||
@@ -58,6 +53,9 @@ import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.*;
|
||||
|
||||
@@ -106,13 +104,9 @@ public final class Channel {
|
||||
private Set<Integer> ongoingCathedralGuests = null;
|
||||
private long ongoingStartTime;
|
||||
|
||||
private final MonitoredReentrantReadWriteLock merchantLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.MERCHANT, true);
|
||||
private final MonitoredReadLock merchRlock = MonitoredReadLockFactory.createLock(merchantLock);
|
||||
private final MonitoredWriteLock merchWlock = MonitoredWriteLockFactory.createLock(merchantLock);
|
||||
|
||||
private final MonitoredReentrantLock[] faceLock = new MonitoredReentrantLock[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL, true);
|
||||
private final Lock lock = new ReentrantLock(true);;
|
||||
private final Lock merchRlock;
|
||||
private final Lock merchWlock;
|
||||
|
||||
public Channel(final int world, final int channel, long startTime) {
|
||||
this.world = world;
|
||||
@@ -123,6 +117,10 @@ public final class Channel {
|
||||
this.port = BASE_PORT + (this.channel - 1) + (world * 100);
|
||||
this.ip = YamlConfig.config.server.HOST + ":" + port;
|
||||
|
||||
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
|
||||
this.merchRlock = rwLock.readLock();
|
||||
this.merchWlock = rwLock.writeLock();
|
||||
|
||||
try {
|
||||
this.channelServer = initServer(port, world, channel);
|
||||
expedType.addAll(Arrays.asList(ExpeditionType.values()));
|
||||
@@ -216,19 +214,6 @@ public final class Channel {
|
||||
}
|
||||
|
||||
closeChannelServices();
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
for (int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
faceLock[i] = faceLock[i].dispose();
|
||||
}
|
||||
|
||||
lock = lock.dispose();
|
||||
}
|
||||
|
||||
private void closeAllMerchants() {
|
||||
|
||||
@@ -32,8 +32,7 @@ import tools.PacketCreator;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -82,11 +81,9 @@ public final class ReportHandler extends AbstractPacketHandler {
|
||||
}
|
||||
|
||||
public void addReport(int reporterid, int victimid, int reason, String description, String chatlog) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
Timestamp currentTimestamp = new java.sql.Timestamp(calendar.getTime().getTime());
|
||||
try (Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO reports (`reporttime`, `reporterid`, `victimid`, `reason`, `chatlog`, `description`) VALUES (?, ?, ?, ?, ?, ?)")) {
|
||||
ps.setString(1, currentTimestamp.toGMTString());
|
||||
ps.setString(1, OffsetDateTime.now().toString());
|
||||
ps.setInt(2, reporterid);
|
||||
ps.setInt(3, victimid);
|
||||
ps.setInt(4, reason);
|
||||
|
||||
@@ -23,12 +23,6 @@ import client.Character;
|
||||
import client.Job;
|
||||
import config.YamlConfig;
|
||||
import constants.id.MapId;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import net.server.coordinator.world.InviteCoordinator;
|
||||
import net.server.coordinator.world.InviteCoordinator.InviteType;
|
||||
import net.server.world.Party;
|
||||
@@ -41,6 +35,9 @@ import tools.Pair;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
@@ -51,9 +48,8 @@ public class PartySearchCoordinator {
|
||||
private final Map<Job, PartySearchEchelon> upcomers = new HashMap<>();
|
||||
|
||||
private final List<Character> leaderQueue = new LinkedList<>();
|
||||
private final MonitoredReentrantReadWriteLock leaderQueueLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.WORLD_PARTY_SEARCH_QUEUE, true);
|
||||
private final MonitoredReadLock leaderQueueRLock = MonitoredReadLockFactory.createLock(leaderQueueLock);
|
||||
private final MonitoredWriteLock leaderQueueWLock = MonitoredWriteLockFactory.createLock(leaderQueueLock);
|
||||
private final Lock leaderQueueRLock;
|
||||
private final Lock leaderQueueWLock;
|
||||
|
||||
private final Map<Integer, Character> searchLeaders = new HashMap<>();
|
||||
private final Map<Integer, LeaderSearchMetadata> searchSettings = new HashMap<>();
|
||||
@@ -65,6 +61,17 @@ public class PartySearchCoordinator {
|
||||
private static final Map<Integer, Set<Integer>> mapNeighbors = fetchNeighbouringMaps();
|
||||
private static final Map<Integer, Job> jobTable = instantiateJobTable();
|
||||
|
||||
public PartySearchCoordinator() {
|
||||
for (Job job : jobTable.values()) {
|
||||
storage.put(job, new PartySearchStorage());
|
||||
upcomers.put(job, new PartySearchEchelon());
|
||||
}
|
||||
|
||||
ReadWriteLock leaderQueueLock = new ReentrantReadWriteLock(true);
|
||||
this.leaderQueueRLock = leaderQueueLock.readLock();
|
||||
this.leaderQueueWLock = leaderQueueLock.writeLock();
|
||||
}
|
||||
|
||||
private static Map<Integer, Set<Integer>> fetchNeighbouringMaps() {
|
||||
Map<Integer, Set<Integer>> mapLinks = new HashMap<>();
|
||||
|
||||
@@ -176,13 +183,6 @@ public class PartySearchCoordinator {
|
||||
|
||||
}
|
||||
|
||||
public PartySearchCoordinator() {
|
||||
for (Job job : jobTable.values()) {
|
||||
storage.put(job, new PartySearchStorage());
|
||||
upcomers.put(job, new PartySearchEchelon());
|
||||
}
|
||||
}
|
||||
|
||||
public void attachPlayer(Character chr) {
|
||||
upcomers.get(getPartySearchJob(chr.getJob())).attachPlayer(chr);
|
||||
}
|
||||
|
||||
@@ -20,30 +20,31 @@
|
||||
package net.server.coordinator.partysearch;
|
||||
|
||||
import client.Character;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
public class PartySearchEchelon {
|
||||
|
||||
private final MonitoredReentrantReadWriteLock psLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.WORLD_PARTY_SEARCH_ECHELON, true);
|
||||
private final MonitoredReadLock psRLock = MonitoredReadLockFactory.createLock(psLock);
|
||||
private final MonitoredWriteLock psWLock = MonitoredWriteLockFactory.createLock(psLock);
|
||||
private final Lock psRLock;
|
||||
private final Lock psWLock;
|
||||
|
||||
private final Map<Integer, WeakReference<Character>> echelon = new HashMap<>(20);
|
||||
|
||||
public PartySearchEchelon() {
|
||||
ReadWriteLock partySearchLock = new ReentrantReadWriteLock(true);
|
||||
this.psRLock = partySearchLock.readLock();
|
||||
this.psWLock = partySearchLock.writeLock();
|
||||
}
|
||||
|
||||
public List<Character> exportEchelon() {
|
||||
psWLock.lock(); // reversing read/write actually could provide a lax yet sure performance/precision trade-off here
|
||||
try {
|
||||
|
||||
@@ -20,15 +20,12 @@
|
||||
package net.server.coordinator.partysearch;
|
||||
|
||||
import client.Character;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import tools.IntervalBuilder;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
@@ -38,9 +35,14 @@ public class PartySearchStorage {
|
||||
private final List<PartySearchCharacter> storage = new ArrayList<>(20);
|
||||
private final IntervalBuilder emptyIntervals = new IntervalBuilder();
|
||||
|
||||
private final MonitoredReentrantReadWriteLock psLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.WORLD_PARTY_SEARCH_STORAGE, true);
|
||||
private final MonitoredReadLock psRLock = MonitoredReadLockFactory.createLock(psLock);
|
||||
private final MonitoredWriteLock psWLock = MonitoredWriteLockFactory.createLock(psLock);
|
||||
private final Lock psRLock;
|
||||
private final Lock psWLock;
|
||||
|
||||
public PartySearchStorage() {
|
||||
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
|
||||
this.psRLock = readWriteLock.readLock();
|
||||
this.psWLock = readWriteLock.writeLock();
|
||||
}
|
||||
|
||||
public List<PartySearchCharacter> getStorageList() {
|
||||
psRLock.lock();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package net.server.coordinator.session;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -10,6 +8,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Manages session initialization using remote host (ip address).
|
||||
@@ -24,7 +23,7 @@ public class SessionInitialization {
|
||||
|
||||
SessionInitialization() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
locks.add(MonitoredReentrantLockFactory.createLock(MonitoredLockType.SERVER_LOGIN_COORD));
|
||||
locks.add(new ReentrantLock());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,6 @@ package net.server.coordinator.world;
|
||||
import client.Character;
|
||||
import config.YamlConfig;
|
||||
import net.server.Server;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.TimerManager;
|
||||
import server.life.Monster;
|
||||
import server.maps.MapleMap;
|
||||
@@ -34,14 +30,15 @@ import tools.Pair;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MonsterAggroCoordinator {
|
||||
|
||||
private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_AGGRO);
|
||||
private final MonitoredReentrantLock idleLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_AGGRO_IDLE, true);
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Lock idleLock = new ReentrantLock(true);
|
||||
private long lastStopTime = Server.getInstance().getCurrentTime();
|
||||
|
||||
private ScheduledFuture<?> aggroMonitor = null;
|
||||
@@ -375,15 +372,5 @@ public class MonsterAggroCoordinator {
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
lock = lock.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ import config.YamlConfig;
|
||||
import net.packet.Packet;
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.coordinator.matchchecker.MatchCheckerCoordinator;
|
||||
import net.server.coordinator.world.InviteCoordinator;
|
||||
@@ -45,6 +43,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class Guild {
|
||||
private static final Logger log = LoggerFactory.getLogger(Guild.class);
|
||||
@@ -54,7 +53,7 @@ public class Guild {
|
||||
}
|
||||
|
||||
private final List<GuildCharacter> members;
|
||||
private final Lock membersLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.GUILD, true);
|
||||
private final Lock membersLock = new ReentrantLock(true);
|
||||
|
||||
private final String[] rankTitles = new String[5]; // 1 = master, 2 = jr, 5 = lowest member
|
||||
private String name, notice;
|
||||
|
||||
@@ -21,16 +21,14 @@ package net.server.services;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.Server;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.TimerManager;
|
||||
import tools.Pair;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
@@ -38,21 +36,18 @@ import java.util.concurrent.ScheduledFuture;
|
||||
public abstract class BaseScheduler {
|
||||
private int idleProcs = 0;
|
||||
private final List<SchedulerListener> listeners = new LinkedList<>();
|
||||
private final List<MonitoredReentrantLock> externalLocks = new LinkedList<>();
|
||||
private final List<Lock> externalLocks = new LinkedList<>();
|
||||
private final Map<Object, Pair<Runnable, Long>> registeredEntries = new HashMap<>();
|
||||
|
||||
private ScheduledFuture<?> schedulerTask = null;
|
||||
private MonitoredReentrantLock schedulerLock;
|
||||
private final Lock schedulerLock = new ReentrantLock(true);
|
||||
private final Runnable monitorTask = () -> runBaseSchedule();
|
||||
|
||||
protected BaseScheduler(MonitoredLockType lockType) {
|
||||
schedulerLock = MonitoredReentrantLockFactory.createLock(lockType, true);
|
||||
protected BaseScheduler() {
|
||||
}
|
||||
|
||||
// NOTE: practice EXTREME caution when adding external locks to the scheduler system, if you don't know what you're doing DON'T USE THIS.
|
||||
protected BaseScheduler(MonitoredLockType lockType, List<MonitoredReentrantLock> extLocks) {
|
||||
schedulerLock = MonitoredReentrantLockFactory.createLock(lockType, true);
|
||||
|
||||
protected BaseScheduler(List<Lock> extLocks) {
|
||||
externalLocks.addAll(extLocks);
|
||||
}
|
||||
|
||||
@@ -61,22 +56,12 @@ public abstract class BaseScheduler {
|
||||
}
|
||||
|
||||
private void lockScheduler() {
|
||||
if (!externalLocks.isEmpty()) {
|
||||
for (MonitoredReentrantLock l : externalLocks) {
|
||||
l.lock();
|
||||
}
|
||||
}
|
||||
|
||||
externalLocks.forEach(Lock::lock);
|
||||
schedulerLock.lock();
|
||||
}
|
||||
|
||||
private void unlockScheduler() {
|
||||
if (!externalLocks.isEmpty()) {
|
||||
for (MonitoredReentrantLock l : externalLocks) {
|
||||
l.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
externalLocks.forEach(Lock::unlock);
|
||||
schedulerLock.unlock();
|
||||
}
|
||||
|
||||
@@ -184,15 +169,5 @@ public abstract class BaseScheduler {
|
||||
unlockScheduler();
|
||||
externalLocks.clear();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
schedulerLock = schedulerLock.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package net.server.services.task.channel;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.services.BaseScheduler;
|
||||
import net.server.services.BaseService;
|
||||
|
||||
@@ -53,10 +52,6 @@ public class EventService extends BaseService {
|
||||
|
||||
private class EventScheduler extends BaseScheduler {
|
||||
|
||||
public EventScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_EVENTS);
|
||||
}
|
||||
|
||||
public void registerDelayedAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.services.task.channel;
|
||||
|
||||
import client.Character;
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.services.BaseScheduler;
|
||||
import net.server.services.BaseService;
|
||||
import server.maps.MapleMap;
|
||||
import tools.PacketCreator;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
public class FaceExpressionService extends BaseService {
|
||||
|
||||
private final FaceExpressionScheduler[] faceExpressionSchedulers = new FaceExpressionScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private final MonitoredReentrantLock[] faceLock = new MonitoredReentrantLock[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
public FaceExpressionService() {
|
||||
for (int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
faceLock[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_FACEEXPRS, true);
|
||||
faceExpressionSchedulers[i] = new FaceExpressionScheduler(faceLock[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
for (int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
faceLock[i] = faceLock[i].dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
for (int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if (faceExpressionSchedulers[i] != null) {
|
||||
faceExpressionSchedulers[i].dispose();
|
||||
faceExpressionSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
public void registerFaceExpression(final MapleMap map, final Character chr, int emote) {
|
||||
int lockid = getChannelSchedulerIndex(map.getId());
|
||||
|
||||
Runnable cancelAction = () -> {
|
||||
if (chr.isLoggedinWorld()) {
|
||||
map.broadcastMessage(chr, PacketCreator.facialExpression(chr, 0), false);
|
||||
}
|
||||
};
|
||||
|
||||
faceLock[lockid].lock();
|
||||
try {
|
||||
if (!chr.isLoggedinWorld()) {
|
||||
return;
|
||||
}
|
||||
|
||||
faceExpressionSchedulers[lockid].registerFaceExpression(chr.getId(), cancelAction);
|
||||
} finally {
|
||||
faceLock[lockid].unlock();
|
||||
}
|
||||
|
||||
map.broadcastMessage(chr, PacketCreator.facialExpression(chr, emote), false);
|
||||
}
|
||||
|
||||
public void unregisterFaceExpression(int mapid, Character chr) {
|
||||
int lockid = getChannelSchedulerIndex(mapid);
|
||||
|
||||
faceLock[lockid].lock();
|
||||
try {
|
||||
faceExpressionSchedulers[lockid].unregisterFaceExpression(chr.getId());
|
||||
} finally {
|
||||
faceLock[lockid].unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private class FaceExpressionScheduler extends BaseScheduler {
|
||||
|
||||
public FaceExpressionScheduler(final MonitoredReentrantLock channelFaceLock) {
|
||||
super(MonitoredLockType.CHANNEL_FACESCHDL, Collections.singletonList(channelFaceLock));
|
||||
}
|
||||
|
||||
public void registerFaceExpression(Integer characterId, Runnable runAction) {
|
||||
registerEntry(characterId, runAction, 5000);
|
||||
}
|
||||
|
||||
public void unregisterFaceExpression(Integer characterId) {
|
||||
interruptEntry(characterId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,15 +20,13 @@
|
||||
package net.server.services.task.channel;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.services.BaseScheduler;
|
||||
import net.server.services.BaseService;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
@@ -63,11 +61,9 @@ public class MobAnimationService extends BaseService {
|
||||
|
||||
private class MobAnimationScheduler extends BaseScheduler {
|
||||
Set<Integer> onAnimationMobs = new HashSet<>(1000);
|
||||
private MonitoredReentrantLock animationLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_MOBANIMAT, true);
|
||||
private final Lock animationLock = new ReentrantLock(true);
|
||||
|
||||
public MobAnimationScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBACTION);
|
||||
|
||||
super.addListener((toRemove, update) -> {
|
||||
animationLock.lock();
|
||||
try {
|
||||
@@ -98,18 +94,9 @@ public class MobAnimationService extends BaseService {
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeLocks();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
animationLock = animationLock.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package net.server.services.task.channel;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.services.BaseScheduler;
|
||||
import net.server.services.BaseService;
|
||||
|
||||
@@ -53,10 +52,6 @@ public class MobClearSkillService extends BaseService {
|
||||
|
||||
private class MobClearSkillScheduler extends BaseScheduler {
|
||||
|
||||
public MobClearSkillScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBSKILL);
|
||||
}
|
||||
|
||||
public void registerClearSkillAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package net.server.services.task.channel;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.services.BaseScheduler;
|
||||
import net.server.services.BaseService;
|
||||
|
||||
@@ -53,10 +52,6 @@ public class MobMistService extends BaseService {
|
||||
|
||||
private class MobMistScheduler extends BaseScheduler {
|
||||
|
||||
public MobMistScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBMIST);
|
||||
}
|
||||
|
||||
public void registerMistCancelAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
|
||||
@@ -21,10 +21,6 @@ package net.server.services.task.channel;
|
||||
|
||||
import client.status.MonsterStatusEffect;
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.services.BaseScheduler;
|
||||
import net.server.services.BaseService;
|
||||
|
||||
@@ -32,6 +28,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
@@ -71,7 +69,7 @@ public class MobStatusService extends BaseService {
|
||||
private class MobStatusScheduler extends BaseScheduler {
|
||||
|
||||
private final Map<MonsterStatusEffect, MobStatusOvertimeEntry> registeredMobStatusOvertime = new HashMap<>();
|
||||
private MonitoredReentrantLock overtimeStatusLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_OVTSTATUS, true);
|
||||
private final Lock overtimeStatusLock = new ReentrantLock(true);
|
||||
|
||||
private class MobStatusOvertimeEntry {
|
||||
private int procCount;
|
||||
@@ -94,8 +92,6 @@ public class MobStatusService extends BaseService {
|
||||
}
|
||||
|
||||
public MobStatusScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBSTATUS);
|
||||
|
||||
super.addListener((toRemove, update) -> {
|
||||
List<Runnable> toRun = new ArrayList<>();
|
||||
|
||||
@@ -144,18 +140,9 @@ public class MobStatusService extends BaseService {
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeLocks();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
overtimeStatusLock = overtimeStatusLock.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package net.server.services.task.channel;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.services.BaseScheduler;
|
||||
import net.server.services.BaseService;
|
||||
|
||||
@@ -58,10 +57,6 @@ public class OverallService extends BaseService { // thanks Alex for suggestin
|
||||
|
||||
public class OverallScheduler extends BaseScheduler {
|
||||
|
||||
public OverallScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_OVERALL);
|
||||
}
|
||||
|
||||
public void registerDelayedAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
package net.server.services.task.world;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.services.BaseScheduler;
|
||||
import net.server.services.BaseService;
|
||||
|
||||
@@ -44,10 +43,6 @@ public class CharacterSaveService extends BaseService {
|
||||
|
||||
private class CharacterSaveScheduler extends BaseScheduler {
|
||||
|
||||
public CharacterSaveScheduler() {
|
||||
super(MonitoredLockType.WORLD_SAVECHARS);
|
||||
}
|
||||
|
||||
public void registerSaveCharacter(Integer characterId, Runnable runAction) {
|
||||
registerEntry(characterId, runAction, 0);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ public enum ChannelServices implements ServiceType {
|
||||
MOB_ANIMATION(MobAnimationService.class),
|
||||
MOB_CLEAR_SKILL(MobClearSkillService.class),
|
||||
MOB_MIST(MobMistService.class),
|
||||
FACE_EXPRESSION(FaceExpressionService.class),
|
||||
EVENT(EventService.class),
|
||||
OVERALL(OverallService.class);
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.task;
|
||||
|
||||
import net.server.audit.LockCollector;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
* @info Thread responsible for expiring locks signalized for dispose.
|
||||
*/
|
||||
public class ReleaseLockTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
LockCollector.getInstance().runLockCollector();
|
||||
}
|
||||
}
|
||||
@@ -24,10 +24,6 @@ package net.server.world;
|
||||
import client.Character;
|
||||
import client.Client;
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.coordinator.matchchecker.MatchCheckerCoordinator;
|
||||
import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType;
|
||||
import scripting.event.EventInstanceManager;
|
||||
@@ -38,6 +34,8 @@ import tools.PacketCreator;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class Party {
|
||||
|
||||
@@ -52,7 +50,7 @@ public class Party {
|
||||
|
||||
private final Map<Integer, Door> doors = new HashMap<>();
|
||||
|
||||
private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.PARTY, true);
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
|
||||
public Party(int id, PartyCharacter chrfor) {
|
||||
this.leaderId = chrfor.getId();
|
||||
@@ -281,14 +279,6 @@ public class Party {
|
||||
}
|
||||
}
|
||||
|
||||
public void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
lock = lock.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
||||
@@ -32,11 +32,6 @@ import constants.game.GameConstants;
|
||||
import net.packet.Packet;
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.*;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.channel.CharacterIdChannelPair;
|
||||
import net.server.coordinator.matchchecker.MatchCheckerCoordinator;
|
||||
@@ -69,6 +64,10 @@ import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.*;
|
||||
|
||||
@@ -103,13 +102,12 @@ public class World {
|
||||
private final MatchCheckerCoordinator matchChecker = new MatchCheckerCoordinator();
|
||||
private final PartySearchCoordinator partySearch = new PartySearchCoordinator();
|
||||
|
||||
private final MonitoredReentrantReadWriteLock chnLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.WORLD_CHANNELS, true);
|
||||
private final MonitoredReadLock chnRLock = MonitoredReadLockFactory.createLock(chnLock);
|
||||
private final MonitoredWriteLock chnWLock = MonitoredWriteLockFactory.createLock(chnLock);
|
||||
private final Lock chnRLock;
|
||||
private final Lock chnWLock;
|
||||
|
||||
private final Map<Integer, SortedMap<Integer, Character>> accountChars = new HashMap<>();
|
||||
private final Map<Integer, Storage> accountStorages = new HashMap<>();
|
||||
private MonitoredReentrantLock accountCharsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_CHARS, true);
|
||||
private final Lock accountCharsLock = new ReentrantLock(true);
|
||||
|
||||
private final Set<Integer> queuedGuilds = new HashSet<>();
|
||||
private final Map<Integer, Pair<Pair<Boolean, Boolean>, Pair<Integer, Integer>>> queuedMarriages = new HashMap<>();
|
||||
@@ -118,39 +116,39 @@ public class World {
|
||||
private final Map<Integer, Integer> partyChars = new HashMap<>();
|
||||
private final Map<Integer, Party> parties = new HashMap<>();
|
||||
private final AtomicInteger runningPartyId = new AtomicInteger();
|
||||
private MonitoredReentrantLock partyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PARTY, true);
|
||||
private final Lock partyLock = new ReentrantLock(true);
|
||||
|
||||
private final Map<Integer, Integer> owlSearched = new LinkedHashMap<>();
|
||||
private final List<Map<Integer, Integer>> cashItemBought = new ArrayList<>(9);
|
||||
private final MonitoredReentrantReadWriteLock suggestLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.WORLD_SUGGEST, true);
|
||||
private final MonitoredReadLock suggestRLock = MonitoredReadLockFactory.createLock(suggestLock);
|
||||
private final MonitoredWriteLock suggestWLock = MonitoredWriteLockFactory.createLock(suggestLock);
|
||||
|
||||
private final Lock suggestRLock;
|
||||
private final Lock suggestWLock;
|
||||
|
||||
private final Map<Integer, Integer> disabledServerMessages = new HashMap<>(); // reuse owl lock
|
||||
private MonitoredReentrantLock srvMessagesLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_SRVMESSAGES);
|
||||
private final Lock srvMessagesLock = new ReentrantLock();
|
||||
private ScheduledFuture<?> srvMessagesSchedule;
|
||||
|
||||
private MonitoredReentrantLock activePetsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PETS, true);
|
||||
private Lock activePetsLock = new ReentrantLock(true);
|
||||
private final Map<Integer, Integer> activePets = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> petsSchedule;
|
||||
private long petUpdate;
|
||||
|
||||
private MonitoredReentrantLock activeMountsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MOUNTS, true);
|
||||
private Lock activeMountsLock = new ReentrantLock(true);
|
||||
private final Map<Integer, Integer> activeMounts = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> mountsSchedule;
|
||||
private long mountUpdate;
|
||||
|
||||
private MonitoredReentrantLock activePlayerShopsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PSHOPS, true);
|
||||
private Lock activePlayerShopsLock = new ReentrantLock(true);
|
||||
private final Map<Integer, PlayerShop> activePlayerShops = new LinkedHashMap<>();
|
||||
|
||||
private MonitoredReentrantLock activeMerchantsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MERCHS, true);
|
||||
private Lock activeMerchantsLock = new ReentrantLock(true);
|
||||
private final Map<Integer, Pair<HiredMerchant, Integer>> activeMerchants = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> merchantSchedule;
|
||||
private long merchantUpdate;
|
||||
|
||||
private final Map<Runnable, Long> registeredTimedMapObjects = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> timedMapObjectsSchedule;
|
||||
private MonitoredReentrantLock timedMapObjectLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MAPOBJS, true);
|
||||
private Lock timedMapObjectLock = new ReentrantLock(true);
|
||||
|
||||
private final Map<Character, Integer> fishingAttempters = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
private Map<Character, Integer> playerHpDec = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
@@ -177,6 +175,14 @@ public class World {
|
||||
runningPartyId.set(1000000001); // partyid must not clash with charid to solve update item looting issues, found thanks to Vcoc
|
||||
runningMessengerId.set(1);
|
||||
|
||||
ReadWriteLock channelLock = new ReentrantReadWriteLock(true);
|
||||
this.chnRLock = channelLock.readLock();
|
||||
this.chnWLock = channelLock.writeLock();
|
||||
|
||||
ReadWriteLock suggestLock = new ReentrantReadWriteLock(true);
|
||||
this.suggestRLock = suggestLock.readLock();
|
||||
this.suggestWLock = suggestLock.writeLock();
|
||||
|
||||
petUpdate = Server.getInstance().getCurrentTime();
|
||||
mountUpdate = petUpdate;
|
||||
|
||||
@@ -2097,27 +2103,7 @@ public class World {
|
||||
partyLock.unlock();
|
||||
}
|
||||
|
||||
for (Party p : pList) {
|
||||
p.disposeLocks();
|
||||
}
|
||||
|
||||
closeWorldServices();
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
accountCharsLock = accountCharsLock.dispose();
|
||||
partyLock = partyLock.dispose();
|
||||
srvMessagesLock = srvMessagesLock.dispose();
|
||||
activePetsLock = activePetsLock.dispose();
|
||||
activeMountsLock = activeMountsLock.dispose();
|
||||
activePlayerShopsLock = activePlayerShopsLock.dispose();
|
||||
activeMerchantsLock = activeMerchantsLock.dispose();
|
||||
timedMapObjectLock = timedMapObjectLock.dispose();
|
||||
}
|
||||
|
||||
public final void shutdown() {
|
||||
|
||||
@@ -26,11 +26,6 @@ import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import config.YamlConfig;
|
||||
import constants.inventory.ItemConstants;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.*;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import net.server.coordinator.world.EventRecallCoordinator;
|
||||
import net.server.world.Party;
|
||||
import net.server.world.PartyCharacter;
|
||||
@@ -58,6 +53,10 @@ import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
|
||||
@@ -82,12 +81,11 @@ public class EventInstanceManager {
|
||||
private Expedition expedition = null;
|
||||
private final List<Integer> mapIds = new LinkedList<>();
|
||||
|
||||
private final MonitoredReentrantReadWriteLock lock = new MonitoredReentrantReadWriteLock(MonitoredLockType.EIM, true);
|
||||
private final MonitoredReadLock rL = MonitoredReadLockFactory.createLock(lock);
|
||||
private final MonitoredWriteLock wL = MonitoredWriteLockFactory.createLock(lock);
|
||||
private final Lock readLock;
|
||||
private final Lock writeLock;
|
||||
|
||||
private MonitoredReentrantLock pL = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EIM_PARTY, true);
|
||||
private MonitoredReentrantLock sL = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EIM_SCRIPT, true);
|
||||
private final Lock propertyLock = new ReentrantLock(true);
|
||||
private final Lock scriptLock = new ReentrantLock(true);
|
||||
|
||||
private ScheduledFuture<?> event_schedule = null;
|
||||
private boolean disposed = false;
|
||||
@@ -117,6 +115,10 @@ public class EventInstanceManager {
|
||||
this.name = name;
|
||||
this.ess = new EventScriptScheduler();
|
||||
this.mapManager = new MapManager(this, em.getWorldServer().getId(), em.getChannelServer().getId());
|
||||
|
||||
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
|
||||
this.readLock = readWriteLock.readLock();
|
||||
this.writeLock = readWriteLock.writeLock();
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -124,11 +126,11 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public EventManager getEm() {
|
||||
sL.lock();
|
||||
scriptLock.lock();
|
||||
try {
|
||||
return em;
|
||||
} finally {
|
||||
sL.unlock();
|
||||
scriptLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +241,7 @@ public class EventInstanceManager {
|
||||
return;
|
||||
}
|
||||
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
if (chars.containsKey(chr.getId())) {
|
||||
return;
|
||||
@@ -248,7 +250,7 @@ public class EventInstanceManager {
|
||||
chars.put(chr.getId(), chr);
|
||||
chr.setEventInstance(this);
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
if (runEntryScript) {
|
||||
@@ -391,12 +393,12 @@ public class EventInstanceManager {
|
||||
log.error("Event script {} does not implement the playerUnregistered function", em.getName(), ex);
|
||||
}
|
||||
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
chars.remove(chr.getId());
|
||||
chr.setEventInstance(null);
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
gridRemove(chr);
|
||||
@@ -404,38 +406,38 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public int getPlayerCount() {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return chars.size();
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Character getPlayerById(int id) {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return chars.get(id);
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Character> getPlayers() {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return new ArrayList<>(chars.values());
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Character> getPlayerList() {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return new LinkedList<>(chars.values());
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,7 +482,7 @@ public class EventInstanceManager {
|
||||
public void monsterKilled(final Monster mob, final boolean hasKiller) {
|
||||
int scriptResult = 0;
|
||||
|
||||
sL.lock();
|
||||
scriptLock.lock();
|
||||
try {
|
||||
mobs.remove(mob);
|
||||
|
||||
@@ -492,7 +494,7 @@ public class EventInstanceManager {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sL.unlock();
|
||||
scriptLock.unlock();
|
||||
}
|
||||
|
||||
if (scriptResult > 0) {
|
||||
@@ -598,13 +600,13 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
for (Character chr : chars.values()) {
|
||||
chr.setEventInstance(null);
|
||||
}
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
dispose(false);
|
||||
@@ -624,7 +626,7 @@ public class EventInstanceManager {
|
||||
|
||||
ess.dispose();
|
||||
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
for (Character chr : chars.values()) {
|
||||
chr.setEventInstance(null);
|
||||
@@ -633,7 +635,7 @@ public class EventInstanceManager {
|
||||
mobs.clear();
|
||||
ess = null;
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
if (event_schedule != null) {
|
||||
@@ -648,44 +650,33 @@ public class EventInstanceManager {
|
||||
|
||||
disposeExpedition();
|
||||
|
||||
sL.lock();
|
||||
scriptLock.lock();
|
||||
try {
|
||||
if (!eventCleared) {
|
||||
em.disposeInstance(name);
|
||||
}
|
||||
} finally {
|
||||
sL.unlock();
|
||||
scriptLock.unlock();
|
||||
}
|
||||
|
||||
TimerManager.getInstance().schedule(() -> {
|
||||
mapManager.dispose(); // issues from instantly disposing some event objects found thanks to MedicOP
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
mapManager = null;
|
||||
em = null;
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}, MINUTES.toMillis(1));
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
pL = pL.dispose();
|
||||
sL = sL.dispose();
|
||||
}
|
||||
|
||||
public MapManager getMapFactory() {
|
||||
return mapManager;
|
||||
}
|
||||
|
||||
public void schedule(final String methodName, long delay) {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
if (ess != null) {
|
||||
Runnable r = () -> {
|
||||
@@ -699,7 +690,7 @@ public class EventInstanceManager {
|
||||
ess.registerEntry(r, delay);
|
||||
}
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,13 +703,13 @@ public class EventInstanceManager {
|
||||
map.setEventInstance(this);
|
||||
|
||||
if (!mapManager.isMapLoaded(mapId)) {
|
||||
sL.lock();
|
||||
scriptLock.lock();
|
||||
try {
|
||||
if (em.getProperty("shuffleReactors") != null && em.getProperty("shuffleReactors").equals("true")) {
|
||||
map.shuffleReactors();
|
||||
}
|
||||
} finally {
|
||||
sL.unlock();
|
||||
scriptLock.unlock();
|
||||
}
|
||||
}
|
||||
return map;
|
||||
@@ -733,56 +724,56 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public void setProperty(String key, String value) {
|
||||
pL.lock();
|
||||
propertyLock.lock();
|
||||
try {
|
||||
props.setProperty(key, value);
|
||||
} finally {
|
||||
pL.unlock();
|
||||
propertyLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Object setProperty(String key, String value, boolean prev) {
|
||||
pL.lock();
|
||||
propertyLock.lock();
|
||||
try {
|
||||
return props.setProperty(key, value);
|
||||
} finally {
|
||||
pL.unlock();
|
||||
propertyLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void setObjectProperty(String key, Object obj) {
|
||||
pL.lock();
|
||||
propertyLock.lock();
|
||||
try {
|
||||
objectProps.put(key, obj);
|
||||
} finally {
|
||||
pL.unlock();
|
||||
propertyLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public String getProperty(String key) {
|
||||
pL.lock();
|
||||
propertyLock.lock();
|
||||
try {
|
||||
return props.getProperty(key);
|
||||
} finally {
|
||||
pL.unlock();
|
||||
propertyLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getIntProperty(String key) {
|
||||
pL.lock();
|
||||
propertyLock.lock();
|
||||
try {
|
||||
return Integer.parseInt(props.getProperty(key));
|
||||
} finally {
|
||||
pL.unlock();
|
||||
propertyLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Object getObjectProperty(String key) {
|
||||
pL.lock();
|
||||
propertyLock.lock();
|
||||
try {
|
||||
return objectProps.get(key);
|
||||
} finally {
|
||||
pL.unlock();
|
||||
propertyLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -957,11 +948,11 @@ public class EventInstanceManager {
|
||||
public final void setExclusiveItems(List<Object> items) {
|
||||
List<Integer> exclusive = convertToIntegerList(items);
|
||||
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
exclusiveItems.addAll(exclusive);
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,13 +980,13 @@ public class EventInstanceManager {
|
||||
List<Integer> rewardQtys = convertToIntegerList(qtys);
|
||||
|
||||
//rewardsSet and rewardsQty hold temporary values
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
collectionSet.put(eventLevel, rewardIds);
|
||||
collectionQty.put(eventLevel, rewardQtys);
|
||||
collectionExp.put(eventLevel, expGiven);
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1036,7 +1027,7 @@ public class EventInstanceManager {
|
||||
List<Integer> rewardsSet, rewardsQty;
|
||||
Integer rewardExp;
|
||||
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
eventLevel--; //event level starts counting from 1
|
||||
if (eventLevel >= collectionSet.size()) {
|
||||
@@ -1048,7 +1039,7 @@ public class EventInstanceManager {
|
||||
|
||||
rewardExp = collectionExp.get(eventLevel);
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
if (rewardExp == null) {
|
||||
@@ -1080,11 +1071,11 @@ public class EventInstanceManager {
|
||||
if (expedition != null) {
|
||||
expedition.dispose(eventCleared);
|
||||
|
||||
sL.lock();
|
||||
scriptLock.lock();
|
||||
try {
|
||||
expedition.removeChannelExpedition(em.getChannelServer());
|
||||
} finally {
|
||||
sL.unlock();
|
||||
scriptLock.unlock();
|
||||
}
|
||||
|
||||
expedition = null;
|
||||
@@ -1108,11 +1099,11 @@ public class EventInstanceManager {
|
||||
chr.awardQuestPoint(YamlConfig.config.server.QUEST_POINT_PER_EVENT_CLEAR);
|
||||
}
|
||||
|
||||
sL.lock();
|
||||
scriptLock.lock();
|
||||
try {
|
||||
em.disposeInstance(name);
|
||||
} finally {
|
||||
sL.unlock();
|
||||
scriptLock.unlock();
|
||||
}
|
||||
|
||||
disposeExpedition();
|
||||
@@ -1168,7 +1159,7 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public final boolean isEventTeamTogether() {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
if (chars.size() <= 1) {
|
||||
return true;
|
||||
@@ -1187,7 +1178,7 @@ public class EventInstanceManager {
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1228,29 +1219,29 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public final int getLeaderId() {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return leaderId;
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Character getLeader() {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return chars.get(leaderId);
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public final void setLeader(Character chr) {
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
leaderId = chr.getId();
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1293,11 +1284,11 @@ public class EventInstanceManager {
|
||||
map.broadcastMessage(PacketCreator.playSound("Party1/Clear"));
|
||||
if (hasGate) {
|
||||
map.broadcastMessage(PacketCreator.environmentChange(mapObj, newState));
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
openedGates.put(map.getId(), new Pair<>(mapObj, newState));
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1305,13 +1296,13 @@ public class EventInstanceManager {
|
||||
public final void recoverOpenedGate(Character chr, int thisMapId) {
|
||||
Pair<String, Integer> gateData = null;
|
||||
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
if (openedGates.containsKey(thisMapId)) {
|
||||
gateData = openedGates.get(thisMapId);
|
||||
}
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
if (gateData != null) {
|
||||
@@ -1349,50 +1340,50 @@ public class EventInstanceManager {
|
||||
|
||||
// registers a player status in an event
|
||||
public final void gridInsert(Character chr, int newStatus) {
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
playerGrid.put(chr.getId(), newStatus);
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// unregisters a player status in an event
|
||||
public final void gridRemove(Character chr) {
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
playerGrid.remove(chr.getId());
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// checks a player status
|
||||
public final int gridCheck(Character chr) {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
Integer i = playerGrid.get(chr.getId());
|
||||
return (i != null) ? i : -1;
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public final int gridSize() {
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return playerGrid.size();
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public final void gridClear() {
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
playerGrid.clear();
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,6 @@ import client.Character;
|
||||
import config.YamlConfig;
|
||||
import constants.game.GameConstants;
|
||||
import net.server.Server;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.guild.Guild;
|
||||
import net.server.world.Party;
|
||||
@@ -50,6 +46,8 @@ import javax.script.Invocable;
|
||||
import javax.script.ScriptException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
@@ -75,9 +73,9 @@ public class EventManager {
|
||||
private Integer readyId = 0, onLoadInstances = 0;
|
||||
private final Properties props = new Properties();
|
||||
private final String name;
|
||||
private MonitoredReentrantLock lobbyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_LOBBY);
|
||||
private MonitoredReentrantLock queueLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_QUEUE);
|
||||
private MonitoredReentrantLock startLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_START);
|
||||
private final Lock lobbyLock = new ReentrantLock();
|
||||
private final Lock queueLock = new ReentrantLock();
|
||||
private final Lock startLock = new ReentrantLock();
|
||||
|
||||
private final Set<Integer> playerPermit = new HashSet<>();
|
||||
private final Semaphore startSemaphore = new Semaphore(7);
|
||||
@@ -139,18 +137,6 @@ public class EventManager {
|
||||
wserv = null;
|
||||
server = null;
|
||||
iv = null;
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
lobbyLock = lobbyLock.dispose();
|
||||
queueLock = queueLock.dispose();
|
||||
startLock = startLock.dispose();
|
||||
}
|
||||
|
||||
private List<Integer> convertToIntegerList(List<Object> objects) {
|
||||
|
||||
@@ -21,10 +21,6 @@ package scripting.event.scheduler;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.Server;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.ThreadManager;
|
||||
import server.TimerManager;
|
||||
|
||||
@@ -34,6 +30,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
@@ -45,13 +43,9 @@ public class EventScriptScheduler {
|
||||
private final Map<Runnable, Long> registeredEntries = new HashMap<>();
|
||||
|
||||
private ScheduledFuture<?> schedulerTask = null;
|
||||
private MonitoredReentrantLock schedulerLock;
|
||||
private final Lock schedulerLock = new ReentrantLock(true);
|
||||
private final Runnable monitorTask = () -> runBaseSchedule();
|
||||
|
||||
public EventScriptScheduler() {
|
||||
schedulerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_SCHDL, true);
|
||||
}
|
||||
|
||||
private void runBaseSchedule() {
|
||||
List<Runnable> toRemove;
|
||||
Map<Runnable, Long> registeredEntriesCopy;
|
||||
@@ -148,16 +142,6 @@ public class EventScriptScheduler {
|
||||
} finally {
|
||||
schedulerLock.unlock();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
});
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
schedulerLock = schedulerLock.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ import config.YamlConfig;
|
||||
import constants.id.ItemId;
|
||||
import constants.inventory.ItemConstants;
|
||||
import net.server.Server;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import provider.Data;
|
||||
import provider.DataProvider;
|
||||
import provider.DataProviderFactory;
|
||||
@@ -42,6 +40,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
import static java.util.concurrent.TimeUnit.HOURS;
|
||||
@@ -261,7 +260,7 @@ public class CashShop {
|
||||
private final List<Item> inventory = new ArrayList<>();
|
||||
private final List<Integer> wishList = new ArrayList<>();
|
||||
private int notes = 0;
|
||||
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CASHSHOP);
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
public CashShop(int accountId, int characterId, int jobType) throws SQLException {
|
||||
this.accountId = accountId;
|
||||
|
||||
@@ -23,8 +23,6 @@ import client.inventory.InventoryType;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.ItemFactory;
|
||||
import constants.game.GameConstants;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import provider.Data;
|
||||
@@ -42,6 +40,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Matze
|
||||
@@ -57,7 +56,7 @@ public class Storage {
|
||||
private byte slots;
|
||||
private final Map<InventoryType, List<Item>> typeItems = new HashMap<>();
|
||||
private List<Item> items = new LinkedList<>();
|
||||
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.STORAGE, true);
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
|
||||
private Storage(int id, byte slots, int meso) {
|
||||
this.id = id;
|
||||
|
||||
@@ -28,9 +28,6 @@ import constants.id.MobId;
|
||||
import net.packet.Packet;
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.Channel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -45,6 +42,8 @@ import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
@@ -100,7 +99,7 @@ public class Expedition {
|
||||
private final boolean silent;
|
||||
private final int minSize;
|
||||
private final int maxSize;
|
||||
private final MonitoredReentrantLock pL = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EIM_PARTY, true);
|
||||
private final Lock pL = new ReentrantLock(true);
|
||||
|
||||
public Expedition(Character player, ExpeditionType met, boolean sil, int minPlayers, int maxPlayers) {
|
||||
leader = player;
|
||||
|
||||
@@ -21,12 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package server.life;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import provider.Data;
|
||||
import provider.DataProvider;
|
||||
import provider.DataProviderFactory;
|
||||
@@ -38,6 +32,9 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
@@ -49,22 +46,22 @@ public class MobSkillFactory {
|
||||
private static final Map<String, MobSkill> mobSkills = new HashMap<>();
|
||||
private final static DataProvider dataSource = DataProviderFactory.getDataProvider(WZFiles.SKILL);
|
||||
private static final Data skillRoot = dataSource.getData("MobSkill.img");
|
||||
private final static MonitoredReentrantReadWriteLock dataLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.MOBSKILL_FACTORY);
|
||||
private final static MonitoredReadLock rL = MonitoredReadLockFactory.createLock(dataLock);
|
||||
private final static MonitoredWriteLock wL = MonitoredWriteLockFactory.createLock(dataLock);
|
||||
private final static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
||||
private final static Lock readLock = readWriteLock.readLock();
|
||||
private final static Lock writeLock = readWriteLock.writeLock();
|
||||
|
||||
public static MobSkill getMobSkill(final int skillId, final int level) {
|
||||
final String key = skillId + "" + level;
|
||||
rL.lock();
|
||||
readLock.lock();
|
||||
try {
|
||||
MobSkill ret = mobSkills.get(key);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
} finally {
|
||||
rL.unlock();
|
||||
readLock.unlock();
|
||||
}
|
||||
wL.lock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
MobSkill ret;
|
||||
ret = mobSkills.get(key);
|
||||
@@ -114,7 +111,7 @@ public class MobSkillFactory {
|
||||
}
|
||||
return ret;
|
||||
} finally {
|
||||
wL.unlock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,6 @@ import config.YamlConfig;
|
||||
import constants.id.MobId;
|
||||
import constants.skills.*;
|
||||
import net.packet.Packet;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.coordinator.world.MonsterAggroCoordinator;
|
||||
import net.server.services.task.channel.MobAnimationService;
|
||||
@@ -66,6 +62,8 @@ import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class Monster extends AbstractLoadedLife {
|
||||
private static final Logger log = LoggerFactory.getLogger(Monster.class);
|
||||
@@ -98,11 +96,11 @@ public class Monster extends AbstractLoadedLife {
|
||||
private Runnable removeAfterAction = null;
|
||||
private boolean availablePuppetUpdate = true;
|
||||
|
||||
private MonitoredReentrantLock externalLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MOB_EXT);
|
||||
private MonitoredReentrantLock monsterLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MOB, true);
|
||||
private MonitoredReentrantLock statiLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MOB_STATI);
|
||||
private MonitoredReentrantLock animationLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MOB_ANI);
|
||||
private final MonitoredReentrantLock aggroUpdateLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MOB_AGGRO);
|
||||
private final Lock externalLock = new ReentrantLock();
|
||||
private final Lock monsterLock = new ReentrantLock(true);
|
||||
private final Lock statiLock = new ReentrantLock();
|
||||
private final Lock animationLock = new ReentrantLock();
|
||||
private final Lock aggroUpdateLock = new ReentrantLock();
|
||||
|
||||
public Monster(int id, MonsterStats stats) {
|
||||
super(id);
|
||||
@@ -2195,17 +2193,5 @@ public class Monster extends AbstractLoadedLife {
|
||||
}
|
||||
|
||||
this.getMap().dismissRemoveAfter(this);
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
externalLock = externalLock.dispose();
|
||||
monsterLock = monsterLock.dispose();
|
||||
statiLock = statiLock.dispose();
|
||||
animationLock = animationLock.dispose();
|
||||
}
|
||||
}
|
||||
@@ -22,16 +22,13 @@ package server.maps;
|
||||
import client.Character;
|
||||
import client.Client;
|
||||
import constants.id.MapId;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import net.server.world.Party;
|
||||
import tools.PacketCreator;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
@@ -45,9 +42,8 @@ public class DoorObject extends AbstractMapObject {
|
||||
private int linkedPortalId;
|
||||
private Point linkedPos;
|
||||
|
||||
private final MonitoredReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.PLAYER_DOOR, true);
|
||||
private final MonitoredReadLock rlock = MonitoredReadLockFactory.createLock(locks);
|
||||
private final MonitoredWriteLock wlock = MonitoredWriteLockFactory.createLock(locks);
|
||||
private final Lock rlock;
|
||||
private final Lock wlock;
|
||||
|
||||
public DoorObject(int owner, MapleMap destination, MapleMap origin, int townPortalId, Point targetPosition, Point toPosition) {
|
||||
super();
|
||||
@@ -58,6 +54,10 @@ public class DoorObject extends AbstractMapObject {
|
||||
from = origin;
|
||||
to = destination;
|
||||
linkedPos = toPosition;
|
||||
|
||||
ReadWriteLock lock = new ReentrantReadWriteLock(true);
|
||||
this.rlock = lock.readLock();
|
||||
this.wlock = lock.writeLock();
|
||||
}
|
||||
|
||||
public void update(int townPortalId, Point toPosition) {
|
||||
|
||||
@@ -25,13 +25,12 @@ import client.Character;
|
||||
import client.Client;
|
||||
import constants.game.GameConstants;
|
||||
import constants.id.MapId;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import scripting.portal.PortalScriptManager;
|
||||
import tools.PacketCreator;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class GenericPortal implements Portal {
|
||||
private String name;
|
||||
@@ -43,7 +42,7 @@ public class GenericPortal implements Portal {
|
||||
private int id;
|
||||
private String scriptName;
|
||||
private boolean portalState;
|
||||
private MonitoredReentrantLock scriptLock = null;
|
||||
private Lock scriptLock = null;
|
||||
|
||||
public GenericPortal(int type) {
|
||||
this.type = type;
|
||||
@@ -120,7 +119,7 @@ public class GenericPortal implements Portal {
|
||||
|
||||
if (scriptName != null) {
|
||||
if (scriptLock == null) {
|
||||
scriptLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.PORTAL, true);
|
||||
scriptLock = new ReentrantLock(true);
|
||||
}
|
||||
} else {
|
||||
scriptLock = null;
|
||||
|
||||
@@ -33,8 +33,6 @@ import client.processor.npc.FredrickProcessor;
|
||||
import config.YamlConfig;
|
||||
import net.packet.Packet;
|
||||
import net.server.Server;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.ItemInformationProvider;
|
||||
import server.Trade;
|
||||
import tools.DatabaseConnection;
|
||||
@@ -50,6 +48,7 @@ import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author XoticStory
|
||||
@@ -76,7 +75,7 @@ public class HiredMerchant extends AbstractMapObject {
|
||||
private final Visitor[] visitors = new Visitor[3];
|
||||
private final LinkedList<PastVisitor> visitorHistory = new LinkedList<>();
|
||||
private final LinkedHashSet<String> blacklist = new LinkedHashSet<>(); // case-sensitive character names
|
||||
private final Lock visitorLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.VISITOR_MERCH, true);
|
||||
private final Lock visitorLock = new ReentrantLock(true);
|
||||
|
||||
private record Visitor(Character chr, Instant enteredAt) {}
|
||||
|
||||
|
||||
@@ -23,12 +23,11 @@ package server.maps;
|
||||
import client.Character;
|
||||
import client.Client;
|
||||
import client.inventory.Item;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import tools.PacketCreator;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
@@ -40,7 +39,7 @@ public class MapItem extends AbstractMapObject {
|
||||
protected byte type;
|
||||
protected boolean pickedUp = false, playerDrop, partyDrop;
|
||||
protected long dropTime;
|
||||
private final Lock itemLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_ITEM);
|
||||
private final Lock itemLock = new ReentrantLock();
|
||||
|
||||
public MapItem(Item item, Point position, MapObject dropper, Character owner, Client ownerClient, byte type, boolean playerDrop) {
|
||||
setPosition(position);
|
||||
|
||||
@@ -19,16 +19,13 @@
|
||||
*/
|
||||
package server.maps;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import scripting.event.EventInstanceManager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class MapManager {
|
||||
private final int channel;
|
||||
@@ -37,17 +34,17 @@ public class MapManager {
|
||||
|
||||
private final Map<Integer, MapleMap> maps = new HashMap<>();
|
||||
|
||||
private final MonitoredReadLock mapsRLock;
|
||||
private final MonitoredWriteLock mapsWLock;
|
||||
private final Lock mapsRLock;
|
||||
private final Lock mapsWLock;
|
||||
|
||||
public MapManager(EventInstanceManager eim, int world, int channel) {
|
||||
this.world = world;
|
||||
this.channel = channel;
|
||||
this.event = eim;
|
||||
|
||||
MonitoredReentrantReadWriteLock rrwl = new MonitoredReentrantReadWriteLock(MonitoredLockType.MAP_MANAGER);
|
||||
this.mapsRLock = MonitoredReadLockFactory.createLock(rrwl);
|
||||
this.mapsWLock = MonitoredWriteLockFactory.createLock(rrwl);
|
||||
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
||||
this.mapsRLock = readWriteLock.readLock();
|
||||
this.mapsWLock = readWriteLock.writeLock();
|
||||
}
|
||||
|
||||
public MapleMap resetMap(int mapid) {
|
||||
|
||||
@@ -38,16 +38,8 @@ import constants.id.MobId;
|
||||
import constants.inventory.ItemConstants;
|
||||
import net.packet.Packet;
|
||||
import net.server.Server;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.coordinator.world.MonsterAggroCoordinator;
|
||||
import net.server.services.task.channel.FaceExpressionService;
|
||||
import net.server.services.task.channel.MobMistService;
|
||||
import net.server.services.task.channel.OverallService;
|
||||
import net.server.services.type.ChannelServices;
|
||||
@@ -78,6 +70,9 @@ import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
@@ -163,15 +158,15 @@ public class MapleMap {
|
||||
private int timeExpand;
|
||||
|
||||
//locks
|
||||
private final MonitoredReadLock chrRLock;
|
||||
private final MonitoredWriteLock chrWLock;
|
||||
private final MonitoredReadLock objectRLock;
|
||||
private final MonitoredWriteLock objectWLock;
|
||||
private final Lock chrRLock;
|
||||
private final Lock chrWLock;
|
||||
private final Lock objectRLock;
|
||||
private final Lock objectWLock;
|
||||
|
||||
private final Lock lootLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_LOOT, true);
|
||||
private final Lock lootLock = new ReentrantLock(true);
|
||||
|
||||
// due to the nature of loadMapFromWz (synchronized), sole function that calls 'generateMapDropRangeCache', this lock remains optional.
|
||||
private static final Lock bndLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MAP_BOUNDS, true);
|
||||
private static final Lock bndLock = new ReentrantLock(true);
|
||||
|
||||
public MapleMap(int mapid, int world, int channel, int returnMapId, float monsterRate) {
|
||||
this.mapid = mapid;
|
||||
@@ -182,13 +177,14 @@ public class MapleMap {
|
||||
if (this.monsterRate == 0) {
|
||||
this.monsterRate = 1;
|
||||
}
|
||||
final MonitoredReentrantReadWriteLock chrLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.MAP_CHRS, true);
|
||||
chrRLock = MonitoredReadLockFactory.createLock(chrLock);
|
||||
chrWLock = MonitoredWriteLockFactory.createLock(chrLock);
|
||||
|
||||
final MonitoredReentrantReadWriteLock objectLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.MAP_OBJS, true);
|
||||
objectRLock = MonitoredReadLockFactory.createLock(objectLock);
|
||||
objectWLock = MonitoredWriteLockFactory.createLock(objectLock);
|
||||
final ReadWriteLock chrLock = new ReentrantReadWriteLock(true);
|
||||
chrRLock = chrLock.readLock();
|
||||
chrWLock = chrLock.writeLock();
|
||||
|
||||
final ReadWriteLock objectLock = new ReentrantReadWriteLock(true);
|
||||
objectRLock = objectLock.readLock();
|
||||
objectWLock = objectLock.writeLock();
|
||||
|
||||
aggroMonitor = new MonsterAggroCoordinator();
|
||||
}
|
||||
@@ -2677,9 +2673,6 @@ public class MapleMap {
|
||||
|
||||
public void removePlayer(Character chr) {
|
||||
Channel cserv = chr.getClient().getChannelServer();
|
||||
|
||||
FaceExpressionService service = (FaceExpressionService) this.getChannelServer().getServiceAccess(ChannelServices.FACE_EXPRESSION);
|
||||
service.unregisterFaceExpression(mapid, chr);
|
||||
chr.unregisterChairBuff();
|
||||
|
||||
Party party = chr.getParty();
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
package server.maps;
|
||||
|
||||
import client.Character;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.TimerManager;
|
||||
import tools.PacketCreator;
|
||||
|
||||
@@ -29,6 +27,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
@@ -38,7 +37,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
public class MiniDungeon {
|
||||
List<Character> players = new ArrayList<>();
|
||||
ScheduledFuture<?> timeoutTask = null;
|
||||
Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MINIDUNGEON, true);
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
|
||||
int baseMap;
|
||||
long expireTime;
|
||||
|
||||
@@ -29,8 +29,6 @@ import client.inventory.Item;
|
||||
import client.inventory.manipulator.InventoryManipulator;
|
||||
import client.inventory.manipulator.KarmaManipulator;
|
||||
import net.packet.Packet;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.Trade;
|
||||
import tools.PacketCreator;
|
||||
import tools.Pair;
|
||||
@@ -38,6 +36,7 @@ import tools.Pair;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Matze
|
||||
@@ -56,7 +55,7 @@ public class PlayerShop extends AbstractMapObject {
|
||||
private final List<String> bannedList = new ArrayList<>();
|
||||
private final List<Pair<Character, String>> chatLog = new LinkedList<>();
|
||||
private final Map<Integer, Byte> chatSlot = new LinkedHashMap<>();
|
||||
private final Lock visitorLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.VISITOR_PSHOP, true);
|
||||
private final Lock visitorLock = new ReentrantLock(true);
|
||||
|
||||
public PlayerShop(Character owner, String description, int itemid) {
|
||||
this.setPosition(owner.getPosition());
|
||||
|
||||
@@ -24,8 +24,6 @@ package server.maps;
|
||||
import client.Client;
|
||||
import config.YamlConfig;
|
||||
import net.packet.Packet;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.services.task.channel.OverallService;
|
||||
import net.server.services.type.ChannelServices;
|
||||
import scripting.reactor.ReactorScriptManager;
|
||||
@@ -38,6 +36,7 @@ import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author Lerk
|
||||
@@ -58,8 +57,8 @@ public class Reactor extends AbstractMapObject {
|
||||
private Runnable delayedRespawnRun = null;
|
||||
private GuardianSpawnPoint guardian = null;
|
||||
private byte facingDirection = 0;
|
||||
private final Lock reactorLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.REACTOR, true);
|
||||
private final Lock hitLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.REACTOR_HIT, true);
|
||||
private final Lock reactorLock = new ReentrantLock(true);
|
||||
private final Lock hitLock = new ReentrantLock(true);
|
||||
|
||||
public Reactor(ReactorStats stats, int rid) {
|
||||
this.evstate = (byte) 0;
|
||||
|
||||
@@ -19,31 +19,25 @@
|
||||
*/
|
||||
package tools;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import net.server.audit.locks.factory.MonitoredReadLockFactory;
|
||||
import net.server.audit.locks.factory.MonitoredWriteLockFactory;
|
||||
|
||||
import java.awt.geom.Line2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
public class IntervalBuilder {
|
||||
|
||||
private final List<Line2D> intervalLimits = new ArrayList<>();
|
||||
|
||||
protected MonitoredReadLock intervalRlock;
|
||||
protected MonitoredWriteLock intervalWlock;
|
||||
private final Lock intervalRlock;
|
||||
private final Lock intervalWlock;
|
||||
|
||||
public IntervalBuilder() {
|
||||
MonitoredReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.INTERVAL, true);
|
||||
intervalRlock = MonitoredReadLockFactory.createLock(locks);
|
||||
intervalWlock = MonitoredWriteLockFactory.createLock(locks);
|
||||
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
|
||||
this.intervalRlock = readWriteLock.readLock();
|
||||
this.intervalWlock = readWriteLock.writeLock();
|
||||
}
|
||||
|
||||
private void refitOverlappedIntervals(int st, int en, int newFrom, int newTo) {
|
||||
|
||||
Reference in New Issue
Block a user