[Opensymphony-oscache] Deadlock using GeneralCacheAdministrator

rintcius <[email protected]> Thu, 01 Sep 2005 03:37:49 CDT
Newsgroups gmane.comp.java.open-symphony.os-cache
Message-ID <28828326.1125564537709.JavaMail.os-j2ee@opensymphony01.contegix.com>
I have a deadlock situation with oscache 2.1 as well as 2.1.1 which is used in a jboss 4.0 appserver.
I am using the GeneralCacheAdministrator in the typical use without failover that is described in e.g
http://www.opensymphony.com/oscache/api/com/opensymphony/oscache/general/GeneralCacheAdministrator.html
The problem occurs when multiple requests are handled simultaneously and the application is in the process of filling the cache.
I have searched through the open bug reports. It looks a bit similar to http://jira.opensymphony.com/browse/CACHE-182 but it occurs at a different place in the code.

Here is a theory of what happens in our case:
1) thread 1 obtains a jboss managed transaction lock
2) thread 2 tries to retrieve a value from the cache but it is not there yet so a NeedsRefreshException is thrown and the content is retrieved, blocking the entry until this thread delivers or cancels the entry (putInCache or cancelUpdate)
3) thread 1 tries to retrieve a value from the cache but it is blocked by thread 2 (see stacktrace 1)
4) thread 2 waits on thread 1 to release the transaction lock in order to actually retrieve the data (see stacktrace 2)

Note: blocking is set to false in our case, so in the Cache class updateState.wait() is called because cacheEntry.isNew() is true. The value of blocking is not important here.

We can avoid the deadlock by doing the actual retrieval *after* cancelling the update in case of a cache miss and do another getFromCache/putInCache/cancelUpdate-cycle after the retrieval is done. However this solution looks kind of clumsy (see the code below).
Does anyone have other suggestions? Is this a bug in oscache or am I missing something?
Thanks for any suggestions.

Rintcius


stacktrace 1:
 System Thread [RMI TCP Connection(8)-10.181.1.32] (Suspended)
	Object.wait(long) line: not available [native method]
	EntryUpdateState(Object).wait() line: 429 [local variables unavailable]
	Cache.getFromCache(String, int, String) line: 260
	Cache.getFromCache(String) line: 183
	GeneralCacheAdministrator.getFromCache(String) line: 124
	ChannelContainer.getByName(String) line: 594

stacktrace 2: 
System Thread [RMI TCP Connection(7)-10.181.1.32] (Suspended)
	Object.wait(long) line: not available [native method]
	QueuedPessimisticEJBLock.waitForTx(Transaction, boolean) line: 332
	QueuedPessimisticEJBLock.doSchedule(Invocation) line: 236
	...
	...
	$Proxy116.getAccessBean() line: not available
	ChannelContainer.doGetByName(String) line: 656
	ChannelContainer.getByName(String) line: 598
 

  public ChannelAccessBean getByName(String name) throws DataFindException {
    String cacheKey = getCacheKeyForName(name);
    ChannelAccessBean channel;
    try {
      channel = (ChannelAccessBean) getCacheAdministrator().getFromCache(cacheKey);
    } catch (NeedsRefreshException e) {
      // cancel asap to avoid deadlock
      getCacheAdministrator().cancelUpdate(cacheKey);

      channel = doGetByName(name);
      // do another getFromCache + putInCache/cancelUpdate cycle
      putInCache(cacheKey, channel);
    }
    return channel;
  }

  private void putInCache(String cacheKey, ChannelAccessBean channel) {
    try {
      getCacheAdministrator().getFromCache(cacheKey);
    } catch (NeedsRefreshException e) {
      boolean updated = false;
      try {
        getCacheAdministrator().putInCache(cacheKey, channel, new String[]{CACHE_GROUP_NAME});
        updated = true;
      } finally {
        if (!updated) {
          getCacheAdministrator().cancelUpdate(cacheKey);
        }
      }
    }
  }

---------------------------------------------------------------------
Posted via Jive Forums
http://forums.opensymphony.com/thread.jspa?threadID=6334&messageID=14272#14272