[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