PreparedStatementWrapper separated to two files; changed state from refcnt+monitor to enum
This commit is contained in:
parent
50c03c9f63
commit
a3909e2a5c
@ -28,6 +28,7 @@ xomrk {
|
|||||||
optInContracts()
|
optInContracts()
|
||||||
explicitApi()
|
explicitApi()
|
||||||
|
|
||||||
|
jvmToolchain(21)
|
||||||
jvm {
|
jvm {
|
||||||
withJava()
|
withJava()
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ public class PreparedStatementsCompilationPhantomCache /*implements ReadOnlyProp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BoundPreparedStatementWrapper extends _PreparedStatementWrapper {
|
private static class BoundPreparedStatementWrapper extends _PreparedStatementWrapper_Delegates {
|
||||||
@NotNull
|
@NotNull
|
||||||
private final ConnectionsMapNode _node;
|
private final ConnectionsMapNode _node;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,229 @@
|
|||||||
|
package ru.langrafhomyak.db.jdbc_resources_manager;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
/* package */ abstract class _PreparedStatementWrapper_Logic implements PreparedStatement {
|
||||||
|
private enum State {
|
||||||
|
OPEN, IN_USE, CLOSED
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class StateVar {
|
||||||
|
private final AtomicReference<State> _value;
|
||||||
|
|
||||||
|
StateVar(State initial) {
|
||||||
|
this._value = new AtomicReference<>(initial);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _throwState(@NotNull State v) {
|
||||||
|
if (v == State.OPEN) return;
|
||||||
|
if (v == State.CLOSED)
|
||||||
|
throw new IllegalStateException("This PreparedStatement was returned to pool to cache compilation for future uses");
|
||||||
|
if (v == State.IN_USE) this._throwConcurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterMethod() {
|
||||||
|
this._throwState(this._compareAndExchange(State.OPEN, State.IN_USE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void exitMethod() {
|
||||||
|
this._value.set(State.OPEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
this._throwState(this._compareAndExchange(State.OPEN, State.CLOSED));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isClosed() {
|
||||||
|
return this._value.get() == State.CLOSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _throwConcurrent() {
|
||||||
|
throw new IllegalStateException("You are trying concurrently call method on PreparedStatement while it is not designed to be threadsafe");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
|
private State _compareAndExchange(State expected, State newValue) {
|
||||||
|
if (_isNativeCompareAndExchangeExists) {
|
||||||
|
return this._value.compareAndExchange(expected, newValue);
|
||||||
|
} else {
|
||||||
|
while (true) {
|
||||||
|
final State old = this._value.get();
|
||||||
|
if (old != expected) return old;
|
||||||
|
if (this._value.compareAndSet(expected, newValue)) return old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final boolean _isNativeCompareAndExchangeExists;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final AtomicReference<Object> a = new AtomicReference<>(new Object());
|
||||||
|
boolean f;
|
||||||
|
try {
|
||||||
|
a.compareAndExchange(a, a);
|
||||||
|
f = true;
|
||||||
|
} catch (NoSuchMethodError e) {
|
||||||
|
f = false;
|
||||||
|
}
|
||||||
|
_isNativeCompareAndExchangeExists = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected final PreparedStatement _orig;
|
||||||
|
@NotNull
|
||||||
|
protected final StateVar _state;
|
||||||
|
// private ResultSet _currentQuery = null;
|
||||||
|
private boolean _closeOnCompletion = false;
|
||||||
|
|
||||||
|
_PreparedStatementWrapper_Logic(@NotNull PreparedStatement orig) {
|
||||||
|
this._orig = orig;
|
||||||
|
this._state = new StateVar(State.OPEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void _onClose() throws SQLException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws SQLException {
|
||||||
|
this._state.close();
|
||||||
|
this._onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isClosed() {
|
||||||
|
return this._state.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeOnCompletion() {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
this._closeOnCompletion = true;
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCloseOnCompletion() {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
return this._closeOnCompletion;
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class _BoundResultSetWrapper extends ResultSetWrapper {
|
||||||
|
|
||||||
|
public _BoundResultSetWrapper(@NotNull ResultSet orig) {
|
||||||
|
super(orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws SQLException {
|
||||||
|
if (this._orig.isClosed())
|
||||||
|
return;
|
||||||
|
this._orig.close();
|
||||||
|
// _PreparedStatementWrapper_Logic.this._currentQuery = null;
|
||||||
|
if (_PreparedStatementWrapper_Logic.this._closeOnCompletion)
|
||||||
|
_PreparedStatementWrapper_Logic.this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Statement getStatement() {
|
||||||
|
return _PreparedStatementWrapper_Logic.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private ResultSet _prepareRS(@Nullable ResultSet orig) {
|
||||||
|
requireNonNull(orig, "Underlying PreparedStatement didn't returned ResultSet");
|
||||||
|
ResultSet wrapped = this.new _BoundResultSetWrapper(orig);
|
||||||
|
// this._currentQuery = wrapped;
|
||||||
|
return wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultSet executeQuery() throws SQLException {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
return this._prepareRS(this._orig.executeQuery());
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultSet getResultSet() throws SQLException {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
return this._prepareRS(this._orig.getResultSet());
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResultSet getGeneratedKeys() throws SQLException {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
return this._prepareRS(this._orig.getGeneratedKeys());
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
return iface.isInstance(this) ? iface.cast(this) : this._orig.unwrap(iface);
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
return iface.isInstance(this) || this._orig.isWrapperFor(iface);
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPoolable(boolean value) throws SQLException {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
throw new SQLException("Disabling pooling not allowed on prepared statements driven by PreparedStatementsCompilationCache");
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPoolable() {
|
||||||
|
this._state.enterMethod();
|
||||||
|
try {
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
this._state.exitMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user