while (true) {
assertNotTimedOut();
Element oldElement = underlyingStore.getQuiet(key);
if (oldElement == null) {
SoftLock softLock = softLockFactory.createSoftLock(getCurrentTransactionContext().getTransactionId(), key,
null, oldElement);
softLock.lock();
Element newElement = createElement(key, softLock);
oldElement = underlyingStore.putIfAbsent(newElement);
if (oldElement == null) {
// CAS succeeded, value is in store, job done.
getCurrentTransactionContext().registerSoftLock(cacheName, this, softLock);
LOG.debug("remove: cache [{}] key [{}] was not in, soft lock inserted", cacheName, key);
return null;
} else {
// CAS failed, something with that key may now be in store, restart.
softLock.unlock();
LOG.debug("remove: cache [{}] key [{}] was not in, soft lock insertion failed, retrying...", cacheName, key);
continue;
}
} else {
Object value = oldElement.getObjectValue();
if (value instanceof SoftLock) {
SoftLock softLock = (SoftLock) value;
if (cleanupExpiredSoftLock(oldElement, softLock)) {
LOG.debug("remove: cache [{}] key [{}] guarded by expired soft lock, cleaned up {}",
new Object[] {cacheName, key, softLock});
continue;
}
if (softLock.getTransactionID().equals(getCurrentTransactionContext().getTransactionId())) {
Element removed = softLock.updateElement(null);
underlyingStore.put(oldElement);
getCurrentTransactionContext().updateSoftLock(cacheName, softLock);
// replaced old value with new one under soft lock, job done.
LOG.debug("remove: cache [{}] key [{}] soft locked in current transaction, replaced old value with new one under" +
" soft lock", cacheName, key);
return copyElementForRead(removed);
} else {
try {
LOG.debug("remove: cache [{}] key [{}] soft locked in foreign transaction, waiting {}ms for soft lock to" +
" die...", new Object[] {cacheName, key, timeBeforeTimeout()});
boolean locked = softLock.tryLock(timeBeforeTimeout());
if (!locked) {
LOG.debug("remove: cache [{}] key [{}] soft locked in foreign transaction and not released before" +
" current transaction timeout", cacheName, key);
throw new DeadLockException("deadlock detected in cache [" + cacheName + "] on key [" + key + "] between" +
" current transaction [" + getCurrentTransactionContext().getTransactionId() + "] and foreign" +
" transaction [" + softLock.getTransactionID() + "]");
}
softLock.clearTryLock();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
// once the soft lock got unlocked we don't know what's in the store anymore, restart.
LOG.debug("remove: cache [{}] key [{}] soft locked in foreign transaction, soft lock died, retrying...",
cacheName, key);
continue;
}
} else {
SoftLock softLock = softLockFactory.createSoftLock(getCurrentTransactionContext().getTransactionId(), key,
null, oldElement);
softLock.lock();
Element newElement = createElement(key, softLock);
boolean replaced = underlyingStore.replace(oldElement, newElement, comparator);
if (replaced) {
// CAS succeeded, value replaced with soft lock, job done.
getCurrentTransactionContext().registerSoftLock(cacheName, this, softLock);
LOG.debug("remove: cache [{}] key [{}] was in, replaced with soft lock", cacheName, key);
return copyElementForRead(oldElement);
} else {
// CAS failed, something else with that key is now in store or the key disappeared, restart.
softLock.unlock();
LOG.debug("remove: cache [{}] key [{}] was in, replacement by soft lock failed, retrying...", cacheName, key);
continue;
}
}
}