Unverified 提交 d5c9eff7 authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #1700 from h2database/double-commit

Double commit in TestKillRestartMulti
...@@ -1393,10 +1393,7 @@ public class Database implements DataHandler { ...@@ -1393,10 +1393,7 @@ public class Database implements DataHandler {
for (Session s : all) { for (Session s : all) {
if (s != except) { if (s != except) {
try { try {
// must roll back, otherwise the session is removed and // this will rollback outstanding transaction
// the transaction log that contains its uncommitted
// operations as well
s.rollback();
s.close(); s.close();
} catch (DbException e) { } catch (DbException e) {
trace.error(e, "disconnecting session #{0}", s.getId()); trace.error(e, "disconnecting session #{0}", s.getId());
......
...@@ -15,6 +15,7 @@ import java.util.LinkedList; ...@@ -15,6 +15,7 @@ import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Command; import org.h2.command.Command;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
...@@ -114,7 +115,6 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -114,7 +115,6 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
private boolean autoCommitAtTransactionEnd; private boolean autoCommitAtTransactionEnd;
private String currentTransactionName; private String currentTransactionName;
private volatile long cancelAtNs; private volatile long cancelAtNs;
private boolean closed;
private final long sessionStart = System.currentTimeMillis(); private final long sessionStart = System.currentTimeMillis();
private ValueTimestampTimeZone transactionStart; private ValueTimestampTimeZone transactionStart;
private ValueTimestampTimeZone currentCommandStart; private ValueTimestampTimeZone currentCommandStart;
...@@ -160,7 +160,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -160,7 +160,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
private ArrayList<Value> temporaryLobs; private ArrayList<Value> temporaryLobs;
private Transaction transaction; private Transaction transaction;
private State state = State.INIT; private final AtomicReference<State> state = new AtomicReference<>(State.INIT);
private long startStatement = -1; private long startStatement = -1;
/** /**
...@@ -598,7 +598,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -598,7 +598,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
* @return the prepared statement * @return the prepared statement
*/ */
public Command prepareLocal(String sql) { public Command prepareLocal(String sql) {
if (closed) { if (isClosed()) {
throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, throw DbException.get(ErrorCode.CONNECTION_BROKEN_1,
"session closed"); "session closed");
} }
...@@ -879,8 +879,9 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -879,8 +879,9 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
@Override @Override
public void close() { public void close() {
if (!closed) { // this is the only operation that can be invoked concurrently
state = State.CLOSED; // so, we should prevent double-closure
if (state.getAndSet(State.CLOSED) != State.CLOSED) {
try { try {
database.checkPowerOff(); database.checkPowerOff();
...@@ -898,7 +899,6 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -898,7 +899,6 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
// want to take the meta lock using the system session. // want to take the meta lock using the system session.
database.unlockMeta(this); database.unlockMeta(this);
} finally { } finally {
closed = true;
database.removeSession(this); database.removeSession(this);
} }
} }
...@@ -1038,11 +1038,11 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1038,11 +1038,11 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
@Override @Override
public Trace getTrace() { public Trace getTrace() {
if (trace != null && !closed) { if (trace != null && !isClosed()) {
return trace; return trace;
} }
String traceModuleName = "jdbc[" + id + "]"; String traceModuleName = "jdbc[" + id + "]";
if (closed) { if (isClosed()) {
return new TraceSystem(null).getTrace(traceModuleName); return new TraceSystem(null).getTrace(traceModuleName);
} }
trace = database.getTraceSystem().getTrace(traceModuleName); trace = database.getTraceSystem().getTrace(traceModuleName);
...@@ -1204,7 +1204,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1204,7 +1204,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
@Override @Override
public boolean isClosed() { public boolean isClosed() {
return closed; return state.get() == State.CLOSED;
} }
public void setThrottle(int throttle) { public void setThrottle(int throttle) {
...@@ -1225,15 +1225,17 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1225,15 +1225,17 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
if (lastThrottle + TimeUnit.MILLISECONDS.toNanos(Constants.THROTTLE_DELAY) > time) { if (lastThrottle + TimeUnit.MILLISECONDS.toNanos(Constants.THROTTLE_DELAY) > time) {
return; return;
} }
State prevState = this.state; State prevState = this.state.get();
if (prevState != State.CLOSED) {
lastThrottle = time + throttleNs; lastThrottle = time + throttleNs;
try { try {
this.state = State.SLEEP; state.compareAndSet(prevState, State.SLEEP);
Thread.sleep(TimeUnit.NANOSECONDS.toMillis(throttleNs)); Thread.sleep(TimeUnit.NANOSECONDS.toMillis(throttleNs));
} catch (Exception e) { } catch (Exception e) {
// ignore InterruptedException // ignore InterruptedException
} finally { } finally {
this.state = prevState; state.compareAndSet(State.SLEEP, prevState);
}
} }
} }
...@@ -1250,7 +1252,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1250,7 +1252,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
* from * from
*/ */
public void setCurrentCommand(Command command, Object generatedKeysRequest) { public void setCurrentCommand(Command command, Object generatedKeysRequest) {
this.currentCommand = command; currentCommand = command;
// Preserve generated keys in case of a new query due to possible nested // Preserve generated keys in case of a new query due to possible nested
// queries in update // queries in update
if (command != null && !command.isQuery()) { if (command != null && !command.isQuery()) {
...@@ -1265,7 +1267,10 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1265,7 +1267,10 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
currentCommandStart = null; currentCommandStart = null;
} }
} }
state = command == null ? State.SLEEP : State.RUNNING; State currentState = state.get();
if(currentState != State.CLOSED) {
state.compareAndSet(currentState, command == null ? State.SLEEP : State.RUNNING);
}
} }
/** /**
...@@ -1782,11 +1787,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1782,11 +1787,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
} }
public State getState() { public State getState() {
return getBlockingSessionId() != 0 ? State.BLOCKED : state; return getBlockingSessionId() != 0 ? State.BLOCKED : state.get();
}
public void setState(State state) {
this.state = state;
} }
public int getBlockingSessionId() { public int getBlockingSessionId() {
......
...@@ -183,23 +183,12 @@ public class TcpServerThread implements Runnable { ...@@ -183,23 +183,12 @@ public class TcpServerThread implements Runnable {
private void closeSession() { private void closeSession() {
if (session != null) { if (session != null) {
RuntimeException closeError = null; RuntimeException closeError = null;
try {
Command rollback = session.prepareLocal("ROLLBACK");
rollback.executeUpdate(false);
} catch (RuntimeException e) {
closeError = e;
server.traceError(e);
} catch (Exception e) {
server.traceError(e);
}
try { try {
session.close(); session.close();
server.removeConnection(threadId); server.removeConnection(threadId);
} catch (RuntimeException e) { } catch (RuntimeException e) {
if (closeError == null) {
closeError = e; closeError = e;
server.traceError(e); server.traceError(e);
}
} catch (Exception e) { } catch (Exception e) {
server.traceError(e); server.traceError(e);
} finally { } finally {
...@@ -544,7 +533,6 @@ public class TcpServerThread implements Runnable { ...@@ -544,7 +533,6 @@ public class TcpServerThread implements Runnable {
} }
default: default:
trace("Unknown operation: " + operation); trace("Unknown operation: " + operation);
closeSession();
close(); close();
} }
} }
......
...@@ -45,7 +45,7 @@ public class TestKillRestart extends TestDb { ...@@ -45,7 +45,7 @@ public class TestKillRestart extends TestDb {
String user = getUser(), password = getPassword(); String user = getUser(), password = getPassword();
String selfDestruct = SelfDestructor.getPropertyString(60); String selfDestruct = SelfDestructor.getPropertyString(60);
String[] procDef = { getJVM(), selfDestruct, String[] procDef = { getJVM(), selfDestruct,
"-cp", getClassPath(), "-cp", getClassPath(), "-ea",
getClass().getName(), "-url", url, "-user", user, getClass().getName(), "-url", url, "-user", user,
"-password", password }; "-password", password };
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论