Skip to content

GH-3010 Add idleBetweenTries for JdbcLockRegistry #3039

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.integration.jdbc.lock;

import java.time.Duration;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
Expand Down Expand Up @@ -55,15 +56,28 @@ public class JdbcLockRegistry implements ExpirableLockRegistry {

private final LockRepository client;

private Duration idleBetweenTries = Duration.ofMillis(100);

public JdbcLockRegistry(LockRepository 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
public Lock obtain(Object lockKey) {
Assert.isInstanceOf(String.class, 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) {
Expand All @@ -87,14 +101,17 @@ private static final class JdbcLock implements Lock {

private final LockRepository mutex;

private final Duration idleBetweenTries;

private final String path;

private volatile long lastUsed = System.currentTimeMillis();

private final ReentrantLock delegate = new ReentrantLock();

JdbcLock(LockRepository client, String path) {
JdbcLock(LockRepository client, Duration idleBetweenTries, String path) {
this.mutex = client;
this.idleBetweenTries = idleBetweenTries;
this.path = path;
}

Expand All @@ -108,19 +125,19 @@ public void lock() {
while (true) {
try {
while (!doLock()) {
Thread.sleep(100); //NOSONAR
Thread.sleep(this.idleBetweenTries.toMillis());
}
break;
}
catch (TransientDataAccessException e) {
// try again
}
catch (InterruptedException e) {
/*
* This method must be uninterruptible so catch and ignore
* interrupts and only break out of the while loop when
* we get the lock.
*/
/*
* This method must be uninterruptible so catch and ignore
* interrupts and only break out of the while loop when
* we get the lock.
*/
}
catch (Exception e) {
this.delegate.unlock();
Expand All @@ -139,7 +156,7 @@ public void lockInterruptibly() throws InterruptedException {
while (true) {
try {
while (!doLock()) {
Thread.sleep(100); //NOSONAR
Thread.sleep(this.idleBetweenTries.toMillis());
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
Expand Down Expand Up @@ -183,7 +200,7 @@ public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
while (true) {
try {
while (!(acquired = doLock()) && System.currentTimeMillis() < expire) { //NOSONAR
Thread.sleep(100); //NOSONAR
Thread.sleep(this.idleBetweenTries.toMillis());
}
if (!acquired) {
this.delegate.unlock();
Expand Down
3 changes: 3 additions & 0 deletions src/reference/asciidoc/jdbc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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

Expand Down