Fixed - methods belongs to transactional objects get blocked at high concurrency. #1459

pull/1499/head
Nikita 7 years ago
parent ba14300611
commit eb36207f93

@ -575,38 +575,34 @@ public class RedissonLock extends RedissonExpirable implements RLock {
return; return;
} }
// waiting for message
final RedissonLockEntry entry = getEntry(currentThreadId); final RedissonLockEntry entry = getEntry(currentThreadId);
synchronized (entry) { if (entry.getLatch().tryAcquire()) {
if (entry.getLatch().tryAcquire()) { lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId); } else {
} else { // waiting for message
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>(); final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Runnable listener = new Runnable() { final Runnable listener = new Runnable() {
@Override
public void run() {
if (futureRef.get() != null) {
futureRef.get().cancel();
}
lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
}
};
entry.addListener(listener);
if (ttl >= 0) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override @Override
public void run() { public void run(Timeout timeout) throws Exception {
if (futureRef.get() != null) { if (entry.removeListener(listener)) {
futureRef.get().cancel(); lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
} }
lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
} }
}; }, ttl, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
entry.addListener(listener);
if (ttl >= 0) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
synchronized (entry) {
if (entry.removeListener(listener)) {
lockAsync(leaseTime, unit, subscribeFuture, result, currentThreadId);
}
}
}
}, ttl, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
} }
} }
} }
@ -768,48 +764,44 @@ public class RedissonLock extends RedissonExpirable implements RLock {
// waiting for message // waiting for message
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
final RedissonLockEntry entry = getEntry(currentThreadId); final RedissonLockEntry entry = getEntry(currentThreadId);
synchronized (entry) { if (entry.getLatch().tryAcquire()) {
if (entry.getLatch().tryAcquire()) { tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId);
tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId); } else {
} else { final AtomicBoolean executed = new AtomicBoolean();
final AtomicBoolean executed = new AtomicBoolean(); final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>(); final Runnable listener = new Runnable() {
final Runnable listener = new Runnable() { @Override
@Override public void run() {
public void run() { executed.set(true);
executed.set(true); if (futureRef.get() != null) {
if (futureRef.get() != null) { futureRef.get().cancel();
futureRef.get().cancel();
}
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId);
} }
};
entry.addListener(listener);
long t = time.get(); long elapsed = System.currentTimeMillis() - current;
if (ttl >= 0 && ttl < time.get()) { time.addAndGet(-elapsed);
t = ttl;
tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId);
} }
if (!executed.get()) { };
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() { entry.addListener(listener);
@Override
public void run(Timeout timeout) throws Exception { long t = time.get();
synchronized (entry) { if (ttl >= 0 && ttl < time.get()) {
if (entry.removeListener(listener)) { t = ttl;
long elapsed = System.currentTimeMillis() - current; }
time.addAndGet(-elapsed); if (!executed.get()) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId); @Override
} public void run(Timeout timeout) throws Exception {
} if (entry.removeListener(listener)) {
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
tryLockAsync(time, leaseTime, unit, subscribeFuture, result, currentThreadId);
} }
}, t, TimeUnit.MILLISECONDS); }
futureRef.set(scheduledFuture); }, t, TimeUnit.MILLISECONDS);
} futureRef.set(scheduledFuture);
} }
} }
} }

@ -213,40 +213,17 @@ public class RedissonPermitExpirableSemaphore extends RedissonExpirable implemen
// waiting for message // waiting for message
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
final RedissonLockEntry entry = getEntry(); final RedissonLockEntry entry = getEntry();
synchronized (entry) { if (entry.getLatch().tryAcquire()) {
if (entry.getLatch().tryAcquire()) { tryAcquireAsync(time, permits, subscribeFuture, result, ttl, timeUnit);
tryAcquireAsync(time, permits, subscribeFuture, result, ttl, timeUnit); } else {
} else { final AtomicReference<Timeout> waitTimeoutFutureRef = new AtomicReference<Timeout>();
final AtomicReference<Timeout> waitTimeoutFutureRef = new AtomicReference<Timeout>();
final Timeout scheduledFuture;
if (nearestTimeout != null) {
scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
if (waitTimeoutFutureRef.get() != null && !waitTimeoutFutureRef.get().cancel()) {
return;
}
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
tryAcquireAsync(time, permits, subscribeFuture, result, ttl, timeUnit);
}
}, nearestTimeout, TimeUnit.MILLISECONDS);
} else {
scheduledFuture = null;
}
final Runnable listener = new Runnable() { final Timeout scheduledFuture;
if (nearestTimeout != null) {
scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override @Override
public void run() { public void run(Timeout timeout) throws Exception {
if (waitTimeoutFutureRef.get() != null && !waitTimeoutFutureRef.get().cancel()) { if (waitTimeoutFutureRef.get() != null && !waitTimeoutFutureRef.get().cancel()) {
entry.getLatch().release();
return;
}
if (scheduledFuture != null && !scheduledFuture.cancel()) {
entry.getLatch().release();
return; return;
} }
@ -255,29 +232,48 @@ public class RedissonPermitExpirableSemaphore extends RedissonExpirable implemen
tryAcquireAsync(time, permits, subscribeFuture, result, ttl, timeUnit); tryAcquireAsync(time, permits, subscribeFuture, result, ttl, timeUnit);
} }
}; }, nearestTimeout, TimeUnit.MILLISECONDS);
entry.addListener(listener); } else {
scheduledFuture = null;
}
final Runnable listener = new Runnable() {
@Override
public void run() {
if (waitTimeoutFutureRef.get() != null && !waitTimeoutFutureRef.get().cancel()) {
entry.getLatch().release();
return;
}
if (scheduledFuture != null && !scheduledFuture.cancel()) {
entry.getLatch().release();
return;
}
long t = time.get(); long elapsed = System.currentTimeMillis() - current;
Timeout waitTimeoutFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() { time.addAndGet(-elapsed);
@Override
public void run(Timeout timeout) throws Exception {
if (scheduledFuture != null && !scheduledFuture.cancel()) {
return;
}
synchronized (entry) { tryAcquireAsync(time, permits, subscribeFuture, result, ttl, timeUnit);
if (entry.removeListener(listener)) { }
long elapsed = System.currentTimeMillis() - current; };
time.addAndGet(-elapsed); entry.addListener(listener);
tryAcquireAsync(time, permits, subscribeFuture, result, ttl, timeUnit); long t = time.get();
} Timeout waitTimeoutFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
} @Override
public void run(Timeout timeout) throws Exception {
if (scheduledFuture != null && !scheduledFuture.cancel()) {
return;
} }
}, t, TimeUnit.MILLISECONDS);
waitTimeoutFutureRef.set(waitTimeoutFuture); if (entry.removeListener(listener)) {
} long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
tryAcquireAsync(time, permits, subscribeFuture, result, ttl, timeUnit);
}
}
}, t, TimeUnit.MILLISECONDS);
waitTimeoutFutureRef.set(waitTimeoutFuture);
} }
} }
}); });
@ -318,34 +314,32 @@ public class RedissonPermitExpirableSemaphore extends RedissonExpirable implemen
} }
final RedissonLockEntry entry = getEntry(); final RedissonLockEntry entry = getEntry();
synchronized (entry) { if (entry.getLatch().tryAcquire(permits)) {
if (entry.getLatch().tryAcquire(permits)) { acquireAsync(permits, subscribeFuture, result, ttl, timeUnit);
acquireAsync(permits, subscribeFuture, result, ttl, timeUnit); } else {
} else { final Timeout scheduledFuture;
final Timeout scheduledFuture; if (nearestTimeout != null) {
if (nearestTimeout != null) { scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
acquireAsync(permits, subscribeFuture, result, ttl, timeUnit);
}
}, nearestTimeout, TimeUnit.MILLISECONDS);
} else {
scheduledFuture = null;
}
Runnable listener = new Runnable() {
@Override @Override
public void run() { public void run(Timeout timeout) throws Exception {
if (scheduledFuture != null && !scheduledFuture.cancel()) {
entry.getLatch().release();
return;
}
acquireAsync(permits, subscribeFuture, result, ttl, timeUnit); acquireAsync(permits, subscribeFuture, result, ttl, timeUnit);
} }
}; }, nearestTimeout, TimeUnit.MILLISECONDS);
entry.addListener(listener); } else {
scheduledFuture = null;
} }
Runnable listener = new Runnable() {
@Override
public void run() {
if (scheduledFuture != null && !scheduledFuture.cancel()) {
entry.getLatch().release();
return;
}
acquireAsync(permits, subscribeFuture, result, ttl, timeUnit);
}
};
entry.addListener(listener);
} }
} }
}); });

@ -180,45 +180,41 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
// waiting for message // waiting for message
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
final RedissonLockEntry entry = getEntry(); final RedissonLockEntry entry = getEntry();
synchronized (entry) { if (entry.getLatch().tryAcquire()) {
if (entry.getLatch().tryAcquire()) { tryAcquireAsync(time, permits, subscribeFuture, result);
tryAcquireAsync(time, permits, subscribeFuture, result); } else {
} else { final AtomicBoolean executed = new AtomicBoolean();
final AtomicBoolean executed = new AtomicBoolean(); final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>(); final Runnable listener = new Runnable() {
final Runnable listener = new Runnable() { @Override
public void run() {
executed.set(true);
if (futureRef.get() != null && !futureRef.get().cancel()) {
entry.getLatch().release();
return;
}
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
tryAcquireAsync(time, permits, subscribeFuture, result);
}
};
entry.addListener(listener);
long t = time.get();
if (!executed.get()) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override @Override
public void run() { public void run(Timeout timeout) throws Exception {
executed.set(true); if (entry.removeListener(listener)) {
if (futureRef.get() != null && !futureRef.get().cancel()) { long elapsed = System.currentTimeMillis() - current;
entry.getLatch().release(); time.addAndGet(-elapsed);
return;
}
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
tryAcquireAsync(time, permits, subscribeFuture, result); tryAcquireAsync(time, permits, subscribeFuture, result);
}
};
entry.addListener(listener);
long t = time.get();
if (!executed.get()) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
synchronized (entry) {
if (entry.removeListener(listener)) {
long elapsed = System.currentTimeMillis() - current;
time.addAndGet(-elapsed);
tryAcquireAsync(time, permits, subscribeFuture, result);
}
}
} }
}, t, TimeUnit.MILLISECONDS); }
futureRef.set(scheduledFuture); }, t, TimeUnit.MILLISECONDS);
} futureRef.set(scheduledFuture);
} }
} }
} }
@ -251,18 +247,16 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
} }
final RedissonLockEntry entry = getEntry(); final RedissonLockEntry entry = getEntry();
synchronized (entry) { if (entry.getLatch().tryAcquire(permits)) {
if (entry.getLatch().tryAcquire(permits)) { acquireAsync(permits, subscribeFuture, result);
acquireAsync(permits, subscribeFuture, result); } else {
} else { Runnable listener = new Runnable() {
Runnable listener = new Runnable() { @Override
@Override public void run() {
public void run() { acquireAsync(permits, subscribeFuture, result);
acquireAsync(permits, subscribeFuture, result); }
} };
}; entry.addListener(listener);
entry.addListener(listener);
}
} }
} }
}); });

@ -35,12 +35,8 @@ public class LockPubSub extends PublishSubscribe<RedissonLockEntry> {
@Override @Override
protected void onMessage(RedissonLockEntry value, Long message) { protected void onMessage(RedissonLockEntry value, Long message) {
if (message.equals(unlockMessage)) { if (message.equals(unlockMessage)) {
while (true) { Runnable runnableToExecute = value.getListeners().poll();
Runnable runnableToExecute = value.getListeners().poll(); if (runnableToExecute != null) {
if (runnableToExecute == null) {
break;
}
runnableToExecute.run(); runnableToExecute.run();
} }

@ -32,12 +32,8 @@ public class SemaphorePubSub extends PublishSubscribe<RedissonLockEntry> {
@Override @Override
protected void onMessage(RedissonLockEntry value, Long message) { protected void onMessage(RedissonLockEntry value, Long message) {
while (true) { Runnable runnableToExecute = value.getListeners().poll();
Runnable runnableToExecute = value.getListeners().poll(); if (runnableToExecute != null) {
if (runnableToExecute == null) {
break;
}
runnableToExecute.run(); runnableToExecute.run();
} }

@ -22,8 +22,8 @@ public abstract class RedissonBaseTransactionalMapTest extends BaseTest {
@Test @Test
public void testFastPut() throws InterruptedException { public void testFastPut() throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(16); ExecutorService executor = Executors.newFixedThreadPool(200);
for (int i = 0; i < 500; i++) { for (int i = 0; i < 2000; i++) {
executor.submit(() -> { executor.submit(() -> {
for (int j = 0; j < 100; j++) { for (int j = 0; j < 100; j++) {
RTransaction t = redisson.createTransaction(TransactionOptions.defaults()); RTransaction t = redisson.createTransaction(TransactionOptions.defaults());
@ -35,7 +35,7 @@ public abstract class RedissonBaseTransactionalMapTest extends BaseTest {
} }
executor.shutdown(); executor.shutdown();
assertThat(executor.awaitTermination(1, TimeUnit.MINUTES)).isTrue(); assertThat(executor.awaitTermination(2, TimeUnit.MINUTES)).isTrue();
} }

Loading…
Cancel
Save