From bd52834b796783e5101a7f0581333b6acb62e17c Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 19 Aug 2019 16:07:48 -0400 Subject: [PATCH] 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** --- .../jdbc/lock/JdbcLockRegistry.java | 37 ++++++++++++++----- src/reference/asciidoc/jdbc.adoc | 3 ++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/lock/JdbcLockRegistry.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/lock/JdbcLockRegistry.java index 9bc5bb806cd..2f546871247 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/lock/JdbcLockRegistry.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/lock/JdbcLockRegistry.java @@ -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; @@ -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) { @@ -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; } @@ -108,7 +125,7 @@ public void lock() { while (true) { try { while (!doLock()) { - Thread.sleep(100); //NOSONAR + Thread.sleep(this.idleBetweenTries.toMillis()); } break; } @@ -116,11 +133,11 @@ public void lock() { // 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(); @@ -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(); } @@ -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(); diff --git a/src/reference/asciidoc/jdbc.adoc b/src/reference/asciidoc/jdbc.adoc index 27ee0297821..e5a8b38793d 100644 --- a/src/reference/asciidoc/jdbc.adoc +++ b/src/reference/asciidoc/jdbc.adoc @@ -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