mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 06:09:55 +01:00
Merge branch 'db-shutdown-race' into 'master'
Fix race condition in DB shutdown See merge request briar/briar!1620
This commit is contained in:
@@ -70,6 +70,7 @@ import static java.sql.Types.BOOLEAN;
|
|||||||
import static java.sql.Types.INTEGER;
|
import static java.sql.Types.INTEGER;
|
||||||
import static java.sql.Types.VARCHAR;
|
import static java.sql.Types.VARCHAR;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.logging.Level.FINE;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
@@ -572,6 +573,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
try {
|
try {
|
||||||
if (closed) throw new DbClosedException();
|
if (closed) throw new DbClosedException();
|
||||||
txn = connections.poll();
|
txn = connections.poll();
|
||||||
|
logConnectionCounts();
|
||||||
} finally {
|
} finally {
|
||||||
connectionsLock.unlock();
|
connectionsLock.unlock();
|
||||||
}
|
}
|
||||||
@@ -582,7 +584,14 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
txn.setAutoCommit(false);
|
txn.setAutoCommit(false);
|
||||||
connectionsLock.lock();
|
connectionsLock.lock();
|
||||||
try {
|
try {
|
||||||
|
// The DB may have been closed since the check above
|
||||||
|
if (closed) {
|
||||||
|
tryToClose(txn, LOG, WARNING);
|
||||||
|
throw new DbClosedException();
|
||||||
|
}
|
||||||
openConnections++;
|
openConnections++;
|
||||||
|
logConnectionCounts();
|
||||||
|
connectionsChanged.signalAll();
|
||||||
} finally {
|
} finally {
|
||||||
connectionsLock.unlock();
|
connectionsLock.unlock();
|
||||||
}
|
}
|
||||||
@@ -593,67 +602,87 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
return txn;
|
return txn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@GuardedBy("connectionsLock")
|
||||||
public void abortTransaction(Connection txn) {
|
private void logConnectionCounts() {
|
||||||
try {
|
if (LOG.isLoggable(FINE)) {
|
||||||
txn.rollback();
|
LOG.fine(openConnections + " connections open, "
|
||||||
connectionsLock.lock();
|
+ connections.size() + " in pool");
|
||||||
try {
|
|
||||||
connections.add(txn);
|
|
||||||
connectionsChanged.signalAll();
|
|
||||||
} finally {
|
|
||||||
connectionsLock.unlock();
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
// Try to close the connection
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
tryToClose(txn, LOG, WARNING);
|
|
||||||
// Whatever happens, allow the database to close
|
|
||||||
connectionsLock.lock();
|
|
||||||
try {
|
|
||||||
openConnections--;
|
|
||||||
connectionsChanged.signalAll();
|
|
||||||
} finally {
|
|
||||||
connectionsLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commitTransaction(Connection txn) throws DbException {
|
public void abortTransaction(Connection txn) {
|
||||||
|
// The transaction may have been aborted due to an earlier exception,
|
||||||
|
// so close the connection rather than returning it to the pool
|
||||||
try {
|
try {
|
||||||
txn.commit();
|
txn.rollback();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DbException(e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
|
closeConnection(txn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeConnection(Connection txn) {
|
||||||
|
tryToClose(txn, LOG, WARNING);
|
||||||
connectionsLock.lock();
|
connectionsLock.lock();
|
||||||
try {
|
try {
|
||||||
connections.add(txn);
|
openConnections--;
|
||||||
|
logConnectionCounts();
|
||||||
connectionsChanged.signalAll();
|
connectionsChanged.signalAll();
|
||||||
} finally {
|
} finally {
|
||||||
connectionsLock.unlock();
|
connectionsLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeAllConnections() throws SQLException {
|
@Override
|
||||||
|
public void commitTransaction(Connection txn) throws DbException {
|
||||||
|
// If the transaction commits successfully then return the connection
|
||||||
|
// to the pool, otherwise close it
|
||||||
|
try {
|
||||||
|
txn.commit();
|
||||||
|
returnConnectionToPool(txn);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
closeConnection(txn);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void returnConnectionToPool(Connection txn) {
|
||||||
|
connectionsLock.lock();
|
||||||
|
try {
|
||||||
|
connections.add(txn);
|
||||||
|
logConnectionCounts();
|
||||||
|
connectionsChanged.signalAll();
|
||||||
|
} finally {
|
||||||
|
connectionsLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeAllConnections() {
|
||||||
boolean interrupted = false;
|
boolean interrupted = false;
|
||||||
connectionsLock.lock();
|
connectionsLock.lock();
|
||||||
try {
|
try {
|
||||||
closed = true;
|
closed = true;
|
||||||
for (Connection c : connections) c.close();
|
for (Connection c : connections) tryToClose(c, LOG, WARNING);
|
||||||
openConnections -= connections.size();
|
openConnections -= connections.size();
|
||||||
connections.clear();
|
connections.clear();
|
||||||
while (openConnections > 0) {
|
while (openConnections > 0) {
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("Waiting for " + openConnections
|
||||||
|
+ " connections to be closed");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
connectionsChanged.await();
|
connectionsChanged.await();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while closing connections");
|
LOG.warning("Interrupted while closing connections");
|
||||||
interrupted = true;
|
interrupted = true;
|
||||||
}
|
}
|
||||||
for (Connection c : connections) c.close();
|
for (Connection c : connections) tryToClose(c, LOG, WARNING);
|
||||||
openConnections -= connections.size();
|
openConnections -= connections.size();
|
||||||
connections.clear();
|
connections.clear();
|
||||||
}
|
}
|
||||||
|
LOG.info("All connections closed");
|
||||||
} finally {
|
} finally {
|
||||||
connectionsLock.unlock();
|
connectionsLock.unlock();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user