/*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see .
*/
package com.l2jserver.gameserver.util;
import gnu.trove.function.TObjectFunction;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.procedure.TIntObjectProcedure;
import gnu.trove.procedure.TIntProcedure;
import gnu.trove.procedure.TObjectProcedure;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Custom extension of TIntObjectHashMap that is synchronized via
* ReentrantReadWriteLock.
* The purpose of this map is to replace the use of FastMap.shared() which
* requires a lot of resources.
*
* @author Nik
*
* @param value object.
*/
public class L2TIntObjectHashMap extends TIntObjectHashMap
{
private final Lock _readLock;
private final Lock _writeLock;
private boolean _tempWritesLockDisable;
public L2TIntObjectHashMap()
{
super();
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
_readLock = lock.readLock();
_writeLock = lock.writeLock();
_tempWritesLockDisable = false;
}
@Override
public V put(int key, V value)
{
_writeLock.lock();
try
{
return super.put(key, value);
}
finally
{
_writeLock.unlock();
}
}
/**
* Unsynchronized operation, its free from any locks.
* Its useful while the readLock is taken by a thread (forEach operation for
* example) and you need to put
* something in the map without causing a deadlock by taking the writeLock
* before the readLock is unlocked.
* @param key
* @param value
* @return
*/
public V unsynchronizedPut(int key, V value)
{
return super.put(key, value);
}
@Override
public V get(int key)
{
if (!_tempWritesLockDisable)
_readLock.lock();
try
{
return super.get(key);
}
finally
{
if (!_tempWritesLockDisable)
_readLock.unlock();
}
}
@Override
public void clear()
{
_writeLock.lock();
try
{
super.clear();
}
finally
{
_writeLock.unlock();
}
}
@Override
public V remove(int key)
{
if (!_tempWritesLockDisable)
_writeLock.lock();
try
{
return super.remove(key);
}
finally
{
if (!_tempWritesLockDisable)
_writeLock.unlock();
}
}
/**
* Unsynchronized operation, its free from any locks.
* Its useful while the readLock is taken by a thread (forEach operation for
* example) and you need to remove
* something in the map without causing a deadlock by taking the writeLock
* before the readLock is unlocked.
* @param key
* @return
*/
public V unsynchronizedRemove(int key)
{
return super.remove(key);
}
@Override
public boolean equals(Object other)
{
_readLock.lock();
try
{
return super.equals(other);
}
finally
{
_readLock.unlock();
}
}
@Override
public V[] values()
{
_readLock.lock();
try
{
return super.values();
}
finally
{
_readLock.unlock();
}
}
@Override
public V[] values(V[] arg0)
{
_readLock.lock();
try
{
return super.values(arg0);
}
finally
{
_readLock.unlock();
}
}
@Override
public int[] keys()
{
_readLock.lock();
try
{
return super.keys();
}
finally
{
_readLock.unlock();
}
}
@Override
public int[] keys(int[] arg0)
{
_readLock.lock();
try
{
return super.keys(arg0);
}
finally
{
_readLock.unlock();
}
}
@Override
public boolean contains(int val)
{
_readLock.lock();
try
{
return super.contains(val);
}
finally
{
_readLock.unlock();
}
}
@Override
public boolean containsValue(Object arg0)
{
_readLock.lock();
try
{
return super.containsValue(arg0);
}
finally
{
_readLock.unlock();
}
}
@Override
public boolean containsKey(int key)
{
_readLock.lock();
try
{
return super.containsKey(key);
}
finally
{
_readLock.unlock();
}
}
@Override
public boolean forEachKey(TIntProcedure procedure)
{
_readLock.lock();
try
{
return super.forEachKey(procedure);
}
finally
{
_readLock.unlock();
}
}
/**
* A safe from deadlock loop. put and remove synchronizers are disabled
* while this loop is running.
* Keep in mind that this uses writeLock instead of readLock, and its
* intended only if you are trying to
* put/remove something while looping the values of this map.
* @param procedure
* @return
*/
public boolean safeForEachKey(TIntProcedure procedure)
{
_writeLock.lock();
try
{
_tempWritesLockDisable = true;
return super.forEachKey(procedure);
}
finally
{
_tempWritesLockDisable = false;
_writeLock.unlock();
}
}
@Override
public boolean forEachValue(TObjectProcedure super V> arg0)
{
_readLock.lock();
try
{
return super.forEachValue(arg0);
}
finally
{
_readLock.unlock();
}
}
/**
* A safe from deadlock loop. put and remove synchronizers are disabled
* while this loop is running.
* Keep in mind that this uses writeLock instead of readLock, and its
* intended only if you are trying to
* put/remove something while looping the values of this map.
* @param arg0
* @return
*/
public boolean safeForEachValue(TObjectProcedure arg0)
{
_writeLock.lock();
try
{
_tempWritesLockDisable = true;
return super.forEachValue(arg0);
}
finally
{
_tempWritesLockDisable = false;
_writeLock.unlock();
}
}
@Override
public boolean forEachEntry(TIntObjectProcedure super V> arg0)
{
_readLock.lock();
try
{
return super.forEachEntry(arg0);
}
finally
{
_readLock.unlock();
}
}
/**
* A safe from deadlock loop. put and remove synchronizers are disabled
* while this loop is running.
* Keep in mind that this uses writeLock instead of readLock, and its
* intended only if you are trying to
* put/remove something while looping the values of this map.
* @param arg0
* @return
*/
public boolean safeForEachEntry(TIntObjectProcedure arg0)
{
_writeLock.lock();
try
{
_tempWritesLockDisable = true;
return super.forEachEntry(arg0);
}
finally
{
_tempWritesLockDisable = false;
_writeLock.unlock();
}
}
@Override
public boolean retainEntries(TIntObjectProcedure super V> arg0)
{
_writeLock.lock();
try
{
return super.retainEntries(arg0);
}
finally
{
_writeLock.unlock();
}
}
@Override
public void transformValues(TObjectFunction arg0)
{
_writeLock.lock();
try
{
super.transformValues(arg0);
}
finally
{
_writeLock.unlock();
}
}
}