Switch to Maven file structure
This commit is contained in:
112
src/main/java/net/server/audit/locks/MonitoredLockType.java
Normal file
112
src/main/java/net/server/audit/locks/MonitoredLockType.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
36
src/main/java/net/server/audit/locks/MonitoredReadLock.java
Normal file
36
src/main/java/net/server/audit/locks/MonitoredReadLock.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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 {
|
||||
|
||||
public void lock();
|
||||
|
||||
public void unlock();
|
||||
|
||||
public boolean tryLock();
|
||||
|
||||
public MonitoredReadLock dispose();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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 {
|
||||
|
||||
public void lock();
|
||||
|
||||
public void unlock();
|
||||
|
||||
public boolean tryLock();
|
||||
|
||||
public MonitoredReentrantLock dispose();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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();
|
||||
}
|
||||
}
|
||||
36
src/main/java/net/server/audit/locks/MonitoredWriteLock.java
Normal file
36
src/main/java/net/server/audit/locks/MonitoredWriteLock.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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 {
|
||||
|
||||
public void lock();
|
||||
|
||||
public void unlock();
|
||||
|
||||
public boolean tryLock();
|
||||
|
||||
public MonitoredWriteLock dispose();
|
||||
|
||||
}
|
||||
171
src/main/java/net/server/audit/locks/active/TrackerReadLock.java
Normal file
171
src/main/java/net/server/audit/locks/active/TrackerReadLock.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
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 java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import server.TimerManager;
|
||||
|
||||
import net.server.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 tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @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(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
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 java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import config.YamlConfig;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import server.TimerManager;
|
||||
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 tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @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(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
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 java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import server.TimerManager;
|
||||
import net.server.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 tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @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(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
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(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyReadLock extends AbstractEmptyLock implements MonitoredReadLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyReadLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredReadLock dispose() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyReentrantLock extends AbstractEmptyLock implements MonitoredReentrantLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyReentrantLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredReentrantLock dispose() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyWriteLock extends AbstractEmptyLock implements MonitoredWriteLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyWriteLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredWriteLock dispose() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user