Merge pull request #93 from P0nk/system-cleanup

System cleanup
This commit is contained in:
Ponk
2022-08-11 15:23:12 +02:00
committed by GitHub
68 changed files with 336 additions and 2127 deletions

View File

@@ -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"

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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<>();

View File

@@ -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();

View File

@@ -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 {

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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());
}
}

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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();
}
}

View File

@@ -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) {

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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) {}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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());

View File

@@ -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;

View File

@@ -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) {