Update H2

This commit is contained in:
Syer10
2026-05-11 19:20:06 -04:00
parent 57c0a85a35
commit fe6dd05411
4 changed files with 179 additions and 4 deletions

View File

@@ -70,11 +70,11 @@ exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "e
exposed-javatime = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" }
exposed-kotlintime = { module = "org.jetbrains.exposed:exposed-kotlin-datetime", version.ref = "exposed" }
postgres = "org.postgresql:postgresql:42.7.11"
h2 = "com.h2database:h2:1.4.200" # current database driver, can't update to h2 v2 without sql migration
h2 = "com.h2database:h2:2.4.240"
hikaricp = "com.zaxxer:HikariCP:7.0.2"
# Exposed Migrations
exposed-migrations = "com.github.Suwayomi:exposed-migrations:3.10.0"
exposed-migrations = "com.github.Suwayomi:exposed-migrations:3.10.1"
# Dependency Injection
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }

View File

@@ -4,6 +4,7 @@ import android.app.Application
import android.content.Context
import io.github.oshai.kotlinlogging.KotlinLogging
import suwayomi.tachidesk.manga.impl.update.IUpdater
import suwayomi.tachidesk.server.database.H2Migration
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File
@@ -74,6 +75,14 @@ private fun migrateMangaDownloadDir(applicationDirs: ApplicationDirs) {
}
}
fun migrateDatabaseToV24240(applicationDirs: ApplicationDirs) {
H2Migration.migrate(
applicationDirs.dataRoot,
"1.4.200",
"2.4.240",
)
}
private val MIGRATIONS =
listOf<Pair<String, (ApplicationDirs) -> Unit>>(
"InitialMigration" to { applicationDirs ->
@@ -83,6 +92,9 @@ private val MIGRATIONS =
"FixGlobalUpdateScheduling" to {
Injekt.get<IUpdater>().deleteLastAutomatedUpdateTimestamp()
},
"MigrateDatabaseToV2.4.240" to { applicationDirs ->
migrateDatabaseToV24240(applicationDirs)
},
)
fun runMigrations(applicationDirs: ApplicationDirs) {

View File

@@ -391,6 +391,8 @@ fun applicationSetup() {
"Localization service initialized. Supported languages: ${LocalizationHelper.getSupportedLocales()}"
}
runMigrations(applicationDirs)
databaseUp()
LocalSource.register()
@@ -440,8 +442,6 @@ fun applicationSetup() {
ignoreInitialValue = false,
)
runMigrations(applicationDirs)
setLogLevelFor("org.eclipse.jetty", Level.OFF)
setLogLevelFor("com.zaxxer.hikari", Level.WARN)

View File

@@ -0,0 +1,163 @@
package suwayomi.tachidesk.server.database
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.NetworkHelper
import io.github.oshai.kotlinlogging.KotlinLogging
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.net.URLClassLoader
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.copyTo
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteExisting
import kotlin.io.path.div
import kotlin.io.path.exists
import kotlin.io.path.name
import kotlin.io.path.notExists
import kotlin.io.path.outputStream
object H2Migration {
private val logger = KotlinLogging.logger {}
private val client by lazy {
Injekt.get<NetworkHelper>().client
}
private const val TOOL_VERSION = "1.8"
private const val TOOL_URL =
"https://manticore-projects.com/download/H2MigrationTool-$TOOL_VERSION/H2MigrationTool-$TOOL_VERSION-all.jar"
private const val MAVEN_BASE =
"https://repo1.maven.org/maven2/com/h2database/h2"
fun migrate(
rootDir: String,
h2Old: String,
h2New: String,
) {
val dbBase = "$rootDir/database"
val mvStore = Path("$dbBase.mv.db")
if (mvStore.notExists()) {
logger.info { "No H2 database found. Skipping migration." }
return
}
val script = Path("$dbBase.${h2Old.substringAfterLast('.')}.sql")
// Backup original database.
val backup = Path("$dbBase.mv.db.${h2Old.substringAfterLast('.')}.backup")
mvStore.copyTo(backup, overwrite = true)
logger.info { "Created backup: ${backup.absolutePathString()}" }
val toolsDir = Path(rootDir) / "bin" / "h2-migration-tools"
val libsDir = toolsDir / "h2libs"
libsDir.createDirectories()
// Download migration tool
val migrationJar =
toolsDir.resolve("H2MigrationTool-$TOOL_VERSION-all.jar")
downloadIfNeeded(
TOOL_URL,
migrationJar,
)
downloadIfNeeded(
"$MAVEN_BASE/$h2Old/h2-$h2Old.jar",
libsDir.resolve("h2-$h2Old.bin"),
)
downloadIfNeeded(
"$MAVEN_BASE/$h2New/h2-$h2New.jar",
libsDir.resolve("h2-$h2New.bin"),
)
runMigrationTool(
migrationJar = migrationJar,
libsDir = libsDir,
mvStore = mvStore,
script = script,
)
// Move database to proper path
val newDatabase = Path(rootDir, "database.${h2New.substringAfterLast('.')}.mv.db")
newDatabase.copyTo(mvStore, overwrite = true)
newDatabase.deleteExisting()
logger.info { "H2 migration completed successfully." }
}
private fun downloadIfNeeded(
url: String,
output: Path,
) {
if (output.exists()) {
logger.debug { "Already downloaded: ${output.name}" }
return
}
client
.newCall(GET(url))
.execute()
.use { response ->
if (!response.isSuccessful) {
throw RuntimeException(
"Failed to download $url " +
"(HTTP ${response.code})",
)
}
output.outputStream().use { out ->
response.body.byteStream().copyTo(out)
}
}
logger.info { "Saved: ${output.absolutePathString()}" }
}
private fun runMigrationTool(
migrationJar: Path,
libsDir: Path,
mvStore: Path,
script: Path,
) {
URLClassLoader(
arrayOf(migrationJar.toUri().toURL()),
javaClass.classLoader,
).use { classLoader ->
val clazz =
classLoader.loadClass("com.manticore.h2.H2MigrationTool")
val main =
clazz.getMethod("main", Array<String>::class.java)
main.invoke(
null,
arrayOf(
// h2 driver dir
"-l",
libsDir.absolutePathString(),
// from version
"-f",
"1.4.200",
// to version
"-t",
"2.4.240",
// user
"-u",
"",
// password
"-p",
"",
// database.mv.db
"-d",
mvStore.absolutePathString(),
// database backup in SQL
"-s",
script.absolutePathString(),
),
)
}
}
}