2018-10-28 09:10:56 +01:00
/ *
* This file is part of Player Analytics ( Plan ) .
*
* Plan is free software : you can redistribute it and / or modify
2018-11-11 19:55:11 +01:00
* it under the terms of the GNU Lesser General Public License v3 as published by
2018-10-28 09:10:56 +01:00
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* Plan is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2018-11-11 19:55:11 +01:00
* GNU Lesser General Public License for more details .
2018-10-28 09:10:56 +01:00
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan . If not , see < https : //www.gnu.org/licenses/>.
* /
2019-08-30 22:14:54 +02:00
package com.djrapitops.plan.storage.database ;
2016-12-30 23:39:11 +01:00
2022-12-18 20:32:08 +01:00
import com.djrapitops.plan.exceptions.database.DBClosedException ;
2019-08-30 11:36:38 +02:00
import com.djrapitops.plan.exceptions.database.DBInitException ;
import com.djrapitops.plan.exceptions.database.DBOpException ;
import com.djrapitops.plan.exceptions.database.FatalDBException ;
2021-03-12 17:03:00 +01:00
import com.djrapitops.plan.identification.ServerUUID ;
2019-08-30 22:14:54 +02:00
import com.djrapitops.plan.settings.config.PlanConfig ;
import com.djrapitops.plan.settings.config.paths.PluginSettings ;
import com.djrapitops.plan.settings.config.paths.TimeSettings ;
import com.djrapitops.plan.settings.locale.Locale ;
2021-03-24 13:00:08 +01:00
import com.djrapitops.plan.settings.locale.lang.PluginLang ;
2019-08-30 22:14:54 +02:00
import com.djrapitops.plan.storage.database.queries.Query ;
2022-05-26 07:40:01 +02:00
import com.djrapitops.plan.storage.database.transactions.ThrowawayTransaction ;
2019-08-30 22:14:54 +02:00
import com.djrapitops.plan.storage.database.transactions.Transaction ;
import com.djrapitops.plan.storage.database.transactions.init.CreateIndexTransaction ;
import com.djrapitops.plan.storage.database.transactions.init.CreateTablesTransaction ;
import com.djrapitops.plan.storage.database.transactions.init.OperationCriticalTransaction ;
2021-04-27 17:32:32 +02:00
import com.djrapitops.plan.storage.database.transactions.init.RemoveIncorrectTebexPackageDataPatch ;
2019-08-30 22:14:54 +02:00
import com.djrapitops.plan.storage.database.transactions.patches.* ;
2021-10-31 12:16:47 +01:00
import com.djrapitops.plan.storage.file.PlanFiles ;
2019-02-16 19:26:08 +01:00
import com.djrapitops.plan.utilities.java.ThrowableUtils ;
2020-05-15 11:20:29 +02:00
import com.djrapitops.plan.utilities.logging.ErrorContext ;
2020-05-14 15:57:29 +02:00
import com.djrapitops.plan.utilities.logging.ErrorLogger ;
2021-10-31 12:16:47 +01:00
import dev.vankka.dependencydownload.DependencyManager ;
import dev.vankka.dependencydownload.classloader.IsolatedClassLoader ;
import dev.vankka.dependencydownload.repository.Repository ;
import dev.vankka.dependencydownload.repository.StandardRepository ;
2021-03-09 10:36:07 +01:00
import net.playeranalytics.plugin.scheduling.PluginRunnable ;
import net.playeranalytics.plugin.scheduling.RunnableFactory ;
import net.playeranalytics.plugin.scheduling.TimeAmount ;
import net.playeranalytics.plugin.server.PluginLogger ;
2019-08-06 07:49:46 +02:00
import org.apache.commons.lang3.concurrent.BasicThreadFactory ;
2016-12-30 23:39:11 +01:00
2017-07-23 17:18:08 +02:00
import java.sql.Connection ;
import java.sql.SQLException ;
2021-10-31 12:16:47 +01:00
import java.util.* ;
2022-10-30 11:02:29 +01:00
import java.util.concurrent.* ;
2022-05-21 08:58:07 +02:00
import java.util.concurrent.atomic.AtomicBoolean ;
2022-05-26 07:40:01 +02:00
import java.util.concurrent.atomic.AtomicInteger ;
2021-04-23 08:01:59 +02:00
import java.util.function.Function ;
2018-09-29 11:40:58 +02:00
import java.util.function.Supplier ;
2017-07-23 17:18:08 +02:00
2017-03-05 13:13:25 +01:00
/ * *
2017-10-02 20:52:13 +02:00
* Class containing main logic for different data related save and load functionality .
2017-07-31 16:36:19 +02:00
*
2021-02-13 14:16:03 +01:00
* @author AuroraLS3
2017-03-05 13:13:25 +01:00
* /
2019-01-18 17:03:37 +01:00
public abstract class SQLDB extends AbstractDatabase {
2016-12-30 23:39:11 +01:00
2022-01-06 14:43:48 +01:00
private static boolean downloadDriver = true ;
2021-10-31 12:16:47 +01:00
private static final List < Repository > DRIVER_REPOSITORIES = Arrays . asList (
2023-05-06 09:38:12 +02:00
new StandardRepository ( " https://papermc.io/repo/repository/maven-public " ) ,
new StandardRepository ( " https://repo1.maven.org/maven2 " )
2021-10-31 12:16:47 +01:00
) ;
2021-03-12 17:03:00 +01:00
private final Supplier < ServerUUID > serverUUIDSupplier ;
2018-09-29 11:40:58 +02:00
2018-08-21 15:26:37 +02:00
protected final Locale locale ;
protected final PlanConfig config ;
2021-10-31 12:16:47 +01:00
protected final PlanFiles files ;
2018-08-21 15:26:37 +02:00
protected final RunnableFactory runnableFactory ;
protected final PluginLogger logger ;
2020-05-14 15:57:29 +02:00
protected final ErrorLogger errorLogger ;
2018-07-29 08:34:47 +02:00
2022-01-06 14:43:48 +01:00
protected ClassLoader driverClassLoader ;
2021-10-31 12:16:47 +01:00
2019-02-16 19:26:08 +01:00
private Supplier < ExecutorService > transactionExecutorServiceProvider ;
private ExecutorService transactionExecutor ;
2024-02-17 08:06:45 +01:00
private static final ThreadLocal < StackTraceElement [ ] > TRANSACTION_ORIGIN = new ThreadLocal < > ( ) ;
2019-02-16 19:26:08 +01:00
2022-05-26 07:40:01 +02:00
private final AtomicInteger transactionQueueSize = new AtomicInteger ( 0 ) ;
private final AtomicBoolean dropUnimportantTransactions = new AtomicBoolean ( false ) ;
2022-05-21 08:58:07 +02:00
private final AtomicBoolean ranIntoFatalError = new AtomicBoolean ( false ) ;
2020-11-05 22:16:01 +01:00
protected SQLDB (
2021-03-12 17:03:00 +01:00
Supplier < ServerUUID > serverUUIDSupplier ,
2018-08-29 15:56:11 +02:00
Locale locale ,
PlanConfig config ,
2021-10-31 12:16:47 +01:00
PlanFiles files ,
2019-08-21 14:58:00 +02:00
RunnableFactory runnableFactory ,
2018-08-29 15:56:11 +02:00
PluginLogger logger ,
2020-05-14 15:57:29 +02:00
ErrorLogger errorLogger
2018-08-29 15:56:11 +02:00
) {
2018-09-29 11:40:58 +02:00
this . serverUUIDSupplier = serverUUIDSupplier ;
2018-07-29 08:34:47 +02:00
this . locale = locale ;
2018-08-21 15:26:37 +02:00
this . config = config ;
2021-10-31 12:16:47 +01:00
this . files = files ;
2018-08-21 15:26:37 +02:00
this . runnableFactory = runnableFactory ;
this . logger = logger ;
2020-05-14 15:57:29 +02:00
this . errorLogger = errorLogger ;
2019-02-16 19:26:08 +01:00
2019-08-06 07:49:46 +02:00
this . transactionExecutorServiceProvider = ( ) - > {
String nameFormat = " Plan " + getClass ( ) . getSimpleName ( ) + " -transaction-thread-%d " ;
return Executors . newSingleThreadExecutor ( new BasicThreadFactory . Builder ( )
. namingPattern ( nameFormat )
. uncaughtExceptionHandler ( ( thread , throwable ) - > {
2021-03-09 10:36:07 +01:00
if ( config . isTrue ( PluginSettings . DEV_MODE ) ) {
errorLogger . warn ( throwable , ErrorContext . builder ( )
2020-05-15 11:20:29 +02:00
. whatToDo ( " THIS ERROR IS ONLY LOGGED IN DEV MODE " )
. build ( ) ) ;
2019-08-06 07:49:46 +02:00
}
} ) . build ( ) ) ;
} ;
2016-12-30 23:39:11 +01:00
}
2022-01-06 14:43:48 +01:00
public static void setDownloadDriver ( boolean downloadDriver ) {
SQLDB . downloadDriver = downloadDriver ;
}
2021-10-31 12:16:47 +01:00
protected abstract List < String > getDependencyResource ( ) ;
public void downloadDriver ( ) {
2022-01-06 14:43:48 +01:00
if ( downloadDriver ) {
DependencyManager dependencyManager = new DependencyManager ( files . getDataDirectory ( ) . resolve ( " libraries " ) ) ;
dependencyManager . loadFromResource ( getDependencyResource ( ) ) ;
2022-10-30 11:02:29 +01:00
try {
dependencyManager . downloadAll ( null , DRIVER_REPOSITORIES ) . get ( ) ;
} catch ( InterruptedException e ) {
Thread . currentThread ( ) . interrupt ( ) ;
} catch ( ExecutionException e ) {
logger . error ( " Failed to download " + getType ( ) . getName ( ) + " -driver " , e ) ;
2022-09-04 18:21:30 +02:00
}
2021-10-31 12:16:47 +01:00
2022-01-06 14:43:48 +01:00
IsolatedClassLoader classLoader = new IsolatedClassLoader ( ) ;
dependencyManager . load ( null , classLoader ) ;
this . driverClassLoader = classLoader ;
} else {
this . driverClassLoader = getClass ( ) . getClassLoader ( ) ;
}
2021-10-31 12:16:47 +01:00
}
2024-03-10 09:25:42 +01:00
public static ThreadLocal < StackTraceElement [ ] > getTransactionOrigin ( ) {
return TRANSACTION_ORIGIN ;
}
2016-12-30 23:39:11 +01:00
@Override
2019-02-18 17:21:14 +01:00
public void init ( ) {
2024-02-11 14:47:39 +01:00
List < Runnable > unfinishedTransactions = forceCloseTransactionExecutor ( ) ;
2019-02-16 19:26:08 +01:00
this . transactionExecutor = transactionExecutorServiceProvider . get ( ) ;
2019-02-22 09:35:06 +01:00
setState ( State . PATCHING ) ;
2019-02-16 19:26:08 +01:00
2018-02-07 18:23:05 +01:00
setupDataSource ( ) ;
setupDatabase ( ) ;
2019-02-16 19:26:08 +01:00
for ( Runnable unfinishedTransaction : unfinishedTransactions ) {
transactionExecutor . submit ( unfinishedTransaction ) ;
}
// If an OperationCriticalTransaction fails open is set to false.
// See executeTransaction method below.
if ( getState ( ) = = State . CLOSED ) {
throw new DBInitException ( " Failed to set-up Database " ) ;
}
2017-02-17 11:26:13 +01:00
}
2016-12-30 23:39:11 +01:00
2024-02-11 14:47:39 +01:00
protected boolean attemptToCloseTransactionExecutor ( ) {
2019-02-16 19:26:08 +01:00
if ( transactionExecutor = = null | | transactionExecutor . isShutdown ( ) | | transactionExecutor . isTerminated ( ) ) {
2024-02-11 14:47:39 +01:00
return true ;
2019-02-16 19:26:08 +01:00
}
transactionExecutor . shutdown ( ) ;
try {
2021-03-24 13:00:08 +01:00
logger . info ( locale . getString ( PluginLang . DISABLED_WAITING_TRANSACTIONS ) ) ;
2019-02-28 16:46:23 +01:00
Long waitMs = config . getOrDefault ( TimeSettings . DB_TRANSACTION_FINISH_WAIT_DELAY , TimeUnit . SECONDS . toMillis ( 20L ) ) ;
2019-05-09 14:39:22 +02:00
if ( waitMs > TimeUnit . MINUTES . toMillis ( 5L ) ) {
logger . warn ( TimeSettings . DB_TRANSACTION_FINISH_WAIT_DELAY . getPath ( ) + " was set to over 5 minutes, using 5 min instead. " ) ;
waitMs = TimeUnit . MINUTES . toMillis ( 5L ) ;
}
2024-02-11 14:47:39 +01:00
return transactionExecutor . awaitTermination ( waitMs , TimeUnit . MILLISECONDS ) ;
2019-02-16 19:26:08 +01:00
} catch ( InterruptedException e ) {
Thread . currentThread ( ) . interrupt ( ) ;
2024-02-11 14:47:39 +01:00
}
return true ;
}
2018-12-31 16:09:45 +01:00
Patch [ ] patches ( ) {
return new Patch [ ] {
2019-02-16 19:26:08 +01:00
new Version10Patch ( ) ,
new GeoInfoLastUsedPatch ( ) ,
new SessionAFKTimePatch ( ) ,
new KillsServerIDPatch ( ) ,
new WorldTimesSeverIDPatch ( ) ,
new WorldsServerIDPatch ( ) ,
new NicknameLastSeenPatch ( ) ,
new VersionTableRemovalPatch ( ) ,
new DiskUsagePatch ( ) ,
new WorldsOptimizationPatch ( ) ,
new KillsOptimizationPatch ( ) ,
new NicknamesOptimizationPatch ( ) ,
new TransferTableRemovalPatch ( ) ,
2023-01-06 22:06:17 +01:00
// new BadAFKThresholdValuePatch(),
2019-09-28 10:53:42 +02:00
new DeleteIPsPatch ( ) ,
2019-09-05 17:15:33 +02:00
new ExtensionShowInPlayersTablePatch ( ) ,
2019-09-28 10:55:55 +02:00
new ExtensionTableRowValueLengthPatch ( ) ,
2019-11-30 09:47:52 +01:00
new CommandUsageTableRemovalPatch ( ) ,
2020-05-03 22:26:01 +02:00
new BadNukkitRegisterValuePatch ( ) ,
new LinkedToSecurityTablePatch ( ) ,
2020-05-07 09:58:45 +02:00
new LinkUsersToPlayersSecurityTablePatch ( ) ,
2021-01-01 10:26:07 +01:00
new LitebansTableHeaderPatch ( ) ,
2021-03-09 09:01:09 +01:00
new UserInfoHostnamePatch ( ) ,
2021-03-17 10:31:14 +01:00
new ServerIsProxyPatch ( ) ,
2021-04-23 14:33:54 +02:00
new ServerTableRowPatch ( ) ,
new PlayerTableRowPatch ( ) ,
2021-04-27 17:32:32 +02:00
new ExtensionTableProviderValuesForPatch ( ) ,
2022-02-02 16:36:20 +01:00
new RemoveIncorrectTebexPackageDataPatch ( ) ,
2022-04-07 17:24:40 +02:00
new ExtensionTableProviderFormattersPatch ( ) ,
2022-04-09 19:52:29 +02:00
new ServerPlanVersionPatch ( ) ,
2022-04-17 08:28:16 +02:00
new RemoveDanglingUserDataPatch ( ) ,
new RemoveDanglingServerDataPatch ( ) ,
new GeoInfoOptimizationPatch ( ) ,
2022-04-09 19:52:29 +02:00
new PingOptimizationPatch ( ) ,
new UserInfoOptimizationPatch ( ) ,
new WorldTimesOptimizationPatch ( ) ,
new SessionsOptimizationPatch ( ) ,
new UserInfoHostnameAllowNullPatch ( ) ,
new RegisterDateMinimizationPatch ( ) ,
2022-05-20 18:31:46 +02:00
new UsersTableNameLengthPatch ( ) ,
2022-08-28 18:11:51 +02:00
new SessionJoinAddressPatch ( ) ,
2022-10-29 07:23:16 +02:00
new RemoveUsernameFromAccessLogPatch ( ) ,
2022-12-18 20:32:08 +01:00
new ComponentColumnToExtensionDataPatch ( ) ,
2022-12-29 19:54:23 +01:00
new BadJoinAddressDataCorrectionPatch ( ) ,
new AfterBadJoinAddressDataCorrectionPatch ( ) ,
2023-04-06 17:58:42 +02:00
new CorrectWrongCharacterEncodingPatch ( logger , config ) ,
2023-08-20 10:56:13 +02:00
new UpdateWebPermissionsPatch ( ) ,
new WebGroupDefaultGroupsPatch ( ) ,
new WebGroupAddMissingAdminGroupPatch ( ) ,
new LegacyPermissionLevelGroupsPatch ( ) ,
new SecurityTableGroupPatch ( )
2018-12-31 16:09:45 +01:00
} ;
}
2017-03-05 13:13:25 +01:00
/ * *
2017-08-08 19:14:28 +02:00
* Ensures connection functions correctly and all tables exist .
* < p >
* Updates to latest schema .
2017-03-05 13:13:25 +01:00
* /
2019-02-16 19:26:08 +01:00
private void setupDatabase ( ) {
2022-05-26 08:44:55 +02:00
executeTransaction ( new OperationCriticalTransaction ( ) {
@Override
protected void performOperations ( ) {
logger . info ( locale . getString ( PluginLang . DB_SCHEMA_PATCH ) ) ;
}
} ) ;
2019-02-16 19:26:08 +01:00
executeTransaction ( new CreateTablesTransaction ( ) ) ;
for ( Patch patch : patches ( ) ) {
executeTransaction ( patch ) ;
2019-01-10 13:21:33 +01:00
}
2019-02-16 19:26:08 +01:00
executeTransaction ( new OperationCriticalTransaction ( ) {
@Override
protected void performOperations ( ) {
2022-04-09 19:52:29 +02:00
logger . info ( locale . getString ( PluginLang . DB_APPLIED_PATCHES ) ) ;
2019-02-22 09:35:06 +01:00
if ( getState ( ) = = State . PATCHING ) setState ( State . OPEN ) ;
2019-02-16 19:26:08 +01:00
}
} ) ;
registerIndexCreationTask ( ) ;
2019-01-10 13:21:33 +01:00
}
2017-07-29 04:42:13 +02:00
2019-01-10 13:21:33 +01:00
private void registerIndexCreationTask ( ) {
try {
2021-03-09 10:36:07 +01:00
runnableFactory . create ( new PluginRunnable ( ) {
2019-01-26 10:58:03 +01:00
@Override
public void run ( ) {
2020-09-01 10:56:27 +02:00
if ( getState ( ) = = State . CLOSED | | getState ( ) = = State . CLOSING ) {
cancel ( ) ;
return ;
}
try {
executeTransaction ( new CreateIndexTransaction ( ) ) ;
} catch ( DBOpException e ) {
2021-03-09 10:36:07 +01:00
errorLogger . warn ( e ) ;
2020-09-01 10:56:27 +02:00
}
2019-01-26 10:58:03 +01:00
}
} ) . runTaskLaterAsynchronously ( TimeAmount . toTicks ( 1 , TimeUnit . MINUTES ) ) ;
2019-01-10 13:21:33 +01:00
} catch ( Exception ignore ) {
// Task failed to register because plugin is being disabled
2017-08-28 12:26:56 +02:00
}
2017-08-16 15:27:36 +02:00
}
2019-02-18 17:21:14 +01:00
/ * *
* Set up the source for connections .
*
* @throws DBInitException If the DataSource fails to be initialized .
* /
public abstract void setupDataSource ( ) ;
2016-12-30 23:39:11 +01:00
2024-03-10 09:25:42 +01:00
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 {
logger . info ( locale . getString ( PluginLang . DISABLED_WAITING_TRANSACTIONS_COMPLETE ) ) ;
}
}
2016-12-31 15:41:28 +01:00
@Override
2018-01-14 14:33:00 +01:00
public void close ( ) {
2024-02-11 14:47:39 +01:00
// SQLiteDB Overrides this, so any additions to this should also be reflected there.
2019-09-30 13:22:03 +02:00
if ( getState ( ) = = State . OPEN ) setState ( State . CLOSING ) ;
2024-02-11 14:47:39 +01:00
if ( attemptToCloseTransactionExecutor ( ) ) {
logger . info ( locale . getString ( PluginLang . DISABLED_WAITING_TRANSACTIONS_COMPLETE ) ) ;
} else {
forceCloseTransactionExecutor ( ) ;
}
2022-01-06 14:43:48 +01:00
unloadDriverClassloader ( ) ;
2019-09-30 13:22:03 +02:00
setState ( State . CLOSED ) ;
2016-12-30 23:39:11 +01:00
}
2017-10-07 18:46:51 +02:00
public abstract Connection getConnection ( ) throws SQLException ;
2017-08-22 18:26:59 +02:00
2018-07-30 15:28:56 +02:00
public abstract void returnToPool ( Connection connection ) ;
2017-08-08 18:26:45 +02:00
2019-02-16 19:26:08 +01:00
@Override
public < T > T query ( Query < T > query ) {
2022-12-18 20:32:08 +01:00
return accessLock . performDatabaseOperation ( ( ) - > query . executeQuery ( this ) ) ;
}
public < T > T queryWithinTransaction ( Query < T > query , Transaction transaction ) {
return accessLock . performDatabaseOperation ( ( ) - > query . executeQuery ( this ) , transaction ) ;
2018-07-28 08:32:05 +02:00
}
2024-03-10 09:25:42 +01:00
protected void unloadDriverClassloader ( ) {
// Unloading class loader using close() causes issues when reloading.
// It is better to leak this memory than crash the plugin on reload.
driverClassLoader = null ;
2024-02-17 08:06:45 +01:00
}
2019-02-16 19:26:08 +01:00
@Override
2022-04-11 18:07:52 +02:00
public CompletableFuture < ? > executeTransaction ( Transaction transaction ) {
2019-02-16 19:26:08 +01:00
if ( getState ( ) = = State . CLOSED ) {
2022-12-18 20:32:08 +01:00
throw new DBClosedException ( " Transaction tried to execute although database is closed. " ) ;
2018-07-28 08:32:05 +02:00
}
2024-02-17 08:06:45 +01:00
StackTraceElement [ ] origin = Thread . currentThread ( ) . getStackTrace ( ) ;
2018-11-03 21:09:12 +01:00
2022-05-26 07:40:01 +02:00
if ( determineIfShouldDropUnimportantTransactions ( transactionQueueSize . incrementAndGet ( ) )
& & transaction instanceof ThrowawayTransaction ) {
// Drop throwaway transaction immediately.
return CompletableFuture . completedFuture ( null ) ;
}
2019-02-16 19:26:08 +01:00
return CompletableFuture . supplyAsync ( ( ) - > {
2022-05-26 07:40:01 +02:00
try {
2024-02-17 08:06:45 +01:00
TRANSACTION_ORIGIN . set ( origin ) ;
2024-02-11 14:47:39 +01:00
if ( getState ( ) = = State . CLOSED ) return CompletableFuture . completedFuture ( null ) ;
2022-12-18 20:32:08 +01:00
accessLock . performDatabaseOperation ( ( ) - > {
if ( ! ranIntoFatalError . get ( ) ) { transaction . executeTransaction ( this ) ; }
} , transaction ) ;
2022-05-26 07:40:01 +02:00
return CompletableFuture . completedFuture ( null ) ;
} finally {
transactionQueueSize . decrementAndGet ( ) ;
2024-02-17 08:06:45 +01:00
TRANSACTION_ORIGIN . remove ( ) ;
2022-05-21 08:58:07 +02:00
}
2021-04-23 08:01:59 +02:00
} , getTransactionExecutor ( ) ) . exceptionally ( errorHandler ( transaction , origin ) ) ;
2019-02-28 11:47:37 +01:00
}
2022-05-26 07:40:01 +02:00
private boolean determineIfShouldDropUnimportantTransactions ( int queueSize ) {
2024-02-11 14:47:39 +01:00
if ( getState ( ) = = State . CLOSING ) {
return true ;
}
2022-05-26 07:40:01 +02:00
boolean dropTransactions = dropUnimportantTransactions . get ( ) ;
if ( queueSize > = 500 & & ! dropTransactions ) {
2022-11-20 19:01:04 +01:00
logger . warn ( " Database queue size: " + queueSize + " , dropping some unimportant transactions. If this keeps happening disable some extensions or optimize MySQL. " ) ;
2022-05-26 07:40:01 +02:00
dropUnimportantTransactions . set ( true ) ;
return true ;
} else if ( queueSize < 50 & & dropTransactions ) {
dropUnimportantTransactions . set ( false ) ;
return false ;
}
return dropTransactions ;
}
2024-02-17 08:06:45 +01:00
private Function < Throwable , CompletableFuture < Object > > errorHandler ( Transaction transaction , StackTraceElement [ ] origin ) {
2021-04-23 08:01:59 +02:00
return throwable - > {
2019-02-16 19:26:08 +01:00
if ( throwable = = null ) {
return CompletableFuture . completedFuture ( null ) ;
2018-06-02 06:59:42 +02:00
}
2020-08-12 12:27:42 +02:00
if ( throwable . getCause ( ) instanceof FatalDBException ) {
2022-05-21 08:58:07 +02:00
ranIntoFatalError . set ( true ) ;
2020-08-12 12:27:42 +02:00
logger . error ( " Database failed to open, " + transaction . getClass ( ) . getName ( ) + " failed to be executed. " ) ;
FatalDBException actual = ( FatalDBException ) throwable . getCause ( ) ;
Optional < String > whatToDo = actual . getContext ( ) . flatMap ( ErrorContext : : getWhatToDo ) ;
2022-06-18 10:31:53 +02:00
whatToDo . ifPresentOrElse (
message - > logger . error ( " What to do: " + message ) ,
( ) - > logger . error ( " Error msg: " + actual . getMessage ( ) )
) ;
2019-02-16 19:26:08 +01:00
setState ( State . CLOSED ) ;
2018-06-02 06:59:42 +02:00
}
2019-02-16 19:26:08 +01:00
ThrowableUtils . appendEntryPointToCause ( throwable , origin ) ;
2021-03-09 10:36:07 +01:00
ErrorContext errorContext = ErrorContext . builder ( )
2020-08-12 12:27:42 +02:00
. related ( " Transaction: " + transaction . getClass ( ) )
2022-05-21 08:58:07 +02:00
. related ( " DB State: " + getState ( ) + " - fatal: " + ranIntoFatalError . get ( ) )
2021-03-09 10:36:07 +01:00
. build ( ) ;
if ( getState ( ) = = State . CLOSED ) {
errorLogger . critical ( throwable , errorContext ) ;
} else {
errorLogger . error ( throwable , errorContext ) ;
}
2019-02-16 19:26:08 +01:00
return CompletableFuture . completedFuture ( null ) ;
2019-02-28 11:47:37 +01:00
} ;
2019-01-18 17:18:54 +01:00
}
2019-02-16 19:26:08 +01:00
private ExecutorService getTransactionExecutor ( ) {
if ( transactionExecutor = = null ) {
transactionExecutor = transactionExecutorServiceProvider . get ( ) ;
}
return transactionExecutor ;
2019-01-18 17:59:45 +01:00
}
2018-07-16 09:29:45 +02:00
@Override
public boolean equals ( Object o ) {
if ( this = = o ) return true ;
if ( o = = null | | getClass ( ) ! = o . getClass ( ) ) return false ;
SQLDB sqldb = ( SQLDB ) o ;
2018-11-03 15:49:55 +01:00
return getType ( ) = = sqldb . getType ( ) ;
2018-07-16 09:29:45 +02:00
}
@Override
public int hashCode ( ) {
2018-11-03 15:49:55 +01:00
return Objects . hash ( getType ( ) . getName ( ) ) ;
2018-07-16 09:29:45 +02:00
}
2018-09-29 11:40:58 +02:00
2021-03-12 17:03:00 +01:00
public Supplier < ServerUUID > getServerUUIDSupplier ( ) {
2018-09-29 11:40:58 +02:00
return serverUUIDSupplier ;
}
2018-10-12 20:29:52 +02:00
2019-02-16 19:26:08 +01:00
public void setTransactionExecutorServiceProvider ( Supplier < ExecutorService > transactionExecutorServiceProvider ) {
this . transactionExecutorServiceProvider = transactionExecutorServiceProvider ;
}
2020-08-12 13:07:45 +02:00
public RunnableFactory getRunnableFactory ( ) {
return runnableFactory ;
}
public PluginLogger getLogger ( ) {
return logger ;
}
2022-04-09 19:52:29 +02:00
public Locale getLocale ( ) {
return locale ;
}
2022-05-26 07:40:01 +02:00
public boolean shouldDropUnimportantTransactions ( ) {
return dropUnimportantTransactions . get ( ) ;
}
2022-08-14 19:35:32 +02:00
public int getTransactionQueueSize ( ) {
return transactionQueueSize . get ( ) ;
}
2016-12-30 23:39:11 +01:00
}