GH-3010 Add idleBetweenTries for JdbcLockRegistry
Fixes https://github.com/spring-projects/spring-integration/issues/3010 Sometimes `100` milliseconds interval is too often to try to obtain a lock with `UPDATE/INSERT` queries **Cherry-pick to 5.1.x**
This commit is contained in:
committed by
Gary Russell
parent
f0807fe704
commit
f600361237
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.integration.jdbc.lock;
|
package org.springframework.integration.jdbc.lock;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -55,15 +56,28 @@ public class JdbcLockRegistry implements ExpirableLockRegistry {
|
|||||||
|
|
||||||
private final LockRepository client;
|
private final LockRepository client;
|
||||||
|
|
||||||
|
private Duration idleBetweenTries = Duration.ofMillis(100);
|
||||||
|
|
||||||
public JdbcLockRegistry(LockRepository client) {
|
public JdbcLockRegistry(LockRepository client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify a @link Duration} to sleep between lock record insert/update attempts.
|
||||||
|
* Defaults to 100 milliseconds.
|
||||||
|
* @param idleBetweenTries the {@link Duration} to sleep between insert/update attempts.
|
||||||
|
* @since 5.1.8
|
||||||
|
*/
|
||||||
|
public void setIdleBetweenTries(Duration idleBetweenTries) {
|
||||||
|
Assert.notNull(idleBetweenTries, "'idleBetweenTries' must not be null");
|
||||||
|
this.idleBetweenTries = idleBetweenTries;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Lock obtain(Object lockKey) {
|
public Lock obtain(Object lockKey) {
|
||||||
Assert.isInstanceOf(String.class, lockKey);
|
Assert.isInstanceOf(String.class, lockKey);
|
||||||
String path = pathFor((String) lockKey);
|
String path = pathFor((String) lockKey);
|
||||||
return this.locks.computeIfAbsent(path, p -> new JdbcLock(this.client, p));
|
return this.locks.computeIfAbsent(path, (key) -> new JdbcLock(this.client, this.idleBetweenTries, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String pathFor(String input) {
|
private String pathFor(String input) {
|
||||||
@@ -87,14 +101,17 @@ public class JdbcLockRegistry implements ExpirableLockRegistry {
|
|||||||
|
|
||||||
private final LockRepository mutex;
|
private final LockRepository mutex;
|
||||||
|
|
||||||
|
private final Duration idleBetweenTries;
|
||||||
|
|
||||||
private final String path;
|
private final String path;
|
||||||
|
|
||||||
private volatile long lastUsed = System.currentTimeMillis();
|
private volatile long lastUsed = System.currentTimeMillis();
|
||||||
|
|
||||||
private final ReentrantLock delegate = new ReentrantLock();
|
private final ReentrantLock delegate = new ReentrantLock();
|
||||||
|
|
||||||
JdbcLock(LockRepository client, String path) {
|
JdbcLock(LockRepository client, Duration idleBetweenTries, String path) {
|
||||||
this.mutex = client;
|
this.mutex = client;
|
||||||
|
this.idleBetweenTries = idleBetweenTries;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +125,7 @@ public class JdbcLockRegistry implements ExpirableLockRegistry {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
while (!doLock()) {
|
while (!doLock()) {
|
||||||
Thread.sleep(100); //NOSONAR
|
Thread.sleep(this.idleBetweenTries.toMillis());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -116,11 +133,11 @@ public class JdbcLockRegistry implements ExpirableLockRegistry {
|
|||||||
// try again
|
// try again
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
/*
|
/*
|
||||||
* This method must be uninterruptible so catch and ignore
|
* This method must be uninterruptible so catch and ignore
|
||||||
* interrupts and only break out of the while loop when
|
* interrupts and only break out of the while loop when
|
||||||
* we get the lock.
|
* we get the lock.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
this.delegate.unlock();
|
this.delegate.unlock();
|
||||||
@@ -139,7 +156,7 @@ public class JdbcLockRegistry implements ExpirableLockRegistry {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
while (!doLock()) {
|
while (!doLock()) {
|
||||||
Thread.sleep(100); //NOSONAR
|
Thread.sleep(this.idleBetweenTries.toMillis());
|
||||||
if (Thread.currentThread().isInterrupted()) {
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
}
|
}
|
||||||
@@ -183,7 +200,7 @@ public class JdbcLockRegistry implements ExpirableLockRegistry {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
while (!(acquired = doLock()) && System.currentTimeMillis() < expire) { //NOSONAR
|
while (!(acquired = doLock()) && System.currentTimeMillis() < expire) { //NOSONAR
|
||||||
Thread.sleep(100); //NOSONAR
|
Thread.sleep(this.idleBetweenTries.toMillis());
|
||||||
}
|
}
|
||||||
if (!acquired) {
|
if (!acquired) {
|
||||||
this.delegate.unlock();
|
this.delegate.unlock();
|
||||||
|
|||||||
@@ -1086,6 +1086,9 @@ The `timeToLive` (TTL) option on the `DefaultLockRepository` is provided for thi
|
|||||||
You may also want to specify `CLIENT_ID` for the locks stored for a given `DefaultLockRepository` instance.
|
You may also want to specify `CLIENT_ID` for the locks stored for a given `DefaultLockRepository` instance.
|
||||||
If so, you can specify the `id` to be associated with the `DefaultLockRepository` as a constructor parameter.
|
If so, you can specify the `id` to be associated with the `DefaultLockRepository` as a constructor parameter.
|
||||||
|
|
||||||
|
Starting with version 5.1.8, the `JdbcLockRegistry` can be configured with the `idleBetweenTries` - a `Duration` to sleep between lock record insert/update executions.
|
||||||
|
By default it is `100` milliseconds and in some environments non-leaders pollute connections with data source too often.
|
||||||
|
|
||||||
[[jdbc-metadata-store]]
|
[[jdbc-metadata-store]]
|
||||||
=== JDBC Metadata Store
|
=== JDBC Metadata Store
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user