Download [#EHC-939] BlockingCache.get sometimes returns null without

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
[EHC-939] BlockingCache.get sometimes returns null without holding lock Created:
12/Apr/12 Updated: 01/Mar/13 Resolved: 14/Nov/12
Status:
Project:
Component/s:
Affects
Version/s:
Fix Version/s:
Resolved
Ehcache Core
ehcache-core
2.5.1
Type:
Reporter:
Resolution:
Labels:
Remaining
Estimate:
Time Spent:
Original
Estimate:
Bug
Petur Runolfsson
As Designed
None
Not Specified
Issue Links:
Related
relates to
EHC-715 BlockingCache.put removes entry if El...
is related to EHC-947 Write lock leak
Terracotta
Target:
2.7.0
Priority:
Assignee:
Votes:
2 Major
Alexander Snaps
1
Not Specified
Not Specified
Vicente
Description
There appears to be a bug in BlockingCache.get in this block:
if (element == null) {
acquiredLockForKey(key, lock, LockType.WRITE);
element = underlyingCache.getQuiet(key);
if (element != null) {
if (underlyingCache.isStatisticsEnabled())
{ element = underlyingCache.get(key); }
lock.unlock(LockType.WRITE);
}
}
Resolved
Closed
It is possible for the element to expire, be evicted or removed by another thread between the
calls to underlyingCache.getQuiet and underlyingCache.get. In that case, element will be null,
but the lock is unlocked anyway.
This could be fixed by adding an extra if (element != null) before calling lock.unlock, or by not
assigning the result of underlyingCache.get to element.
Here is a test that demonstrates the problem:
public class BlockingCacheTest extends BlockingCache {
public BlockingCacheTest(Ehcache cache) throws CacheException
{ super(cache); }
public static void main(String[] args) throws Exception {
Configuration config = ConfigurationFactory.parseConfiguration();
config.getDefaultCacheConfiguration().setStatistics(true);
CacheManager cm = CacheManager.create(config);
cm.addCache("test");
final Cache cache = cm.getCache("test");
System.out.println("statistics=" + cache.isStatisticsEnabled());
final BlockingCacheTest bc = new BlockingCacheTest(cache);
Thread[] threads = new Thread[10];
for (int j = 0; j < threads.length; j++) {
Thread t = new Thread() {
public void run() {
Object key = "key";
for (int i = 0; i < 1000000; i++) {
Element element = bc.get(key);
if (element == null) {
if (!bc.getLockForKey(key).isHeldByCurrentThread(LockType.WRITE))
{ System.err.println("FAIL: i=" + i); System.exit(1); }
bc.put(new Element(key, i));
}
if (i % 7 == 3)
cache.removeAll();
}
}
};
t.start();
threads[j] = t;
}
for (Thread t : threads)
t.join();
System.out.println("SUCCESS");
System.exit(0);
}
}
Comments
Comment by Fiona OShea [ 12/Apr/12 ]
I'm not sure if this relates to .
Alex can you confirm?
Comment by Martin JANDA [ 06/Jun/12 ]
I see that lock.unlock(WRITE) is not called in all paths when element = null. I have deadlock in FJ pool. I don't
in EhCache 2.5.2 sources.
"ForkJoinPool-1-worker-4" - Thread t@34
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Native Method)

parking to wait for <65786232> (a java.util.concurrent.ForkJoinPool)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.ForkJoinPool.tryAwaitWork(ForkJoinPool.java:864)
at java.util.concurrent.ForkJoinPool.work(ForkJoinPool.java:647)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:398)
Locked ownable synchronizers:

locked <674eceb2> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync)
"ForkJoinPool-1-worker-1" - Thread t@17
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Native Method)

waiting to lock <674eceb2> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync) owned
"ForkJoinPool-1-worker-4" t@34
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchro
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:119
at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:94
at net.sf.ehcache.concurrent.ReadWriteLockSync.lock(ReadWriteLockSync.java:50)
at net.sf.ehcache.constructs.blocking.BlockingCache.acquiredLockForKey(BlockingCache.java:186)
at net.sf.ehcache.constructs.blocking.BlockingCache.get(BlockingCache.java:159)
at net.sf.ehcache.constructs.blocking.SelfPopulatingCache.get(SelfPopulatingCache.java:68)
at net.sf.ehcache.constructs.blocking.BlockingCache.get(BlockingCache.java:243)
"ForkJoinPool-1-worker-2" - Thread t@23
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Native Method)

waiting to lock <674eceb2> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync) owned
"ForkJoinPool-1-worker-4" t@34
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchro
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:119
at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:94
at net.sf.ehcache.concurrent.ReadWriteLockSync.lock(ReadWriteLockSync.java:50)
at net.sf.ehcache.constructs.blocking.BlockingCache.acquiredLockForKey(BlockingCache.java:186)
at net.sf.ehcache.constructs.blocking.BlockingCache.get(BlockingCache.java:159)
at net.sf.ehcache.constructs.blocking.SelfPopulatingCache.get(SelfPopulatingCache.java:68)
at net.sf.ehcache.constructs.blocking.BlockingCache.get(BlockingCache.java:243)
"ForkJoinPool-1-worker-3" - Thread t@33
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Native Method)

waiting to lock <674eceb2> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync) owned
"ForkJoinPool-1-worker-4" t@34
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchro
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireShared(AbstractQueuedSynchronize
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireShared(AbstractQueuedSynchronizer.j
at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.lock(ReentrantReadWriteLock.java:73
at net.sf.ehcache.concurrent.ReadWriteLockSync.lock(ReadWriteLockSync.java:50)
at net.sf.ehcache.constructs.blocking.BlockingCache.acquiredLockForKey(BlockingCache.java:186)
at net.sf.ehcache.constructs.blocking.BlockingCache.get(BlockingCache.java:151)
at net.sf.ehcache.constructs.blocking.SelfPopulatingCache.get(SelfPopulatingCache.java:68)
at net.sf.ehcache.constructs.blocking.BlockingCache.get(BlockingCache.java:243)
Comment by Alexander Snaps [ 06/Jun/12 ]
Martin, that's the purpose of BlockingCache, the unlocking of the key only happens when you put a value for the
returned null...
Comment by Martin JANDA [ 07/Jun/12 ]
Threaddump comment is another bug - - Write lock leak
Comment by Fiona OShea [ 14/Nov/12 ]
Closing as we do not see a bug here.
Please open a new Jira if there is still an existing problem.
Generated at Sat May 13 03:42:11 PDT 2017 using JIRA 6.2.4#6261sha1:4d2e6f6f26064845673c8e7ffe9b6b84b45a6e79.
Related documents