Skip to content

Commit

Permalink
[PLAT-15274]: BackFill Pitr params for DR config and add not-null con…
Browse files Browse the repository at this point in the history
…straints in DB.

Summary:
Backfill pitr params for DR config from universe/global runtime config entry and if not found default to reference.conf values.
Also, added not null constraints on them.

Test Plan: Tested manually by migrating dr config where in one case universe had runtime_config entry and in other case it didn't.

Reviewers: hzare, #yba-api-review!, sanketh, cwang

Reviewed By: hzare

Subscribers: yugaware

Differential Revision: https://phorge.dev.yugabyte.com/D37986
  • Loading branch information
vipul-yb committed Sep 12, 2024
1 parent e72ae64 commit 8796c83
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 0 deletions.
67 changes: 67 additions & 0 deletions managed/src/main/java/com/yugabyte/yw/models/migrations/V376.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) YugaByte, Inc.

package com.yugabyte.yw.models.migrations;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.ebean.Finder;
import io.ebean.Model;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import java.util.List;
import java.util.UUID;
import lombok.Data;

public class V376 {

@Entity
@Data
public static class DrConfig extends Model {

public static final Finder<UUID, DrConfig> find = new Finder<UUID, DrConfig>(DrConfig.class) {};

@Id private UUID uuid;

@OneToMany(mappedBy = "drConfig", cascade = CascadeType.ALL)
@JsonIgnore
private List<XClusterConfig> xClusterConfigs;

@ManyToOne
@JoinColumn(name = "storage_config_uuid", referencedColumnName = "config_uuid")
@JsonIgnore
private UUID storageConfigUuid;

private Long pitrRetentionPeriodSec;

private Long pitrSnapshotIntervalSec;

public static List<DrConfig> getAll() {
return find.query().where().findList();
}
}

@Entity
@Data
public static class XClusterConfig extends Model {

@Id private UUID uuid;

@ManyToOne
@JoinColumn(name = "source_universe_uuid", referencedColumnName = "universe_uuid")
private UUID sourceUniverseUUID;

@ManyToOne
@JoinColumn(name = "target_universe_uuid", referencedColumnName = "universe_uuid")
private UUID targetUniverseUUID;

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumn(name = "dr_config_uuid", referencedColumnName = "uuid")
@JsonIgnore
private DrConfig drConfig;

private boolean secondary;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright (c) YugaByte, Inc.

package db.migration.default_.common;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.yugabyte.yw.models.migrations.V376.DrConfig;
import com.yugabyte.yw.models.migrations.V376.XClusterConfig;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;

@Slf4j
public class V376__Add_DR_Config_Constraint extends BaseJavaMigration {

private static final String RETENTION_PERIOD_PATH =
"yb.xcluster.transactional.pitr.default_retention_period";
private static final String SNAPSHOT_INTERVAL_PATH =
"yb.xcluster.transactional.pitr.default_snapshot_interval";
private static final UUID GLOBAL_SCOPE_UUID =
UUID.fromString("00000000-0000-0000-0000-000000000000");

@Override
public void migrate(Context context) throws Exception {
List<DrConfig> drConfigs = DrConfig.getAll();
for (DrConfig drConfig : drConfigs) {
if (drConfig.getPitrRetentionPeriodSec() == null
&& drConfig.getPitrSnapshotIntervalSec() == null) {
UUID targetUniverseUUID = null;
List<XClusterConfig> xClusterConfigs = drConfig.getXClusterConfigs();
if (xClusterConfigs != null && !xClusterConfigs.isEmpty()) {
Optional<XClusterConfig> xClusterConfigResult =
xClusterConfigs.stream()
.filter(xClusterConfig -> !xClusterConfig.isSecondary())
.findFirst();
if (xClusterConfigResult.isPresent()) {
targetUniverseUUID = xClusterConfigResult.get().getTargetUniverseUUID();
}
}
Long pitrRetentionPeriodSec = 259200L;
Long pitrSnapshotIntervalSec = 3600L;
if (targetUniverseUUID != null) {
Connection connection = context.getConnection();

Optional<Long> retentionPeriod =
getPitrParamFromRuntimeConfigEntry(
connection, targetUniverseUUID, RETENTION_PERIOD_PATH);

if (retentionPeriod.isPresent()) {
pitrRetentionPeriodSec = retentionPeriod.get();
}

Optional<Long> snapshotInterval =
getPitrParamFromRuntimeConfigEntry(
connection, targetUniverseUUID, SNAPSHOT_INTERVAL_PATH);
if (snapshotInterval.isPresent()) {
pitrSnapshotIntervalSec = snapshotInterval.get();
}
}
log.info(
"Setting pitr_retention_period_sec to {} and pitr_snapshot_interval_sec to {} on Dr"
+ " Config with UUID {}",
pitrRetentionPeriodSec,
pitrSnapshotIntervalSec,
drConfig.getUuid());
drConfig.setPitrRetentionPeriodSec(pitrRetentionPeriodSec);
drConfig.setPitrSnapshotIntervalSec(pitrSnapshotIntervalSec);
drConfig.save();
}
}

// Add NOT NULL constraint to pitr_retention_period_sec and pitr_snapshot_interval_sec
addNotNullConstraint(context);
}

void addNotNullConstraint(Context context) throws SQLException {
Connection connection = context.getConnection();
connection
.createStatement()
.execute("ALTER TABLE dr_config ALTER COLUMN pitr_retention_period_sec SET NOT NULL");
connection
.createStatement()
.execute("ALTER TABLE dr_config ALTER COLUMN pitr_snapshot_interval_sec SET NOT NULL");
}

Optional<Long> getPitrParamFromRuntimeConfigEntry(
Connection connection, UUID targetUniverseUUID, String path) throws SQLException {
Optional<Long> universeScopeResult =
getRuntimeConfigEntry(connection, path, targetUniverseUUID);
if (universeScopeResult.isPresent()) {
return universeScopeResult;
} else {
// Check on global scope
Optional<Long> globalScopeResult =
getRuntimeConfigEntry(connection, RETENTION_PERIOD_PATH, GLOBAL_SCOPE_UUID);
if (globalScopeResult.isPresent()) {
return globalScopeResult;
}
}
return Optional.empty();
}

Optional<Long> getRuntimeConfigEntry(Connection connection, String path, UUID scopeUuid)
throws SQLException {
String findRetentionQueryString =
String.format(
"SELECT value from runtime_config_entry where path = '%s' and scope_uuid = '%s'",
path, scopeUuid);
ResultSet retentionResultSet =
connection.createStatement().executeQuery(findRetentionQueryString);
if (retentionResultSet.next()) {
String value = new String(retentionResultSet.getBytes("value"));
Config config = ConfigFactory.parseString("key = " + value);
Long result = config.getDuration("key").getSeconds();
return Optional.of(result);
}
return Optional.empty();
}
}

0 comments on commit 8796c83

Please sign in to comment.