Search in sources :

Example 1 with AppliedMigration

use of org.flywaydb.core.internal.schemahistory.AppliedMigration in project flyway by flyway.

the class MigrationInfoServiceImpl method refresh.

/**
 * Refreshes the info about all known migrations from both the classpath and the DB.
 */
public void refresh() {
    Collection<ResolvedMigration> resolvedMigrations = migrationResolver.resolveMigrations(context);
    List<AppliedMigration> appliedMigrations = schemaHistory.allAppliedMigrations();
    MigrationInfoContext context = new MigrationInfoContext();
    context.outOfOrder = outOfOrder;
    context.pending = pending;
    context.missing = missing;
    context.ignored = ignored;
    context.future = future;
    context.ignorePatterns = configuration.getIgnoreMigrationPatterns();
    context.target = target;
    context.cherryPick = cherryPick;
    Map<Pair<MigrationVersion, Boolean>, ResolvedMigration> resolvedVersioned = new TreeMap<>();
    Map<String, ResolvedMigration> resolvedRepeatable = new TreeMap<>();
    ResolvedMigration pendingBaselineMigration = null;
    AppliedMigration appliedBaselineMigration = null;
    // Separate resolved migrations into versioned and repeatable
    for (ResolvedMigration resolvedMigration : resolvedMigrations) {
        MigrationVersion version = resolvedMigration.getVersion();
        if (version != null) {
            if (version.compareTo(context.lastResolved) > 0) {
                context.lastResolved = version;
            }
            if (resolvedMigration.getType().isBaselineMigration() && version.compareTo(context.latestBaselineMigration) > 0) {
            } else {
                // noinspection RedundantConditionalExpression
                resolvedVersioned.put(Pair.of(version, false), resolvedMigration);
            }
        } else {
            resolvedRepeatable.put(resolvedMigration.getDescription(), resolvedMigration);
        }
    }
    // Split applied into version and repeatable, and update state from synthetic migrations
    List<Pair<AppliedMigration, AppliedMigrationAttributes>> appliedVersioned = new ArrayList<>();
    List<Pair<AppliedMigration, AppliedMigrationAttributes>> appliedRepeatable = new ArrayList<>();
    for (AppliedMigration appliedMigration : appliedMigrations) {
        MigrationVersion version = appliedMigration.getVersion();
        if (version == null) {
            appliedRepeatable.add(Pair.of(appliedMigration, new AppliedMigrationAttributes()));
            if (appliedMigration.getType().equals(MigrationType.DELETE) && appliedMigration.isSuccess()) {
                markRepeatableAsDeleted(appliedMigration.getDescription(), appliedRepeatable);
            }
            continue;
        }
        if (appliedMigration.getType() == MigrationType.SCHEMA) {
            context.schema = version;
        }
        if (appliedMigration.getType() == MigrationType.BASELINE) {
            context.baseline = version;
        }
        if (appliedMigration.getType().equals(MigrationType.DELETE) && appliedMigration.isSuccess()) {
            markAsDeleted(version, appliedVersioned);
        }
        appliedVersioned.add(Pair.of(appliedMigration, new AppliedMigrationAttributes()));
    }
    // Update last applied and out of order states
    for (Pair<AppliedMigration, AppliedMigrationAttributes> av : appliedVersioned) {
        AppliedMigration appliedMigration = av.getLeft();
        MigrationVersion version = appliedMigration.getVersion();
        if (version != null) {
            if (version.compareTo(context.lastApplied) > 0) {
                if (av.getLeft().getType() != MigrationType.DELETE && !av.getRight().deleted) {
                    context.lastApplied = version;
                }
            } else {
                av.getRight().outOfOrder = true;
            }
        }
    }
    // Set target
    if (MigrationVersion.CURRENT == target) {
        context.target = context.lastApplied;
    }
    // Identify pending versioned migrations and build output migration info list
    List<MigrationInfoImpl> migrationInfos1 = new ArrayList<>();
    Set<ResolvedMigration> pendingResolvedVersioned = new HashSet<>(resolvedVersioned.values());
    for (Pair<AppliedMigration, AppliedMigrationAttributes> av : appliedVersioned) {
        ResolvedMigration resolvedMigration = resolvedVersioned.get(Pair.of(av.getLeft().getVersion(), av.getLeft().getType().isUndo()));
        // Remove pending migrations
        if (resolvedMigration != null && !av.getRight().deleted && av.getLeft().getType() != MigrationType.DELETE) {
            pendingResolvedVersioned.remove(resolvedMigration);
        }
        // Build final migration info
        migrationInfos1.add(new MigrationInfoImpl(resolvedMigration, av.getLeft(), context, av.getRight().outOfOrder, av.getRight().deleted, av.getRight().undone));
    }
    // Add all pending migrations to output list
    for (ResolvedMigration prv : pendingResolvedVersioned) {
        if (prv.getVersion().compareTo(context.latestBaselineMigration) <= 0) {
            continue;
        }
        migrationInfos1.add(new MigrationInfoImpl(prv, null, context, false, false, false));
    }
    if (pendingBaselineMigration != null) {
        migrationInfos1.add(new MigrationInfoImpl(pendingBaselineMigration, null, context, false, false, false));
    }
    if (configuration.isFailOnMissingTarget() && target != null && target != MigrationVersion.CURRENT && target != MigrationVersion.LATEST && target != MigrationVersion.NEXT) {
        boolean targetFound = false;
        for (MigrationInfoImpl migration : migrationInfos1) {
            if (target.compareTo(migration.getVersion()) == 0) {
                targetFound = true;
                break;
            }
        }
        if (!targetFound) {
            throw new FlywayException("No migration with a target version " + target + " could be found. Ensure target is specified correctly and the migration exists.");
        }
    }
    // Setup the latest repeatable run ranks
    for (Pair<AppliedMigration, AppliedMigrationAttributes> av : appliedRepeatable) {
        if (av.getRight().deleted && av.getLeft().getType() == MigrationType.DELETE) {
            continue;
        }
        AppliedMigration appliedRepeatableMigration = av.getLeft();
        String desc = appliedRepeatableMigration.getDescription();
        int rank = appliedRepeatableMigration.getInstalledRank();
        Map<String, Integer> latestRepeatableRuns = context.latestRepeatableRuns;
        if (!latestRepeatableRuns.containsKey(desc) || (rank > latestRepeatableRuns.get(desc))) {
            latestRepeatableRuns.put(desc, rank);
        }
    }
    // Using latest repeatable runs, discover pending repeatables and build output list
    Set<ResolvedMigration> pendingResolvedRepeatable = new HashSet<>(resolvedRepeatable.values());
    for (Pair<AppliedMigration, AppliedMigrationAttributes> av : appliedRepeatable) {
        AppliedMigration appliedRepeatableMigration = av.getLeft();
        String desc = appliedRepeatableMigration.getDescription();
        int rank = appliedRepeatableMigration.getInstalledRank();
        ResolvedMigration resolvedMigration = resolvedRepeatable.get(desc);
        int latestRank = context.latestRepeatableRuns.get(desc);
        // If latest run is the same rank, its not pending
        if (!av.getRight().deleted && av.getLeft().getType() != MigrationType.DELETE && resolvedMigration != null && rank == latestRank && resolvedMigration.checksumMatches(appliedRepeatableMigration.getChecksum())) {
            pendingResolvedRepeatable.remove(resolvedMigration);
        }
        // Add to output list
        migrationInfos1.add(new MigrationInfoImpl(resolvedMigration, appliedRepeatableMigration, context, false, av.getRight().deleted, false));
    }
    // Add pending repeatables to output list
    for (ResolvedMigration prr : pendingResolvedRepeatable) {
        migrationInfos1.add(new MigrationInfoImpl(prr, null, context, false, false, false));
    }
    // Set output
    Collections.sort(migrationInfos1);
    migrationInfos = migrationInfos1;
    if (context.target == MigrationVersion.NEXT) {
        MigrationInfo[] pendingMigrationInfos = pending();
        if (pendingMigrationInfos.length == 0) {
            context.target = null;
        } else {
            context.target = pendingMigrationInfos[0].getVersion();
        }
    }
}
Also used : Pair(org.flywaydb.core.internal.util.Pair) AppliedMigration(org.flywaydb.core.internal.schemahistory.AppliedMigration) ResolvedMigration(org.flywaydb.core.api.resolver.ResolvedMigration)

Example 2 with AppliedMigration

use of org.flywaydb.core.internal.schemahistory.AppliedMigration in project flyway by flyway.

the class DbBaseline method baseline.

/**
 * Baselines the database.
 */
public BaselineResult baseline() {
    callbackExecutor.onEvent(Event.BEFORE_BASELINE);
    try {
        if (!schemaHistory.exists()) {
            schemaHistory.create(true);
            LOG.info("Successfully baselined schema with version: " + baselineVersion);
            baselineResult.successfullyBaselined = true;
            baselineResult.baselineVersion = baselineVersion.toString();
        } else {
            AppliedMigration baselineMarker = schemaHistory.getBaselineMarker();
            if (baselineMarker != null) {
                if (baselineVersion.equals(baselineMarker.getVersion()) && baselineDescription.equals(baselineMarker.getDescription())) {
                    LOG.info("Schema history table " + schemaHistory + " already initialized with (" + baselineVersion + "," + baselineDescription + "). Skipping.");
                    baselineResult.successfullyBaselined = true;
                    baselineResult.baselineVersion = baselineVersion.toString();
                } else {
                    throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " with (" + baselineVersion + "," + baselineDescription + ") as it has already been baselined with (" + baselineMarker.getVersion() + "," + baselineMarker.getDescription() + ")\n" + "Need to reset your baseline? Learn more: " + FlywayDbWebsiteLinks.RESET_THE_BASELINE_MIGRATION);
                }
            } else {
                if (schemaHistory.hasSchemasMarker() && baselineVersion.equals(MigrationVersion.fromVersion("0"))) {
                    throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " with version 0 as this version was used for schema creation");
                }
                if (schemaHistory.hasNonSyntheticAppliedMigrations()) {
                    throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " as it already contains migrations\n" + "Need to reset your baseline? Learn more: " + FlywayDbWebsiteLinks.RESET_THE_BASELINE_MIGRATION);
                }
                if (schemaHistory.allAppliedMigrations().isEmpty()) {
                    throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " as it already exists, and is empty.\n" + "Delete the schema history table with the clean command, and run baseline again.");
                }
                throw new FlywayException("Unable to baseline schema history table " + schemaHistory + " as it already contains migrations.\n" + "Delete the schema history table with the clean command, and run baseline again.\n" + "Need to reset your baseline? Learn more: " + FlywayDbWebsiteLinks.RESET_THE_BASELINE_MIGRATION);
            }
        }
    } catch (FlywayException e) {
        callbackExecutor.onEvent(Event.AFTER_BASELINE_ERROR);
        baselineResult.successfullyBaselined = false;
        throw e;
    }
    callbackExecutor.onEvent(Event.AFTER_BASELINE);
    return baselineResult;
}
Also used : FlywayException(org.flywaydb.core.api.FlywayException) AppliedMigration(org.flywaydb.core.internal.schemahistory.AppliedMigration)

Example 3 with AppliedMigration

use of org.flywaydb.core.internal.schemahistory.AppliedMigration in project flyway by flyway.

the class DbRepair method alignAppliedMigrationsWithResolvedMigrations.

private boolean alignAppliedMigrationsWithResolvedMigrations() {
    boolean repaired = false;
    for (MigrationInfo migrationInfo : migrationInfoService.all()) {
        MigrationInfoImpl migrationInfoImpl = (MigrationInfoImpl) migrationInfo;
        ResolvedMigration resolved = migrationInfoImpl.getResolvedMigration();
        AppliedMigration applied = migrationInfoImpl.getAppliedMigration();
        // Repair versioned
        if (resolved != null && resolved.getVersion() != null && applied != null && !applied.getType().isSynthetic() && migrationInfoImpl.getState() != MigrationState.IGNORED && updateNeeded(resolved, applied)) {
            schemaHistory.update(applied, resolved);
            repaired = true;
            repairResult.migrationsAligned.add(CommandResultFactory.createRepairOutput(migrationInfo));
        }
        // Repair repeatable
        if (resolved != null && resolved.getVersion() == null && applied != null && !applied.getType().isSynthetic() && migrationInfoImpl.getState() != MigrationState.IGNORED && resolved.checksumMatchesWithoutBeingIdentical(applied.getChecksum())) {
            schemaHistory.update(applied, resolved);
            repaired = true;
            repairResult.migrationsAligned.add(CommandResultFactory.createRepairOutput(migrationInfo));
        }
    }
    return repaired;
}
Also used : MigrationInfo(org.flywaydb.core.api.MigrationInfo) MigrationInfoImpl(org.flywaydb.core.internal.info.MigrationInfoImpl) AppliedMigration(org.flywaydb.core.internal.schemahistory.AppliedMigration) ResolvedMigration(org.flywaydb.core.api.resolver.ResolvedMigration)

Example 4 with AppliedMigration

use of org.flywaydb.core.internal.schemahistory.AppliedMigration in project flyway by flyway.

the class DbRepair method deleteMissingMigrations.

private boolean deleteMissingMigrations() {
    boolean removed = false;
    for (MigrationInfo migrationInfo : migrationInfoService.all()) {
        MigrationInfoImpl migrationInfoImpl = (MigrationInfoImpl) migrationInfo;
        if (migrationInfo.getType().isSynthetic()) {
            continue;
        }
        AppliedMigration applied = migrationInfoImpl.getAppliedMigration();
        MigrationState state = migrationInfoImpl.getState();
        boolean isMigrationMissing = state == MigrationState.MISSING_SUCCESS || state == MigrationState.MISSING_FAILED || state == MigrationState.FUTURE_SUCCESS || state == MigrationState.FUTURE_FAILED;
        boolean isMigrationIgnored = Arrays.stream(configuration.getIgnoreMigrationPatterns()).anyMatch(p -> p.matchesMigration(migrationInfoImpl.getVersion() != null, state));
        if (isMigrationMissing && !isMigrationIgnored) {
            schemaHistory.delete(applied);
            removed = true;
            repairResult.migrationsDeleted.add(CommandResultFactory.createRepairOutput(migrationInfo));
        }
    }
    return removed;
}
Also used : MigrationInfo(org.flywaydb.core.api.MigrationInfo) MigrationInfoImpl(org.flywaydb.core.internal.info.MigrationInfoImpl) MigrationState(org.flywaydb.core.api.MigrationState) AppliedMigration(org.flywaydb.core.internal.schemahistory.AppliedMigration)

Aggregations

AppliedMigration (org.flywaydb.core.internal.schemahistory.AppliedMigration)4 MigrationInfo (org.flywaydb.core.api.MigrationInfo)2 ResolvedMigration (org.flywaydb.core.api.resolver.ResolvedMigration)2 MigrationInfoImpl (org.flywaydb.core.internal.info.MigrationInfoImpl)2 FlywayException (org.flywaydb.core.api.FlywayException)1 MigrationState (org.flywaydb.core.api.MigrationState)1 Pair (org.flywaydb.core.internal.util.Pair)1