Skip to content

Commit 3203ba4

Browse files
authored
Merge pull request #152 from FOCONIS/migration-context
Introduce MigrationContext to be prepared for JDBC migration refactor
2 parents bce84e0 + 769b0c1 commit 3203ba4

File tree

11 files changed

+184
-62
lines changed

11 files changed

+184
-62
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.ebean.migration;
2+
3+
import java.sql.Connection;
4+
5+
/**
6+
* The current context while a migration runs.
7+
* <p>
8+
* This is used to provide meta-informations in JDBC migrations and mainly provides a read-only access
9+
* to a subset of MigrationConfig.
10+
* <p>
11+
* It is possible to provide an extended implementation in <code>MigrationEngine.run(context)</code>,
12+
* which is accessible in JdbcMigration. So you can create a EbeanMigrationContext, so that you can
13+
* access the current ebean server in the JDBC migration.
14+
*
15+
* @author Roland Praml, FOCONIS AG
16+
*/
17+
public interface MigrationContext {
18+
/**
19+
* The current connection. Note: During migration, this connection is always the same.
20+
* You must not close this connection!
21+
*/
22+
Connection connection();
23+
24+
/**
25+
* The migration path of SQL migrations. You can use this, to load additional SQL resources
26+
* in your JDBC migration or determine, if this JDBC migration is for a particular path.
27+
* This can be used if you have multiple ebean servers for different databases.
28+
*/
29+
String migrationPath();
30+
31+
/**
32+
* The platform of the current migration run. (e.g. <code>sqlserver17</code>)
33+
*/
34+
String platform();
35+
36+
/**
37+
* The base platform of the current migration run. (e.g. <code>sqlserver</code>)
38+
*/
39+
String basePlatform();
40+
41+
}

ebean-migration/src/main/java/io/ebean/migration/MigrationRunner.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ public List<MigrationResource> checkState(Connection connection) {
4444
return run(connection, true);
4545
}
4646

47+
/**
48+
* Return the migrations that would be applied if the migration is run.
49+
*/
50+
public List<MigrationResource> checkState(MigrationContext context) {
51+
return run(context, true);
52+
}
53+
4754
/**
4855
* Run by creating a DB connection from driver, url, username defined in MigrationConfig.
4956
*/
@@ -65,6 +72,13 @@ public void run(Connection connection) {
6572
run(connection, false);
6673
}
6774

75+
/**
76+
* Run the migrations if there are any that need running.
77+
*/
78+
public void run(MigrationContext context) {
79+
run(context, false);
80+
}
81+
6882
private Connection connection(DataSource dataSource) {
6983
String username = migrationConfig.getDbUsername();
7084
try {
@@ -86,4 +100,10 @@ private List<MigrationResource> run(Connection connection, boolean checkStateOnl
86100
return new MigrationEngine(migrationConfig, checkStateOnly).run(connection);
87101
}
88102

103+
/**
104+
* Run the migrations if there are any that need running.
105+
*/
106+
private List<MigrationResource> run(MigrationContext context, boolean checkStateOnly) {
107+
return new MigrationEngine(migrationConfig, checkStateOnly).run(context);
108+
}
89109
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package io.ebean.migration.runner;
2+
3+
import io.ebean.migration.MigrationConfig;
4+
import io.ebean.migration.MigrationContext;
5+
6+
import java.sql.Connection;
7+
8+
/**
9+
* A default implementation of the MigrationContext.
10+
*
11+
* @author Roland Praml, FOCONIS AG
12+
*/
13+
public class DefaultMigrationContext implements MigrationContext {
14+
private final Connection connection;
15+
private final String migrationPath;
16+
private final String platform;
17+
private final String basePlatform;
18+
19+
public DefaultMigrationContext(MigrationConfig config, Connection connection) {
20+
this.connection = connection;
21+
this.migrationPath = config.getMigrationPath();
22+
this.platform = config.getPlatform();
23+
this.basePlatform = config.getBasePlatform();
24+
}
25+
26+
@Override
27+
public Connection connection() {
28+
return connection;
29+
}
30+
31+
@Override
32+
public String migrationPath() {
33+
return migrationPath;
34+
}
35+
36+
@Override
37+
public String platform() {
38+
return platform;
39+
}
40+
41+
@Override
42+
public String basePlatform() {
43+
return basePlatform;
44+
}
45+
}

ebean-migration/src/main/java/io/ebean/migration/runner/FirstCheck.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.ebean.migration.runner;
22

33
import io.ebean.migration.MigrationConfig;
4+
import io.ebean.migration.MigrationContext;
45

56
import java.sql.Connection;
67
import java.sql.SQLException;
@@ -15,17 +16,17 @@ final class FirstCheck {
1516

1617
final MigrationConfig config;
1718
final MigrationPlatform platform;
18-
final Connection connection;
19+
final MigrationContext context;
1920
final String schema;
2021
final String table;
2122
final String sqlTable;
2223
boolean tableKnownToExist;
2324
private int count;
2425

25-
FirstCheck(MigrationConfig config, Connection connection, MigrationPlatform platform) {
26+
FirstCheck(MigrationConfig config, MigrationContext context, MigrationPlatform platform) {
2627
this.config = config;
2728
this.platform = platform;
28-
this.connection = connection;
29+
this.context = context;
2930
this.schema = config.getDbSchema();
3031
this.table = config.getMetaTable();
3132
this.sqlTable = schema != null ? schema + '.' + table : table;
@@ -80,7 +81,7 @@ private int checksumFor(LocalMigrationResource local) {
8081
}
8182

8283
List<MigrationMetaRow> fastRead() throws SQLException {
83-
return platform.fastReadMigrations(sqlTable, connection);
84+
return platform.fastReadMigrations(sqlTable, context.connection());
8485
}
8586

8687
int count() {

ebean-migration/src/main/java/io/ebean/migration/runner/MigrationEngine.java

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.avaje.applog.AppLog;
44
import io.ebean.migration.MigrationConfig;
5+
import io.ebean.migration.MigrationContext;
56
import io.ebean.migration.MigrationException;
67
import io.ebean.migration.MigrationResource;
78

@@ -35,51 +36,63 @@ public MigrationEngine(MigrationConfig migrationConfig, boolean checkStateOnly)
3536

3637
/**
3738
* Run the migrations if there are any that need running.
39+
*
40+
* @param connection the connection to run on. Note the connection will be closed.
3841
*/
3942
public List<MigrationResource> run(Connection connection) {
4043
try {
41-
long startMs = System.currentTimeMillis();
42-
LocalMigrationResources resources = new LocalMigrationResources(migrationConfig);
43-
if (!resources.readResources() && !resources.readInitResources()) {
44-
log.log(DEBUG, "no migrations to check");
45-
return emptyList();
46-
}
47-
long splitMs = System.currentTimeMillis() - startMs;
48-
final var platform = derivePlatform(migrationConfig, connection);
49-
final var firstCheck = new FirstCheck(migrationConfig, connection, platform);
50-
if (fastMode && firstCheck.fastModeCheck(resources.versions())) {
51-
long checkMs = System.currentTimeMillis() - startMs;
52-
log.log(INFO, "DB migrations completed in {0}ms - totalMigrations:{1} readResources:{2}ms", checkMs, firstCheck.count(), splitMs);
53-
return emptyList();
54-
}
55-
// ensure running with autoCommit false
56-
setAutoCommitFalse(connection);
57-
58-
final MigrationTable table = initialiseMigrationTable(firstCheck, connection);
59-
try {
60-
List<MigrationResource> result = runMigrations(table, resources.versions());
61-
connection.commit();
62-
if (!checkStateOnly) {
63-
long commitMs = System.currentTimeMillis();
64-
log.log(INFO, "DB migrations completed in {0}ms - executed:{1} totalMigrations:{2} mode:{3}", (commitMs - startMs), table.count(), table.size(), table.mode());
65-
int countNonTransactional = table.runNonTransactional();
66-
if (countNonTransactional > 0) {
67-
log.log(INFO, "Non-transactional DB migrations completed in {0}ms - executed:{1}", (System.currentTimeMillis() - commitMs), countNonTransactional);
68-
}
44+
return run(new DefaultMigrationContext(migrationConfig, connection));
45+
} finally {
46+
close(connection);
47+
}
48+
}
49+
50+
/**
51+
* Run the migrations if there are any that need running. (Does not close connection)
52+
*/
53+
public List<MigrationResource> run(MigrationContext context) {
54+
55+
long startMs = System.currentTimeMillis();
56+
LocalMigrationResources resources = new LocalMigrationResources(migrationConfig);
57+
if (!resources.readResources() && !resources.readInitResources()) {
58+
log.log(DEBUG, "no migrations to check");
59+
return emptyList();
60+
}
61+
62+
var connection = context.connection();
63+
long splitMs = System.currentTimeMillis() - startMs;
64+
final var platform = derivePlatform(migrationConfig, connection);
65+
final var firstCheck = new FirstCheck(migrationConfig, context, platform);
66+
if (fastMode && firstCheck.fastModeCheck(resources.versions())) {
67+
long checkMs = System.currentTimeMillis() - startMs;
68+
log.log(INFO, "DB migrations completed in {0}ms - totalMigrations:{1} readResources:{2}ms", checkMs, firstCheck.count(), splitMs);
69+
return emptyList();
70+
}
71+
// ensure running with autoCommit false
72+
setAutoCommitFalse(connection);
73+
74+
final MigrationTable table = initialiseMigrationTable(firstCheck, connection);
75+
try {
76+
List<MigrationResource> result = runMigrations(table, resources.versions());
77+
connection.commit();
78+
if (!checkStateOnly) {
79+
long commitMs = System.currentTimeMillis();
80+
log.log(INFO, "DB migrations completed in {0}ms - executed:{1} totalMigrations:{2} mode:{3}", (commitMs - startMs), table.count(), table.size(), table.mode());
81+
int countNonTransactional = table.runNonTransactional();
82+
if (countNonTransactional > 0) {
83+
log.log(INFO, "Non-transactional DB migrations completed in {0}ms - executed:{1}", (System.currentTimeMillis() - commitMs), countNonTransactional);
6984
}
70-
return result;
71-
} catch (MigrationException e) {
72-
rollback(connection);
73-
throw e;
74-
} catch (Throwable e) {
75-
log.log(ERROR, "Perform rollback due to DB migration error", e);
76-
rollback(connection);
77-
throw new MigrationException("Error running DB migrations", e);
78-
} finally {
79-
table.unlockMigrationTable();
8085
}
86+
return result;
87+
} catch (MigrationException e) {
88+
rollback(connection);
89+
throw e;
90+
} catch (Throwable e) {
91+
log.log(ERROR, "Perform rollback due to DB migration error", e);
92+
rollback(connection);
93+
throw new MigrationException("Error running DB migrations", e);
8194
} finally {
82-
close(connection);
95+
table.unlockMigrationTable();
8396
}
8497
}
8598

0 commit comments

Comments
 (0)