diff --git a/stickynote-bukkit/src/main/kotlin/org/sayandev/stickynote/bukkit/StickyNote.kt b/stickynote-bukkit/src/main/kotlin/org/sayandev/stickynote/bukkit/StickyNote.kt index ec647cba..8f866c1e 100644 --- a/stickynote-bukkit/src/main/kotlin/org/sayandev/stickynote/bukkit/StickyNote.kt +++ b/stickynote-bukkit/src/main/kotlin/org/sayandev/stickynote/bukkit/StickyNote.kt @@ -4,6 +4,7 @@ import com.github.shynixn.mccoroutine.bukkit.registerSuspendingEvents import com.github.shynixn.mccoroutine.folia.launch import com.google.common.util.concurrent.ThreadFactoryBuilder import kotlinx.coroutines.* +import org.bukkit.Location import org.bukkit.entity.Player import org.bukkit.event.HandlerList import org.bukkit.event.Listener diff --git a/stickynote-core/src/main/kotlin/org/sayandev/stickynote/core/database/sqlite/SQLiteDatabase.kt b/stickynote-core/src/main/kotlin/org/sayandev/stickynote/core/database/sqlite/SQLiteDatabase.kt index 1258849a..85383810 100644 --- a/stickynote-core/src/main/kotlin/org/sayandev/stickynote/core/database/sqlite/SQLiteDatabase.kt +++ b/stickynote-core/src/main/kotlin/org/sayandev/stickynote/core/database/sqlite/SQLiteDatabase.kt @@ -5,7 +5,7 @@ import java.io.File import java.util.concurrent.CompletableFuture import java.util.logging.Logger -class SQLiteDatabase(dbFile: File, logger: Logger) : SQLiteExecutor(dbFile, logger) { +class SQLiteDatabase(dbFile: File, logger: Logger, maxConnectionPool: Int = 5) : SQLiteExecutor(dbFile, logger, maxConnectionPool) { override fun connect() { super.connect() startQueue() @@ -23,10 +23,6 @@ class SQLiteDatabase(dbFile: File, logger: Logger) : SQLiteExecutor(dbFile, logg return future } - override fun shutdown() { - connection?.close() - } - private fun startQueue() { Thread { while (!isQueueEmpty) { @@ -43,4 +39,4 @@ class SQLiteDatabase(dbFile: File, logger: Logger) : SQLiteExecutor(dbFile, logg override fun onQueryRemoveDueToFail(query: Query) { //ignored } -} +} \ No newline at end of file diff --git a/stickynote-core/src/main/kotlin/org/sayandev/stickynote/core/database/sqlite/SQLiteExecutor.kt b/stickynote-core/src/main/kotlin/org/sayandev/stickynote/core/database/sqlite/SQLiteExecutor.kt index 0e16bcb5..df26b002 100644 --- a/stickynote-core/src/main/kotlin/org/sayandev/stickynote/core/database/sqlite/SQLiteExecutor.kt +++ b/stickynote-core/src/main/kotlin/org/sayandev/stickynote/core/database/sqlite/SQLiteExecutor.kt @@ -1,5 +1,7 @@ package org.sayandev.stickynote.core.database.sqlite +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource import org.sayandev.stickynote.core.database.Database import org.sayandev.stickynote.core.database.Priority import org.sayandev.stickynote.core.database.Query @@ -7,14 +9,15 @@ import org.sayandev.stickynote.core.database.QueryResult import java.io.File import java.io.IOException import java.sql.Connection -import java.sql.DriverManager import java.sql.ResultSet import java.sql.SQLException +import java.util.concurrent.TimeUnit import java.util.logging.Logger -abstract class SQLiteExecutor protected constructor(protected val dbFile: File, private val logger: Logger) : Database() { +abstract class SQLiteExecutor protected constructor(protected val dbFile: File, private val logger: Logger, val maxConnectionPool: Int = 5) : Database() { - protected var connection: Connection? = null + private var dataSource: HikariDataSource? = null + protected val connectionTimeout = TimeUnit.SECONDS.toMillis(30) init { try { @@ -30,13 +33,53 @@ abstract class SQLiteExecutor protected constructor(protected val dbFile: File, override fun connect() { try { - Class.forName("org.sqlite.JDBC") - if (this.connection == null) { - this.connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.path) + if (dataSource == null) { + val config = HikariConfig() + config.jdbcUrl = "jdbc:sqlite:${dbFile.path}" + config.driverClassName = "org.sqlite.JDBC" + config.connectionTimeout = connectionTimeout + config.idleTimeout = 5000 + config.maxLifetime = 1800000 + config.maximumPoolSize = maxConnectionPool + config.minimumIdle = 1 + config.poolName = "stickynote-sqlite-pool" + + config.addDataSourceProperty("socketTimeout", TimeUnit.SECONDS.toMillis(30).toString()) + config.addDataSourceProperty("cachePrepStmts", "true") + config.addDataSourceProperty("prepStmtCacheSize", "250") + config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048") + config.addDataSourceProperty("useServerPrepStmts", "true") + config.addDataSourceProperty("useLocalSessionState", "true") + config.addDataSourceProperty("rewriteBatchedStatements", "true") + config.addDataSourceProperty("cacheResultSetMetadata", "true") + config.addDataSourceProperty("cacheServerConfiguration", "true") + config.addDataSourceProperty("elideSetAutoCommits", "true") + config.addDataSourceProperty("maintainTimeStats", "false") + config.addDataSourceProperty("alwaysSendSetIsolation", "false") + config.addDataSourceProperty("cacheCallableStmts", "true") + config.addDataSourceProperty("allowPublicKeyRetrieval", "true") + config.addDataSourceProperty("characterEncoding", "utf8") + + config.addDataSourceProperty("foreign_keys", "true") + config.addDataSourceProperty("journal_mode", "WAL") + config.addDataSourceProperty("synchronous", "NORMAL") + + dataSource = HikariDataSource(config) + logger.info("Successfully configured SQLite connection pool") } + } catch (e: Exception) { + logger.severe("Failed to create connection pool: ${e.message}") + e.printStackTrace() + } + } + + protected fun getConnection(): Connection? { + return try { + dataSource?.connection } catch (e: SQLException) { - logger.severe(e.message) + logger.severe("Failed to get connection from pool: ${e.message}") e.printStackTrace() + null } } @@ -45,26 +88,31 @@ abstract class SQLiteExecutor protected constructor(protected val dbFile: File, } fun executeQuerySync(query: Query): QueryResult { - try { - val preparedStatement = query.createPreparedStatement(connection) - var resultSet: ResultSet? = null - - if (query.statement.startsWith("INSERT") || - query.statement.startsWith("UPDATE") || - query.statement.startsWith("DELETE") || - query.statement.startsWith("CREATE") || - query.statement.startsWith("ALTER") - ) { - preparedStatement.executeUpdate() - preparedStatement.close() - } - else resultSet = preparedStatement.executeQuery() + val connection = getConnection() ?: return QueryResult(Query.StatusCode.FAILED, null) - if (resultSet != null) { - query.complete(resultSet) + try { + connection.use { conn -> + val preparedStatement = query.createPreparedStatement(conn) + var resultSet: ResultSet? = null + + if (query.statement.startsWith("INSERT") || + query.statement.startsWith("UPDATE") || + query.statement.startsWith("DELETE") || + query.statement.startsWith("CREATE") || + query.statement.startsWith("ALTER") + ) { + preparedStatement.executeUpdate() + preparedStatement.close() + } else { + resultSet = preparedStatement.executeQuery() + } + + if (resultSet != null) { + query.complete(resultSet) + } + + return QueryResult(Query.StatusCode.FINISHED, resultSet) } - - return QueryResult(Query.StatusCode.FINISHED, resultSet) } catch (e: SQLException) { onQueryFail(query) e.printStackTrace() @@ -90,8 +138,11 @@ abstract class SQLiteExecutor protected constructor(protected val dbFile: File, } } + override fun shutdown() { + dataSource?.close() + } + protected abstract fun onQueryFail(query: Query) protected abstract fun onQueryRemoveDueToFail(query: Query) - -} +} \ No newline at end of file diff --git a/stickynote-loader/src/main/kotlin/org/sayandev/plugin/StickyNoteProjectPlugin.kt b/stickynote-loader/src/main/kotlin/org/sayandev/plugin/StickyNoteProjectPlugin.kt index 084745fa..3f71dfef 100644 --- a/stickynote-loader/src/main/kotlin/org/sayandev/plugin/StickyNoteProjectPlugin.kt +++ b/stickynote-loader/src/main/kotlin/org/sayandev/plugin/StickyNoteProjectPlugin.kt @@ -14,7 +14,7 @@ class StickyNoteProjectPlugin : Plugin { * Exclude dependency from relocations. should be the same in StickyNoteLoader * @see org.sayandev.loader.common.StickyNoteLoader * */ - val relocateExclusion = setOf("kotlin-stdlib", "kotlin-reflect", "kotlin", "kotlin-stdlib-jdk8", "kotlin-stdlib-jdk7", /*"kotlinx", "kotlinx-coroutines", "kotlinx-coroutines-core-jvm",*/ "takenaka", "mappings", "gson") + val relocateExclusion = setOf("kotlin-stdlib", "kotlin-reflect", "kotlin", "kotlin-stdlib-jdk8", "kotlin-stdlib-jdk7", "kotlinx", "kotlinx-coroutines", "kotlinx-coroutines-core-jvm", "takenaka", "mappings", "gson") @KotlinPoetJavaPoetPreview override fun apply(target: Project) { @@ -115,7 +115,8 @@ class StickyNoteProjectPlugin : Plugin { relocate("org.sayandev.loader", "${target.rootProject.group}.${target.rootProject.name.lowercase()}.lib.loader") relocate("org.sayandev.stickynote", "${target.rootProject.group}.${target.rootProject.name.lowercase()}.lib.stickynote") relocate("com.mysql", "${target.rootProject.group}.${target.rootProject.name.lowercase()}.lib.mysql") - relocate("kotlinx.coroutines", "${target.rootProject.group}.${target.rootProject.name.lowercase()}.lib.kotlinx.coroutines") + relocate("org.jetbrains.exposed", "${target.rootProject.group}.${target.rootProject.name.lowercase()}.lib.exposed") +// relocate("kotlinx.coroutines", "${target.rootProject.group}.${target.rootProject.name.lowercase()}.lib.kotlinx.coroutines") // relocate("com.github.benmanes.caffeine", "${target.rootProject.group}.${target.rootProject.name.lowercase()}.lib.caffeine") for (bundleAlias in libs.bundleAliases.filter { config.modules.get().map { "implementation.".plus(it.type.artifact.removePrefix("stickynote-").replace("-", ".")) }.contains(it) }) { val bundle = libs.findBundle(bundleAlias).get().get() diff --git a/stickynote-loader/stickynote-loader-common/src/main/java/org/sayandev/loader/common/StickyNoteLoader.java b/stickynote-loader/stickynote-loader-common/src/main/java/org/sayandev/loader/common/StickyNoteLoader.java index 6e9c5b0e..bf88bb3d 100644 --- a/stickynote-loader/stickynote-loader-common/src/main/java/org/sayandev/loader/common/StickyNoteLoader.java +++ b/stickynote-loader/stickynote-loader-common/src/main/java/org/sayandev/loader/common/StickyNoteLoader.java @@ -6,12 +6,8 @@ import com.alessiodp.libby.transitive.ExcludedDependency; import com.alessiodp.libby.transitive.TransitiveDependencyHelper; -import javax.swing.text.html.parser.Entity; import java.io.*; import java.nio.file.FileSystemException; -import java.nio.file.FileVisitOption; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.*; import java.util.concurrent.*; import java.util.logging.Logger; @@ -23,7 +19,7 @@ public abstract class StickyNoteLoader { private static final ConcurrentHashMap> loadingLibraries = new ConcurrentHashMap<>(); private static final ExecutorService executorService = Executors.newWorkStealingPool(Runtime.getRuntime().availableProcessors()); private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - public static final List exclusions = Arrays.asList("kotlin-stdlib", "kotlin-reflect", "kotlin", "kotlin-stdlib-jdk8", "kotlin-stdlib-jdk7"/*, "kotlinx", "kotlinx-coroutines", "kotlinx-coroutines-core-jvm"*/, "takenaka", "mappings", "gson"); + public static final List exclusions = Arrays.asList("kotlin-stdlib", "kotlin-reflect", "kotlin", "kotlin-stdlib-jdk8", "kotlin-stdlib-jdk7", "kotlinx", "kotlinx-coroutines", "kotlinx-coroutines-core-jvm", "takenaka", "mappings", "gson"); public static final Map relocations = new HashMap<>(); // name - group @@ -278,7 +274,7 @@ private Library.Builder createLibraryBuilder(Dependency dependency) { .artifactId(dependency.getName()) .version(dependency.getVersion()) .resolveTransitiveDependencies(false); - + if (relocate) { if (dependency.getRelocation() != null || !dependency.isStickyLoad()) { for (Map.Entry relocation : relocations.entrySet()) { @@ -310,7 +306,7 @@ private List resolveTransitiveLibraries(String id, TransitiveDependency } return transitiveDependencies; } - + private String getLatestVersion(List versions) { if (versions == null || versions.isEmpty()) { return null;