Close transaction queue after connection wait on SQLite
Affects issues: - #3436
This commit is contained in:
parent
bf3bdb599d
commit
e041e193fc
|
@ -148,7 +148,7 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
List<Runnable> unfinishedTransactions = closeTransactionExecutor(transactionExecutor);
|
List<Runnable> unfinishedTransactions = forceCloseTransactionExecutor();
|
||||||
this.transactionExecutor = transactionExecutorServiceProvider.get();
|
this.transactionExecutor = transactionExecutorServiceProvider.get();
|
||||||
|
|
||||||
setState(State.PATCHING);
|
setState(State.PATCHING);
|
||||||
|
@ -167,9 +167,9 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Runnable> closeTransactionExecutor(ExecutorService transactionExecutor) {
|
protected boolean attemptToCloseTransactionExecutor() {
|
||||||
if (transactionExecutor == null || transactionExecutor.isShutdown() || transactionExecutor.isTerminated()) {
|
if (transactionExecutor == null || transactionExecutor.isShutdown() || transactionExecutor.isTerminated()) {
|
||||||
return Collections.emptyList();
|
return true;
|
||||||
}
|
}
|
||||||
transactionExecutor.shutdown();
|
transactionExecutor.shutdown();
|
||||||
try {
|
try {
|
||||||
|
@ -179,20 +179,27 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
logger.warn(TimeSettings.DB_TRANSACTION_FINISH_WAIT_DELAY.getPath() + " was set to over 5 minutes, using 5 min instead.");
|
logger.warn(TimeSettings.DB_TRANSACTION_FINISH_WAIT_DELAY.getPath() + " was set to over 5 minutes, using 5 min instead.");
|
||||||
waitMs = TimeUnit.MINUTES.toMillis(5L);
|
waitMs = TimeUnit.MINUTES.toMillis(5L);
|
||||||
}
|
}
|
||||||
if (!transactionExecutor.awaitTermination(waitMs, TimeUnit.MILLISECONDS)) {
|
return transactionExecutor.awaitTermination(waitMs, TimeUnit.MILLISECONDS);
|
||||||
List<Runnable> unfinished = transactionExecutor.shutdownNow();
|
|
||||||
int unfinishedCount = unfinished.size();
|
|
||||||
if (unfinishedCount > 0) {
|
|
||||||
logger.warn(unfinishedCount + " unfinished database transactions were not executed.");
|
|
||||||
}
|
|
||||||
return unfinished;
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Runnable> forceCloseTransactionExecutor() {
|
||||||
|
if (transactionExecutor == null || transactionExecutor.isShutdown() || transactionExecutor.isTerminated()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<Runnable> unfinished = transactionExecutor.shutdownNow();
|
||||||
|
int unfinishedCount = unfinished.size();
|
||||||
|
if (unfinishedCount > 0) {
|
||||||
|
logger.warn(unfinishedCount + " unfinished database transactions were not executed.");
|
||||||
|
}
|
||||||
|
return unfinished;
|
||||||
} finally {
|
} finally {
|
||||||
logger.info(locale.getString(PluginLang.DISABLED_WAITING_TRANSACTIONS_COMPLETE));
|
logger.info(locale.getString(PluginLang.DISABLED_WAITING_TRANSACTIONS_COMPLETE));
|
||||||
}
|
}
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Patch[] patches() {
|
Patch[] patches() {
|
||||||
|
@ -307,13 +314,18 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
// SQLiteDB Overrides this, so any additions to this should also be reflected there.
|
||||||
if (getState() == State.OPEN) setState(State.CLOSING);
|
if (getState() == State.OPEN) setState(State.CLOSING);
|
||||||
closeTransactionExecutor(transactionExecutor);
|
if (attemptToCloseTransactionExecutor()) {
|
||||||
|
logger.info(locale.getString(PluginLang.DISABLED_WAITING_TRANSACTIONS_COMPLETE));
|
||||||
|
} else {
|
||||||
|
forceCloseTransactionExecutor();
|
||||||
|
}
|
||||||
unloadDriverClassloader();
|
unloadDriverClassloader();
|
||||||
setState(State.CLOSED);
|
setState(State.CLOSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unloadDriverClassloader() {
|
protected void unloadDriverClassloader() {
|
||||||
// Unloading class loader using close() causes issues when reloading.
|
// Unloading class loader using close() causes issues when reloading.
|
||||||
// It is better to leak this memory than crash the plugin on reload.
|
// It is better to leak this memory than crash the plugin on reload.
|
||||||
|
|
||||||
|
@ -349,6 +361,8 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
|
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
try {
|
try {
|
||||||
|
if (getState() == State.CLOSED) return CompletableFuture.completedFuture(null);
|
||||||
|
|
||||||
accessLock.performDatabaseOperation(() -> {
|
accessLock.performDatabaseOperation(() -> {
|
||||||
if (!ranIntoFatalError.get()) {transaction.executeTransaction(this);}
|
if (!ranIntoFatalError.get()) {transaction.executeTransaction(this);}
|
||||||
}, transaction);
|
}, transaction);
|
||||||
|
@ -360,6 +374,9 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean determineIfShouldDropUnimportantTransactions(int queueSize) {
|
private boolean determineIfShouldDropUnimportantTransactions(int queueSize) {
|
||||||
|
if (getState() == State.CLOSING) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
boolean dropTransactions = dropUnimportantTransactions.get();
|
boolean dropTransactions = dropUnimportantTransactions.get();
|
||||||
if (queueSize >= 500 && !dropTransactions) {
|
if (queueSize >= 500 && !dropTransactions) {
|
||||||
logger.warn("Database queue size: " + queueSize + ", dropping some unimportant transactions. If this keeps happening disable some extensions or optimize MySQL.");
|
logger.warn("Database queue size: " + queueSize + ", dropping some unimportant transactions. If this keeps happening disable some extensions or optimize MySQL.");
|
||||||
|
|
|
@ -201,11 +201,21 @@ public class SQLiteDB extends SQLDB {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
super.close();
|
if (getState() == State.OPEN) setState(State.CLOSING);
|
||||||
|
boolean transactionQueueClosed = attemptToCloseTransactionExecutor();
|
||||||
|
if (transactionQueueClosed) logger.info(locale.getString(PluginLang.DISABLED_WAITING_TRANSACTIONS_COMPLETE));
|
||||||
|
|
||||||
|
unloadDriverClassloader();
|
||||||
|
setState(State.CLOSED);
|
||||||
|
|
||||||
stopConnectionPingTask();
|
stopConnectionPingTask();
|
||||||
|
|
||||||
logger.info(locale.getString(PluginLang.DISABLED_WAITING_SQLITE));
|
logger.info(locale.getString(PluginLang.DISABLED_WAITING_SQLITE));
|
||||||
connectionLock.waitUntilNothingAccessing();
|
connectionLock.waitUntilNothingAccessing();
|
||||||
|
|
||||||
|
// Transaction queue can't be force-closed before all connections have terminated.
|
||||||
|
if (!transactionQueueClosed) forceCloseTransactionExecutor();
|
||||||
|
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
MiscUtils.close(connection);
|
MiscUtils.close(connection);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue