From c74202ee5f0d5f438502c94b51e2194411fb037a Mon Sep 17 00:00:00 2001 From: chen-czywj Date: Fri, 24 Feb 2023 15:39:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9cleanupTimer=E5=8E=9F?= =?UTF-8?q?=E5=AD=90=E6=9B=B4=E6=96=B0=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/postgresql/core/BaseConnection.java | 8 ++++++++ .../java/org/postgresql/jdbc/PgConnection.java | 16 ++++++++++++++++ .../java/org/postgresql/jdbc/PgStatement.java | 14 ++++++-------- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java b/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java index 29b43f1..2e7cf67 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java +++ b/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java @@ -8,6 +8,7 @@ package org.postgresql.core; import org.postgresql.PGConnection; import org.postgresql.jdbc.ClientLogic; import org.postgresql.jdbc.FieldMetadata; +import org.postgresql.jdbc.PgStatement; import org.postgresql.jdbc.TimestampUtils; import org.postgresql.log.Log; import org.postgresql.util.LruCache; @@ -17,6 +18,7 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; /** * Driver-internal connection interface. Application code should not use this interface. @@ -228,4 +230,10 @@ public interface BaseConnection extends PGConnection, Connection { PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException; public String getSocketAddress(); + + /** + * Gets the timertask atomic updater for a statement + * @return AtomicReferenceFieldUpdater + */ + AtomicReferenceFieldUpdater getTimerUpdater(); } diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java index 7056343..66a1c34 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java @@ -78,6 +78,8 @@ import java.util.TimerTask; import java.util.concurrent.Executor; import java.io.File; import java.net.URISyntaxException; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + import org.postgresql.core.types.PGClob; import org.postgresql.core.types.PGBlob; @@ -103,6 +105,16 @@ public class PgConnection implements BaseConnection { CONNECTION_INFO_REPORT_BLACK_LIST.put("PGDBNAME",""); } + /**set + * Protects current statement from cancelTask starting, waiting for a bit, and waking up exactly + * on subsequent query execution. The idea is to atomically compare and swap the reference to the + * task, so the task can detect that statement executes different query than the one the + * cancelTask was created. Note: the field must be set/get/compareAndSet via + * {@link #CANCEL_TIMER_UPDATER} as per {@link AtomicReferenceFieldUpdater} javadoc. + */ + private AtomicReferenceFieldUpdater CANCEL_TIMER_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(PgStatement.class, TimerTask.class, "cancelTimerTask"); + // // Data initialized on construction: // @@ -2061,5 +2073,9 @@ public class PgConnection implements BaseConnection { return this.socketAddress; } + public AtomicReferenceFieldUpdater getTimerUpdater() { + return CANCEL_TIMER_UPDATER; + } + } diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java index 7abe182..7211fe3 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java @@ -52,11 +52,9 @@ public class PgStatement implements Statement, BaseStatement { * on subsequent query execution. The idea is to atomically compare and swap the reference to the * task, so the task can detect that statement executes different query than the one the * cancelTask was created. Note: the field must be set/get/compareAndSet via - * {@link #CANCEL_TIMER_UPDATER} as per {@link AtomicReferenceFieldUpdater} javadoc. + * {@link PgConnection CANCEL_TIMER_UPDATER} as per {@link AtomicReferenceFieldUpdater} javadoc. */ - private volatile TimerTask cancelTimerTask = null; - private static final AtomicReferenceFieldUpdater CANCEL_TIMER_UPDATER = - AtomicReferenceFieldUpdater.newUpdater(PgStatement.class, TimerTask.class, "cancelTimerTask"); + public volatile TimerTask cancelTimerTask = null; /** * Protects statement from out-of-order cancels. It protects from both @@ -1181,7 +1179,7 @@ public class PgStatement implements Statement, BaseStatement { TimerTask cancelTask = new TimerTask() { public void run() { try { - if (!CANCEL_TIMER_UPDATER.compareAndSet(PgStatement.this, this, null)) { + if (!connection.getTimerUpdater().compareAndSet(PgStatement.this, this, null)) { // Nothing to do here, statement has already finished and cleared // cancelTimerTask reference return; @@ -1193,7 +1191,7 @@ public class PgStatement implements Statement, BaseStatement { } }; - CANCEL_TIMER_UPDATER.set(this, cancelTask); + connection.getTimerUpdater().set(this, cancelTask); connection.addTimerTask(cancelTask, timeout); } @@ -1202,12 +1200,12 @@ public class PgStatement implements Statement, BaseStatement { * never invoke {@link #cancel()}. */ private boolean cleanupTimer() { - TimerTask timerTask = CANCEL_TIMER_UPDATER.get(this); + TimerTask timerTask = connection.getTimerUpdater().get(this); if (timerTask == null) { // If timeout is zero, then timer task did not exist, so we safely report "all clear" return timeout == 0; } - if (!CANCEL_TIMER_UPDATER.compareAndSet(this, timerTask, null)) { + if (!connection.getTimerUpdater().compareAndSet(this, timerTask, null)) { // Failed to update reference -> timer has just fired, so we must wait for the query state to // become "cancelling". return false;