Now using ReentrantLock instead of synchronized blocks. Should help debug lag issue.

This commit is contained in:
Jeremy Wood 2012-08-11 23:21:58 -04:00
parent 622fb19c4a
commit eb1dc502cd
5 changed files with 265 additions and 40 deletions

View File

@ -47,6 +47,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -350,7 +351,7 @@ public class MVWorld extends SerializationConfig implements MultiverseWorld {
}
}
private final Object propertyLock = new Object();
private final ReentrantLock propertyLock = new ReentrantLock();
// --------------------------------------------------------------
// Begin properties
@ -714,7 +715,13 @@ public class MVWorld extends SerializationConfig implements MultiverseWorld {
*/
@Override
public String getColoredWorldString() {
synchronized (propertyLock) {
Thread thread = Thread.currentThread();
if (propertyLock.isLocked()) {
plugin.log(Level.FINEST, "propertyLock is locked when attempting to get ColoredWorldString on thread: " + thread);
}
propertyLock.lock();
try {
plugin.log(Level.FINEST, "Getting ColoredWorldString on thread: " + thread);
if (alias.length() == 0) {
alias = this.getName();
}
@ -729,6 +736,8 @@ public class MVWorld extends SerializationConfig implements MultiverseWorld {
nameBuilder.append(alias).append(ChatColor.WHITE).toString();
return nameBuilder.toString();
} finally {
propertyLock.unlock();
}
}
@ -940,11 +949,19 @@ public class MVWorld extends SerializationConfig implements MultiverseWorld {
*/
@Override
public String getAlias() {
synchronized (propertyLock) {
Thread thread = Thread.currentThread();
if (propertyLock.isLocked()) {
plugin.log(Level.FINEST, "propertyLock is locked when attempting to get alias on thread: " + thread);
}
propertyLock.lock();
try {
plugin.log(Level.FINEST, "Getting alias on thread: " + thread);
if (this.alias == null || this.alias.length() == 0) {
return this.name;
}
return this.alias;
} finally {
propertyLock.unlock();
}
}
@ -1027,8 +1044,16 @@ public class MVWorld extends SerializationConfig implements MultiverseWorld {
*/
@Override
public boolean isHidden() {
synchronized (propertyLock) {
Thread thread = Thread.currentThread();
if (propertyLock.isLocked()) {
plugin.log(Level.FINEST, "propertyLock is locked when attempting to get hidden on thread: " + thread);
}
propertyLock.lock();
try {
plugin.log(Level.FINEST, "Getting hidden on thread: " + thread);
return this.hidden;
} finally {
propertyLock.unlock();
}
}
@ -1088,8 +1113,16 @@ public class MVWorld extends SerializationConfig implements MultiverseWorld {
*/
@Override
public ChatColor getColor() {
synchronized (propertyLock) {
Thread thread = Thread.currentThread();
if (propertyLock.isLocked()) {
plugin.log(Level.FINEST, "propertyLock is locked when attempting to get color on thread: " + thread);
}
propertyLock.lock();
try {
plugin.log(Level.FINEST, "Getting color on thread: " + thread);
return this.color.getColor();
} finally {
propertyLock.unlock();
}
}
@ -1394,8 +1427,16 @@ public class MVWorld extends SerializationConfig implements MultiverseWorld {
*/
@Override
public ChatColor getStyle() {
synchronized (propertyLock) {
Thread thread = Thread.currentThread();
if (propertyLock.isLocked()) {
plugin.log(Level.FINEST, "propertyLock is locked when attempting to get style on thread: " + thread);
}
propertyLock.lock();
try {
plugin.log(Level.FINEST, "Getting style on thread: " + thread);
return style.getColor();
} finally {
propertyLock.unlock();
}
}

View File

@ -101,6 +101,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -116,7 +117,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
private AnchorManager anchorManager = new AnchorManager(this);
// TODO please let's make this non-static
private MultiverseCoreConfiguration config;
private final Object configLock = new Object();
private final ReentrantLock configLock = new ReentrantLock();
/**
* This method is used to find out who is teleporting a player.
@ -458,8 +459,16 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
} catch (Exception e) {
// We're just thinking "no risk no fun" and therefore have to catch and forget this exception
} finally {
synchronized (configLock) {
config = ((wantedConfig == null) ? new MultiverseCoreConfiguration() : wantedConfig);
Thread thread = Thread.currentThread();
if (configLock.isLocked()) {
//log(Level.FINER, "configLock is locked when attempting to set config variable on thread: " + thread);
}
configLock.lock();
try {
//log(Level.FINER, "Setting config on thread: " + thread);
config = ((wantedConfig == null) ? new MultiverseCoreConfiguration(this) : wantedConfig);
} finally {
configLock.unlock();
}
}
this.migrateWorldConfig();
@ -1223,8 +1232,16 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
*/
@Override
public MultiverseCoreConfig getMVConfig() {
synchronized (configLock) {
Thread thread = Thread.currentThread();
if (configLock.isLocked()) {
log(Level.FINEST, "configLock is locked when attempting to get config on thread: " + thread);
}
configLock.lock();
try {
log(Level.FINEST, "Getting config on thread: " + thread);
return config;
} finally {
configLock.unlock();
}
}

View File

@ -6,6 +6,8 @@ import me.main__.util.SerializationConfig.Property;
import me.main__.util.SerializationConfig.SerializationConfig;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
/**
* Our configuration.
@ -38,7 +40,7 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
return instance;
}
private final Object propertyLock = new Object();
private final ReentrantLock propertyLock = new ReentrantLock();
@Property
private boolean enforceaccess;
@ -61,16 +63,20 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
@Property
private int teleportcooldown;
public MultiverseCoreConfiguration() {
public MultiverseCoreConfiguration(MultiverseCore core) {
super();
this.core = core;
MultiverseCoreConfiguration.setInstance(this);
}
public MultiverseCoreConfiguration(Map<String, Object> values) {
public MultiverseCoreConfiguration(MultiverseCore core, Map<String, Object> values) {
super(values);
this.core = core;
MultiverseCoreConfiguration.setInstance(this);
}
private MultiverseCore core;
/**
* {@inheritDoc}
*/
@ -124,8 +130,16 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
*/
@Override
public boolean getPrefixChat() {
synchronized (propertyLock) {
Thread thread = Thread.currentThread();
if (propertyLock.isLocked()) {
core.log(Level.FINEST, "propertyLock is locked when attempting to get prefixchat on thread: " + thread);
}
propertyLock.lock();
try {
core.log(Level.FINEST, "Getting prefixchat on thread: " + thread);
return this.prefixchat;
} finally {
propertyLock.unlock();
}
}
@ -134,8 +148,16 @@ public class MultiverseCoreConfiguration extends SerializationConfig implements
*/
@Override
public void setPrefixChat(boolean prefixChat) {
synchronized (propertyLock) {
Thread thread = Thread.currentThread();
if (propertyLock.isLocked()) {
core.log(Level.FINEST, "propertyLock is locked when attempting to set prefixchat on thread: " + thread);
}
propertyLock.lock();
try {
core.log(Level.FINEST, "Setting prefixchat on thread: " + thread);
this.prefixchat = prefixChat;
} finally {
propertyLock.unlock();
}
}

View File

@ -30,6 +30,7 @@ import org.bukkit.event.player.PlayerTeleportEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
/**
@ -40,6 +41,7 @@ public class MVPlayerListener implements Listener {
private MVWorldManager worldManager;
private PermissionTools pt;
private final ReentrantLock worldsLock = new ReentrantLock();
private final Map<String, String> playerWorld = new HashMap<String, String>();
public MVPlayerListener(MultiverseCore plugin) {
@ -60,12 +62,20 @@ public class MVPlayerListener implements Listener {
// If not we do nothing, if so we need to check if the World has an Alias.
if (plugin.getMVConfig().getPrefixChat()) {
String world;
synchronized (playerWorld) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to handle player chat on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Handling player chat on thread: " + thread);
world = playerWorld.get(event.getPlayer().getName());
if (world == null) {
world = event.getPlayer().getWorld().getName();
playerWorld.put(event.getPlayer().getName(), world);
}
} finally {
worldsLock.unlock();
}
String prefix = "";
// If we're not a MV world, don't do anything
@ -153,8 +163,16 @@ public class MVPlayerListener implements Listener {
}
// Handle the Players GameMode setting for the new world.
this.handleGameMode(event.getPlayer(), event.getPlayer().getWorld());
synchronized (playerWorld) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to cache player world on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Caching player world on thread: " + thread);
playerWorld.put(p.getName(), p.getWorld().getName());
} finally {
worldsLock.unlock();
}
}
@ -166,8 +184,16 @@ public class MVPlayerListener implements Listener {
public void playerChangedWorld(PlayerChangedWorldEvent event) {
// Permissions now determine whether or not to handle a gamemode.
this.handleGameMode(event.getPlayer(), event.getPlayer().getWorld());
synchronized (playerWorld) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to cache player world on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Caching player world on thread: " + thread);
playerWorld.put(event.getPlayer().getName(), event.getPlayer().getWorld().getName());
} finally {
worldsLock.unlock();
}
}

View File

@ -40,6 +40,7 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -49,6 +50,7 @@ import java.util.logging.Logger;
public class WorldManager implements MVWorldManager {
private final MultiverseCore plugin;
private final WorldPurger worldPurger;
private final ReentrantLock worldsLock = new ReentrantLock();
private final Map<String, MultiverseWorld> worlds;
private Map<String, MVWorld> worldsFromTheConfig;
private FileConfiguration configWorlds = null;
@ -228,8 +230,16 @@ public class WorldManager implements MVWorldManager {
}
// set generator (special case because we can't read it from org.bukkit.World)
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
this.worlds.get(name).setGenerator(generator);
} finally {
worldsLock.unlock();
}
this.saveWorldsConfig();
@ -309,7 +319,13 @@ public class WorldManager implements MVWorldManager {
*/
@Override
public boolean unloadWorld(String name) {
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
if (this.worlds.containsKey(name)) {
if (this.unloadWorldFromBukkit(name, true)) {
this.worlds.remove(name);
@ -330,6 +346,8 @@ public class WorldManager implements MVWorldManager {
} else {
this.plugin.log(Level.INFO, "Multiverse does not know about " + name + " and it's not loaded by Bukkit.");
}
} finally {
worldsLock.unlock();
}
return false;
}
@ -340,10 +358,18 @@ public class WorldManager implements MVWorldManager {
@Override
public boolean loadWorld(String name) {
// Check if the World is already loaded
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
if (this.worlds.containsKey(name)) {
return true;
}
} finally {
worldsLock.unlock();
}
// Check that the world is in the config
@ -382,9 +408,17 @@ public class WorldManager implements MVWorldManager {
String worldName = creator.name();
if (!worldsFromTheConfig.containsKey(worldName))
throw new IllegalArgumentException("That world doesn't exist!");
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
if (worlds.containsKey(worldName))
throw new IllegalArgumentException("That world is already loaded!");
} finally {
worldsLock.unlock();
}
if (!ignoreExists && !new File(this.plugin.getServer().getWorldContainer(), worldName).exists()) {
@ -404,8 +438,15 @@ public class WorldManager implements MVWorldManager {
}
mvworld.init(cbworld, plugin);
this.worldPurger.purgeWorld(mvworld);
synchronized (worlds) {
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
this.worlds.put(worldName, mvworld);
} finally {
worldsLock.unlock();
}
return true;
}
@ -503,8 +544,16 @@ public class WorldManager implements MVWorldManager {
*/
@Override
public Collection<MultiverseWorld> getMVWorlds() {
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
return this.worlds.values();
} finally {
worldsLock.unlock();
}
}
@ -513,10 +562,18 @@ public class WorldManager implements MVWorldManager {
*/
@Override
public MultiverseWorld getMVWorld(String name) {
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
if (this.worlds.containsKey(name)) {
return this.worlds.get(name);
}
} finally {
worldsLock.unlock();
}
return this.getMVWorldByAlias(name);
}
@ -539,12 +596,20 @@ public class WorldManager implements MVWorldManager {
* @return A {@link MVWorld} or null.
*/
private MultiverseWorld getMVWorldByAlias(String alias) {
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
for (MultiverseWorld w : this.worlds.values()) {
if (w.getAlias().equalsIgnoreCase(alias)) {
return w;
}
}
} finally {
worldsLock.unlock();
}
return null;
}
@ -553,9 +618,17 @@ public class WorldManager implements MVWorldManager {
* {@inheritDoc}
*/
@Override
public boolean isMVWorld(String name) {
synchronized (worlds) {
public boolean isMVWorld(final String name) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
return (this.worlds.containsKey(name) || isMVWorldAlias(name));
} finally {
worldsLock.unlock();
}
}
@ -573,13 +646,21 @@ public class WorldManager implements MVWorldManager {
* @param alias The alias of the world to check.
* @return True if the world exists, false if not.
*/
private boolean isMVWorldAlias(String alias) {
synchronized (worlds) {
private boolean isMVWorldAlias(final String alias) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
for (MultiverseWorld w : this.worlds.values()) {
if (w.getAlias().equalsIgnoreCase(alias)) {
return true;
}
}
} finally {
worldsLock.unlock();
}
return false;
}
@ -625,7 +706,13 @@ public class WorldManager implements MVWorldManager {
// Remove all world permissions.
Permission allAccess = this.plugin.getServer().getPluginManager().getPermission("multiverse.access.*");
Permission allExempt = this.plugin.getServer().getPluginManager().getPermission("multiverse.exempt.*");
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
for (MultiverseWorld w : this.worlds.values()) {
// Remove this world from the master list
if (allAccess != null) {
@ -639,19 +726,27 @@ public class WorldManager implements MVWorldManager {
// Special namespace for gamemodes
this.plugin.getServer().getPluginManager().removePermission("mv.bypass.gamemode." + w.getName());
}
}
// Recalc the all permission
this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allAccess);
this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allExempt);
synchronized (worlds) {
// Recalc the all permission
this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allAccess);
this.plugin.getServer().getPluginManager().recalculatePermissionDefaults(allExempt);
this.worlds.clear();
} finally {
worldsLock.unlock();
}
}
for (Map.Entry<String, MVWorld> entry : worldsFromTheConfig.entrySet()) {
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
if (worlds.containsKey(entry.getKey()))
continue;
} finally {
worldsLock.unlock();
}
if (!entry.getValue().getAutoLoad())
continue;
@ -718,10 +813,18 @@ public class WorldManager implements MVWorldManager {
String worldName = key.replaceAll(String.valueOf(SEPARATOR), ".");
if (this.worldsFromTheConfig.containsKey(worldName)) {
// Object-Recycling :D
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
MVWorld oldMVWorld = (MVWorld) this.worlds.get(worldName);
oldMVWorld.copyValues((MVWorld) obj);
newWorldsFromTheConfig.put(worldName, oldMVWorld);
} finally {
worldsLock.unlock();
}
} else {
// we have to use a new one
@ -740,8 +843,16 @@ public class WorldManager implements MVWorldManager {
}
}
this.worldsFromTheConfig = newWorldsFromTheConfig;
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
this.worlds.keySet().retainAll(this.worldsFromTheConfig.keySet());
} finally {
worldsLock.unlock();
}
return this.configWorlds;
}
@ -779,8 +890,16 @@ public class WorldManager implements MVWorldManager {
@Override
public List<String> getUnloadedWorlds() {
List<String> allNames = new ArrayList<String>(this.worldsFromTheConfig.keySet());
synchronized (worlds) {
Thread thread = Thread.currentThread();
if (worldsLock.isLocked()) {
plugin.log(Level.FINEST, "worldsLock is locked when attempting to access worlds on thread: " + thread);
}
worldsLock.lock();
try {
plugin.log(Level.FINEST, "Accessing worlds on thread: " + thread);
allNames.removeAll(worlds.keySet());
} finally {
worldsLock.unlock();
}
return allNames;
}