Hi

Thought of sharing some details about $subject. So that it might help us to
identify or debug any issues in future. We faced a thread synchronization
issue when using Hierarchical locking. The code segment below caused the
issue:

public TopologyLock getTopologyLockForService(String serviceName, boolean
forceCreationIfNotFound) {
        TopologyLock topologyLock =
serviceNameToTopologyLockMap.get(serviceName);
        if (topologyLock == null && forceCreationIfNotFound) {
           * synchronized (TopologyLockHierarchy.class) {*
                if (topologyLock == null) {
                    topologyLock = new TopologyLock();
                    serviceNameToTopologyLockMap.put(serviceName,
topologyLock);
                }
            }
        }
        return topologyLock;
    }

If two threads try to initially access this getTopologyLockForService at
the same time  just after the server startup when try to acquire write
lock, there would be higher chance that they see the topologyLock as null
which is a thread local variable as this method is not thread safe. After
that one thread would enter into synchronized block and add the lock to
hierarchy and exit. But when the second one executes the synchronized
block, since it already has the lock as null due to the get operation is
executed before the synchronized block, it will try to create a lock object
again and add it to the hierarchy. Due to this lock object got overwritten
in the map by second thread, when thread one tries to remove the lock from
the newly created lock object where first thread doesn't hold any lock,
thread one will fail to remove the lock [1]. Then our ReadWriteLockMonitor
complains that lock didn't get removed even after 30s [2].

Solution:

Make the method *syncronized* as below:

public *synchronized* TopologyLock getTopologyLockForService(String
serviceName, boolean forceCreationIfNotFound) {
        TopologyLock topologyLock =
serviceNameToTopologyLockMap.get(serviceName);
        if (topologyLock == null && forceCreationIfNotFound) {
            topologyLock = new TopologyLock();
            serviceNameToTopologyLockMap.put(serviceName, topologyLock);

        }
        return topologyLock;
    }

This solves the issue that was faced earlier.

Please share your concerns, if the fix has any other impact.

[1] [2015-06-23 17:01:34,524]  WARN
{org.apache.stratos.common.concurrent.locks.ReadWriteLock} -  System
warning! Trying to release a lock which has not been taken by the same
thread: [lock-name] application [thread-id] 131 [thread-name]
pool-28-thread-6

[2] 2015-06-23 17:02:04,526] ERROR
{org.apache.stratos.common.concurrent.locks.ReadWriteLockMonitor} -  System
error, lock has not released for 30 seconds: [lock-name] application
[lock-type] Write [thread-id] 131 [thread-name] pool-28-thread-6
[stack-trace]
java.lang.Thread.getStackTrace(Thread.java:1589)
org.apache.stratos.common.concurrent.locks.ReadWriteLock.acquireWriteLock(ReadWriteLock.java:123)
org.apache.stratos.messaging.message.processor.application.updater.ApplicationsUpdater.acquireWriteLockForApplication(ApplicationsUpdater.java:93)
org.apache.stratos.messaging.message.processor.application.GroupInstanceCreatedProcessor.process(GroupInstanceCreatedProcessor.java:57)
org.apache.stratos.messaging.message.processor.MessageProcessorChain.process(MessageProcessorChain.java:61)
org.apache.stratos.messaging.message.receiver.application.ApplicationsEventMessageDelegator.run(ApplicationsEventMessageDelegator.java:70)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:745)

org.apache.stratos.common.exception.LockNotReleasedException
    at
org.apache.stratos.common.concurrent.locks.ReadWriteLockMonitor.checkTimeout(ReadWriteLockMonitor.java:72)
    at
org.apache.stratos.common.concurrent.locks.ReadWriteLockMonitor.run(ReadWriteLockMonitor.java:55)
    at
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
    at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
    at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

Thanks,
Reka




-- 
Reka Thirunavukkarasu
Senior Software Engineer,
WSO2, Inc.:http://wso2.com,
Mobile: +94776442007

Reply via email to