修改cleanupTimer原子更新器
This commit is contained in:
@ -8,6 +8,7 @@ package org.postgresql.core;
|
|||||||
import org.postgresql.PGConnection;
|
import org.postgresql.PGConnection;
|
||||||
import org.postgresql.jdbc.ClientLogic;
|
import org.postgresql.jdbc.ClientLogic;
|
||||||
import org.postgresql.jdbc.FieldMetadata;
|
import org.postgresql.jdbc.FieldMetadata;
|
||||||
|
import org.postgresql.jdbc.PgStatement;
|
||||||
import org.postgresql.jdbc.TimestampUtils;
|
import org.postgresql.jdbc.TimestampUtils;
|
||||||
import org.postgresql.log.Log;
|
import org.postgresql.log.Log;
|
||||||
import org.postgresql.util.LruCache;
|
import org.postgresql.util.LruCache;
|
||||||
@ -17,6 +18,7 @@ import java.sql.Connection;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Driver-internal connection interface. Application code should not use this interface.
|
* 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;
|
PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException;
|
||||||
|
|
||||||
public String getSocketAddress();
|
public String getSocketAddress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timertask atomic updater for a statement
|
||||||
|
* @return AtomicReferenceFieldUpdater<PgStatement, TimerTask>
|
||||||
|
*/
|
||||||
|
AtomicReferenceFieldUpdater<PgStatement, TimerTask> getTimerUpdater();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,6 +78,8 @@ import java.util.TimerTask;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||||
|
|
||||||
import org.postgresql.core.types.PGClob;
|
import org.postgresql.core.types.PGClob;
|
||||||
import org.postgresql.core.types.PGBlob;
|
import org.postgresql.core.types.PGBlob;
|
||||||
|
|
||||||
@ -103,6 +105,16 @@ public class PgConnection implements BaseConnection {
|
|||||||
CONNECTION_INFO_REPORT_BLACK_LIST.put("PGDBNAME","");
|
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<PgStatement, TimerTask> CANCEL_TIMER_UPDATER =
|
||||||
|
AtomicReferenceFieldUpdater.newUpdater(PgStatement.class, TimerTask.class, "cancelTimerTask");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Data initialized on construction:
|
// Data initialized on construction:
|
||||||
//
|
//
|
||||||
@ -2061,5 +2073,9 @@ public class PgConnection implements BaseConnection {
|
|||||||
return this.socketAddress;
|
return this.socketAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AtomicReferenceFieldUpdater<PgStatement, TimerTask> getTimerUpdater() {
|
||||||
|
return CANCEL_TIMER_UPDATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
* 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
|
* 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
|
* 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;
|
public volatile TimerTask cancelTimerTask = null;
|
||||||
private static final AtomicReferenceFieldUpdater<PgStatement, TimerTask> CANCEL_TIMER_UPDATER =
|
|
||||||
AtomicReferenceFieldUpdater.newUpdater(PgStatement.class, TimerTask.class, "cancelTimerTask");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Protects statement from out-of-order cancels. It protects from both
|
* 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() {
|
TimerTask cancelTask = new TimerTask() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
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
|
// Nothing to do here, statement has already finished and cleared
|
||||||
// cancelTimerTask reference
|
// cancelTimerTask reference
|
||||||
return;
|
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);
|
connection.addTimerTask(cancelTask, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1202,12 +1200,12 @@ public class PgStatement implements Statement, BaseStatement {
|
|||||||
* never invoke {@link #cancel()}.
|
* never invoke {@link #cancel()}.
|
||||||
*/
|
*/
|
||||||
private boolean cleanupTimer() {
|
private boolean cleanupTimer() {
|
||||||
TimerTask timerTask = CANCEL_TIMER_UPDATER.get(this);
|
TimerTask timerTask = connection.getTimerUpdater().get(this);
|
||||||
if (timerTask == null) {
|
if (timerTask == null) {
|
||||||
// If timeout is zero, then timer task did not exist, so we safely report "all clear"
|
// If timeout is zero, then timer task did not exist, so we safely report "all clear"
|
||||||
return timeout == 0;
|
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
|
// Failed to update reference -> timer has just fired, so we must wait for the query state to
|
||||||
// become "cancelling".
|
// become "cancelling".
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user