mirror of
https://github.com/corda/corda.git
synced 2025-02-21 01:42:24 +00:00
ENT-8983 Upgrade H2 and liquibase to latest version (#7298)
This commit is contained in:
parent
c777e77962
commit
1a0d354903
@ -77,9 +77,9 @@ mockitoKotlinVersion=1.6.0
|
||||
hamkrestVersion=1.7.0.0
|
||||
joptSimpleVersion=5.0.2
|
||||
jansiVersion=1.18
|
||||
hibernateVersion=5.4.32.Final
|
||||
hibernateVersion=5.6.5.Final
|
||||
# h2Version - Update docs if renamed or removed.
|
||||
h2Version=1.4.199
|
||||
h2Version=2.1.212
|
||||
rxjavaVersion=1.3.8
|
||||
dokkaVersion=0.10.1
|
||||
eddsaVersion=0.3.0
|
||||
@ -88,7 +88,7 @@ commonsCollectionsVersion=4.3
|
||||
beanutilsVersion=1.9.4
|
||||
shiroVersion=1.10.0
|
||||
hikariVersion=3.3.1
|
||||
liquibaseVersion=3.6.3
|
||||
liquibaseVersion=4.18.0
|
||||
dockerComposeRuleVersion=1.5.0
|
||||
seleniumVersion=3.141.59
|
||||
ghostdriverVersion=2.1.0
|
||||
|
BIN
lib/quasar.jar
BIN
lib/quasar.jar
Binary file not shown.
@ -4,9 +4,13 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import liquibase.Contexts
|
||||
import liquibase.LabelExpression
|
||||
import liquibase.Liquibase
|
||||
import liquibase.Scope
|
||||
import liquibase.ThreadLocalScopeManager
|
||||
import liquibase.database.jvm.JdbcConnection
|
||||
import liquibase.exception.LiquibaseException
|
||||
import liquibase.resource.ClassLoaderResourceAccessor
|
||||
import liquibase.resource.Resource
|
||||
import liquibase.resource.URIResource
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.utilities.contextLogger
|
||||
@ -14,8 +18,10 @@ import net.corda.nodeapi.internal.MigrationHelpers.getMigrationResource
|
||||
import net.corda.nodeapi.internal.cordapp.CordappLoader
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.net.URI
|
||||
import java.nio.file.Path
|
||||
import java.sql.Connection
|
||||
import java.util.Collections
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import javax.sql.DataSource
|
||||
import kotlin.concurrent.withLock
|
||||
@ -36,6 +42,10 @@ open class SchemaMigration(
|
||||
const val NODE_BASE_DIR_KEY = "liquibase.nodeDaseDir"
|
||||
const val NODE_X500_NAME = "liquibase.nodeName"
|
||||
val loader = ThreadLocal<CordappLoader>()
|
||||
init {
|
||||
Scope.setScopeManager(ThreadLocalScopeManager())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
protected val mutex = ReentrantLock()
|
||||
}
|
||||
@ -46,31 +56,31 @@ open class SchemaMigration(
|
||||
|
||||
private val classLoader = cordappLoader?.appClassLoader ?: Thread.currentThread().contextClassLoader
|
||||
|
||||
/**
|
||||
/**
|
||||
* Will run the Liquibase migration on the actual database.
|
||||
* @param existingCheckpoints Whether checkpoints exist that would prohibit running a migration
|
||||
* @param schemas The set of MappedSchemas to check
|
||||
* @param forceThrowOnMissingMigration throws an exception if a mapped schema is missing the migration resource. Can be set to false
|
||||
* when allowing hibernate to create missing schemas in dev or tests.
|
||||
* @param existingCheckpoints Whether checkpoints exist that would prohibit running a migration
|
||||
* @param schemas The set of MappedSchemas to check
|
||||
* @param forceThrowOnMissingMigration throws an exception if a mapped schema is missing the migration resource. Can be set to false
|
||||
* when allowing hibernate to create missing schemas in dev or tests.
|
||||
*/
|
||||
fun runMigration(existingCheckpoints: Boolean, schemas: Set<MappedSchema>, forceThrowOnMissingMigration: Boolean) {
|
||||
val resourcesAndSourceInfo = prepareResources(schemas, forceThrowOnMissingMigration)
|
||||
|
||||
// current version of Liquibase appears to be non-threadsafe
|
||||
// this is apparent when multiple in-process nodes are all running migrations simultaneously
|
||||
mutex.withLock {
|
||||
dataSource.connection.use { connection ->
|
||||
val (runner, _, shouldBlockOnCheckpoints) = prepareRunner(connection, resourcesAndSourceInfo)
|
||||
if (shouldBlockOnCheckpoints && existingCheckpoints)
|
||||
throw CheckpointsException()
|
||||
try {
|
||||
runner.update(Contexts().toString())
|
||||
} catch (exp: LiquibaseException) {
|
||||
throw DatabaseMigrationException(exp.message, exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun runMigration(existingCheckpoints: Boolean, schemas: Set<MappedSchema>, forceThrowOnMissingMigration: Boolean) {
|
||||
val resourcesAndSourceInfo = prepareResources(schemas, forceThrowOnMissingMigration)
|
||||
Scope.enter(mapOf(Scope.Attr.classLoader.name to classLoader))
|
||||
// current version of Liquibase appears to be non-threadsafe
|
||||
// this is apparent when multiple in-process nodes are all running migrations simultaneously
|
||||
mutex.withLock {
|
||||
dataSource.connection.use { connection ->
|
||||
val (runner, _, shouldBlockOnCheckpoints) = prepareRunner(connection, resourcesAndSourceInfo)
|
||||
if (shouldBlockOnCheckpoints && existingCheckpoints)
|
||||
throw CheckpointsException()
|
||||
try {
|
||||
runner.update(Contexts().toString())
|
||||
} catch (exp: LiquibaseException) {
|
||||
throw DatabaseMigrationException(exp.message, exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the database is up to date with the latest migration changes.
|
||||
@ -98,7 +108,7 @@ open class SchemaMigration(
|
||||
* @param forceThrowOnMissingMigration throws an exception if a mapped schema is missing the migration resource. Can be set to false
|
||||
* when allowing hibernate to create missing schemas in dev or tests.
|
||||
*/
|
||||
fun getPendingChangesCount(schemas: Set<MappedSchema>, forceThrowOnMissingMigration: Boolean) : Int {
|
||||
fun getPendingChangesCount(schemas: Set<MappedSchema>, forceThrowOnMissingMigration: Boolean): Int {
|
||||
val resourcesAndSourceInfo = prepareResources(schemas, forceThrowOnMissingMigration)
|
||||
|
||||
// current version of Liquibase appears to be non-threadsafe
|
||||
@ -140,19 +150,42 @@ open class SchemaMigration(
|
||||
/** Create a resource accessor that aggregates the changelogs included in the schemas into one dynamic stream. */
|
||||
protected class CustomResourceAccessor(val dynamicInclude: String, val changelogList: List<String?>, classLoader: ClassLoader) :
|
||||
ClassLoaderResourceAccessor(classLoader) {
|
||||
override fun getResourcesAsStream(path: String): Set<InputStream> {
|
||||
override fun getAll(path: String?): List<Resource> {
|
||||
|
||||
if (path == dynamicInclude) {
|
||||
// Create a map in Liquibase format including all migration files.
|
||||
val includeAllFiles = mapOf("databaseChangeLog"
|
||||
to changelogList.filterNotNull().map { file -> mapOf("include" to mapOf("file" to file)) })
|
||||
|
||||
// Transform it to json.
|
||||
val includeAllFilesJson = ObjectMapper().writeValueAsBytes(includeAllFiles)
|
||||
|
||||
// Return the json as a stream.
|
||||
return setOf(ByteArrayInputStream(includeAllFilesJson))
|
||||
val inputStream = getPathAsStream()
|
||||
val resource = object : URIResource(path, URI(path)) {
|
||||
override fun openInputStream(): InputStream {
|
||||
return inputStream
|
||||
}
|
||||
}
|
||||
return Collections.singletonList(resource)
|
||||
}
|
||||
return super.getResourcesAsStream(path)?.take(1)?.toSet() ?: emptySet()
|
||||
// Take 1 resource due to LiquidBase find duplicate files which throws an error
|
||||
return super.getAll(path).take(1)
|
||||
}
|
||||
|
||||
override fun get(path: String?): Resource {
|
||||
if (path == dynamicInclude) {
|
||||
// Return the json as a stream.
|
||||
val inputStream = getPathAsStream()
|
||||
return object : URIResource(path, URI(path)) {
|
||||
override fun openInputStream(): InputStream {
|
||||
return inputStream
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.get(path)
|
||||
}
|
||||
|
||||
private fun getPathAsStream(): InputStream {
|
||||
// Create a map in Liquibase format including all migration files.
|
||||
val includeAllFiles = mapOf("databaseChangeLog"
|
||||
to changelogList.filterNotNull().map { file -> mapOf("include" to mapOf("file" to file)) })
|
||||
val includeAllFilesJson = ObjectMapper().writeValueAsBytes(includeAllFiles)
|
||||
|
||||
return ByteArrayInputStream(includeAllFilesJson)
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,6 +217,7 @@ open class SchemaMigration(
|
||||
if (ourName != null) {
|
||||
System.setProperty(NODE_X500_NAME, ourName.toString())
|
||||
}
|
||||
Scope.enter(mapOf(Scope.Attr.classLoader.name to classLoader))
|
||||
val customResourceAccessor = CustomResourceAccessor(dynamicInclude, changelogList, classLoader)
|
||||
checkResourcesInClassPath(changelogList)
|
||||
return listOf(Pair(customResourceAccessor, ""))
|
||||
|
@ -8,6 +8,7 @@ import liquibase.database.Database
|
||||
import liquibase.database.core.H2Database
|
||||
import liquibase.database.jvm.JdbcConnection
|
||||
import liquibase.resource.ClassLoaderResourceAccessor
|
||||
import liquibase.resource.Resource
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
@ -84,7 +85,9 @@ class IdenityServiceKeyRotationMigrationTest {
|
||||
persist(charlie2.party.dbParty())
|
||||
|
||||
Liquibase("migration/node-core.changelog-v20.xml", object : ClassLoaderResourceAccessor() {
|
||||
override fun getResourcesAsStream(path: String) = super.getResourcesAsStream(path)?.firstOrNull()?.let { setOf(it) }
|
||||
override fun getAll(path: String?): List<Resource> {
|
||||
return super.getAll(path).take(1).toList()
|
||||
}
|
||||
}, liquibaseDB).update(Contexts().toString())
|
||||
|
||||
val dummyKey = Crypto.generateKeyPair().public
|
||||
|
@ -114,7 +114,7 @@ open class MockServices private constructor(
|
||||
}
|
||||
val props = Properties()
|
||||
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
||||
props.setProperty("dataSource.url", "jdbc:h2:file:$dbPath;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
|
||||
props.setProperty("dataSource.url", "jdbc:h2:file:$dbPath;NON_KEYWORDS=KEY,VALUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
|
||||
props.setProperty("dataSource.user", "sa")
|
||||
props.setProperty("dataSource.password", "")
|
||||
return props
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user