Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fb5a55b
[feature](fe) Add routine load target-table alter support
0AyanamiRei Jun 26, 2026
03cf626
[fix](fe) Tighten routine load alter validation
0AyanamiRei Jun 26, 2026
a8bd6be
Merge branch 'master' into feature/routine-load-target-table-switch
0AyanamiRei Jun 29, 2026
9b2cf36
[fix](fe) Fix routine load alter checkstyle issues
0AyanamiRei Jun 29, 2026
760890d
[fix](fe) Refine routine load alter target-table follow-up
0AyanamiRei Jun 29, 2026
931b717
[fix](fe) Align routine load alter partial update mode
0AyanamiRei Jun 29, 2026
48f1b8c
[fix](fe) Fix routine load alter checkstyle line length
0AyanamiRei Jun 29, 2026
0f1be9e
[fix](regression) Fix routine load alter test output checks
0AyanamiRei Jun 29, 2026
4a34f9f
[feature](routine-load) Support composable target table alteration
0AyanamiRei Jul 15, 2026
000c838
[fix](fe) Fix routine load alter review issues
0AyanamiRei Jul 16, 2026
cd0cd0c
Merge branch 'master' into feature/routine-load-target-table-switch
0AyanamiRei Jul 16, 2026
cfb7382
[fix](fe) Restrict routine load target alteration to Kafka
0AyanamiRei Jul 16, 2026
bd1fad5
[fix](fe) Restore Kinesis routine load alter hook
0AyanamiRei Jul 16, 2026
77cb200
Merge branch 'master' into feature/routine-load-target-table-switch
0AyanamiRei Jul 16, 2026
e848c18
[refactor](fe) Simplify routine load target table alteration
0AyanamiRei Jul 17, 2026
8b19f60
[fix](fe) Move routine load ALTER I/O outside metadata locks
0AyanamiRei Jul 17, 2026
e93f300
[fix](fe) Make routine load ALTER state durable
0AyanamiRei Jul 17, 2026
0f81dc7
[improvement](fe) Reduce routine load ALTER lock scope
0AyanamiRei Jul 17, 2026
ba918d0
[fix](fe) Authorize routine load target before metadata lookup
0AyanamiRei Jul 19, 2026
a756d7c
[refactor](fe) Narrow routine load target-table changes
0AyanamiRei Jul 19, 2026
0fca4e7
[test](routineload) Improve target-table alter coverage
0AyanamiRei Jul 23, 2026
04a5e10
[chore](routineload) Resolve master merge conflict
0AyanamiRei Jul 23, 2026
963ed3e
[fix](routineload) Restrict target-table alter to Kafka
0AyanamiRei Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.apache.doris.analysis.Expr;
import org.apache.doris.analysis.ExprToSqlVisitor;
import org.apache.doris.analysis.ImportColumnDesc;
import org.apache.doris.analysis.Separator;
import org.apache.doris.analysis.ToSqlParams;
import org.apache.doris.analysis.UserIdentity;
Expand Down Expand Up @@ -470,6 +471,27 @@ protected void setRoutineLoadDesc(RoutineLoadDesc routineLoadDesc) {
}
}

public void validateTargetTable(Database db, OlapTable targetTable) throws UserException {
if (isMultiTable) {
throw new AnalysisException("ALTER ROUTINE LOAD target table change only supports single-table job");
}
List<ImportColumnDesc> columnsInfo = null;
if (columnDescs != null && !columnDescs.descs.isEmpty()) {
columnsInfo = new ArrayList<>(columnDescs.descs);
}
checkMeta(targetTable, new RoutineLoadDesc(columnSeparator, lineDelimiter, columnsInfo,
precedingFilter, whereExpr, partitionNamesInfo, deleteCondition, mergeType, sequenceCol));

targetTable.readLock();
try {
NereidsStreamLoadPlanner planner = new NereidsStreamLoadPlanner(db, targetTable,
toNereidsRoutineLoadTaskInfo());
planner.plan(new TUniqueId(0, 0));
} finally {
targetTable.readUnlock();
}
}

@Override
public long getId() {
return id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -782,9 +782,12 @@ public void modifyProperties(AlterRoutineLoadCommand command) throws UserExcepti
}

modifyPropertiesInternal(jobProperties, dataSourceProperties);
Comment thread
0AyanamiRei marked this conversation as resolved.
if (command.hasTargetTable()) {
tableId = command.getTargetTableId();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Re-seed progress when a broker-list change selects a different Kafka cluster. With the topic unchanged, modifyPropertiesInternal() only replaces brokerList; it retains progress, custom/current partitions, and the latest-offset cache. Pinned jobs then skip metadata discovery, and a dynamic job whose new cluster has the same numeric partition IDs appears unchanged, so tasks combine the new brokers and target here with offsets from the old cluster. Switching cluster A at offset 1000 to cluster B can therefore skip B's first 1000 records or pause with OFFSET_OUT_OF_RANGE. Resolve the cluster ID and any requested offsets against the effective new brokers outside the job lock; if the cluster changed, require those validated offsets or reset/reseed all progress and partition caches, persist that prepared decision for replay, and recheck the job generation before committing.

Comment thread
0AyanamiRei marked this conversation as resolved.
}

AlterRoutineLoadJobOperationLog log = new AlterRoutineLoadJobOperationLog(this.id,
jobProperties, dataSourceProperties);
jobProperties, dataSourceProperties, command.getTargetTableId());
Env.getCurrentEnv().getEditLog().logAlterRoutineLoadJob(log);
} finally {
writeUnlock();
Expand Down Expand Up @@ -908,6 +911,9 @@ private void resetCloudProgress(Cloud.ResetRLProgressRequest.Builder builder) th
public void replayModifyProperties(AlterRoutineLoadJobOperationLog log) {
try {
modifyPropertiesInternal(log.getJobProperties(), (KafkaDataSourceProperties) log.getDataSourceProperties());
if (log.getTargetTableId() != 0) {
Comment thread
0AyanamiRei marked this conversation as resolved.
tableId = log.getTargetTableId();
}
} catch (UserException e) {
// should not happen
LOG.error("failed to replay modify kafka routine load job: {}", id, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9361,6 +9361,8 @@ public LogicalPlan visitAlterRoutineLoad(DorisParser.AlterRoutineLoadContext ctx
throw new ParseException("only support [<db>.]<job_name>", ctx.name);
}
LabelNameInfo labelNameInfo = new LabelNameInfo(dbName, jobName);
String targetTableName = ctx.targetTable == null
? null : SqlLiteralUtils.parseStringLiteral(ctx.targetTable.getText());

Map<String, String> properties = new HashMap<>();
if (ctx.properties != null) {
Expand All @@ -9387,7 +9389,8 @@ public LogicalPlan visitAlterRoutineLoad(DorisParser.AlterRoutineLoadContext ctx
}
}

return new AlterRoutineLoadCommand(labelNameInfo, loadPropertyMap, properties, dataSourceMapProperties);
return new AlterRoutineLoadCommand(labelNameInfo, targetTableName,
Comment thread
0AyanamiRei marked this conversation as resolved.
loadPropertyMap, properties, dataSourceMapProperties);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,24 @@
import org.apache.doris.catalog.Database;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.catalog.RandomDistributionInfo;
import org.apache.doris.catalog.Table;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.TimeUtils;
import org.apache.doris.common.util.Util;
import org.apache.doris.datasource.InternalCatalog;
import org.apache.doris.datasource.property.fileformat.CsvFileFormatProperties;
import org.apache.doris.datasource.property.fileformat.JsonFileFormatProperties;
import org.apache.doris.load.RoutineLoadDesc;
import org.apache.doris.load.routineload.AbstractDataSourceProperties;
import org.apache.doris.load.routineload.LoadDataSourceType;
import org.apache.doris.load.routineload.RoutineLoadDataSourcePropertyFactory;
import org.apache.doris.load.routineload.RoutineLoadJob;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.commands.info.CreateRoutineLoadInfo;
import org.apache.doris.nereids.trees.plans.commands.info.LabelNameInfo;
Expand All @@ -52,6 +58,7 @@

/**
* ALTER ROUTINE LOAD db.label
* SET TARGET TABLE = "table"
* PROPERTIES(
* ...
* )
Expand Down Expand Up @@ -85,10 +92,12 @@ public class AlterRoutineLoadCommand extends AlterCommand {
.build();

private final LabelNameInfo labelNameInfo;
private final String targetTableName;
private final Map<String, LoadProperty> loadPropertyMap;
private RoutineLoadDesc routineLoadDesc;
private final Map<String, String> jobProperties;
private final Map<String, String> dataSourceMapProperties;
private long targetTableId;
private boolean isPartialUpdate;

// save analyzed job properties.
Expand All @@ -100,6 +109,7 @@ public class AlterRoutineLoadCommand extends AlterCommand {
* AlterRoutineLoadCommand
*/
public AlterRoutineLoadCommand(LabelNameInfo labelNameInfo,
String targetTableName,
Map<String, LoadProperty> loadPropertyMap,
Map<String, String> jobProperties,
Map<String, String> dataSourceMapProperties) {
Expand All @@ -108,6 +118,7 @@ public AlterRoutineLoadCommand(LabelNameInfo labelNameInfo,
Objects.requireNonNull(jobProperties, "jobProperties is null");
Objects.requireNonNull(dataSourceMapProperties, "dataSourceMapProperties is null");
this.labelNameInfo = labelNameInfo;
this.targetTableName = targetTableName;
this.loadPropertyMap = loadPropertyMap == null ? Maps.newHashMap() : loadPropertyMap;
this.jobProperties = jobProperties;
this.dataSourceMapProperties = dataSourceMapProperties;
Expand All @@ -118,7 +129,7 @@ public AlterRoutineLoadCommand(LabelNameInfo labelNameInfo,
public AlterRoutineLoadCommand(LabelNameInfo labelNameInfo,
Map<String, String> jobProperties,
Map<String, String> dataSourceMapProperties) {
this(labelNameInfo, Maps.newHashMap(), jobProperties, dataSourceMapProperties);
this(labelNameInfo, null, Maps.newHashMap(), jobProperties, dataSourceMapProperties);
}

public String getDbName() {
Expand All @@ -133,6 +144,18 @@ public Map<String, String> getAnalyzedJobProperties() {
return analyzedJobProperties;
}

public boolean hasTargetTable() {
return targetTableName != null;
}

public String getTargetTableName() {
return targetTableName;
}

public long getTargetTableId() {
return targetTableId;
}

public boolean hasDataSourceProperty() {
return MapUtils.isNotEmpty(dataSourceMapProperties);
}
Expand Down Expand Up @@ -164,15 +187,21 @@ public void validate(ConnectContext ctx) throws UserException {
// check routine load job properties include desired concurrent number etc.
checkJobProperties();
// check load properties
RoutineLoadJob job = Env.getCurrentEnv().getRoutineLoadManager()
.getJob(getDbName(), getJobName());
this.routineLoadDesc = CreateRoutineLoadInfo.checkLoadProperties(ctx, loadPropertyMap,
job.getDbFullName(), job.getTableName(), job.isMultiTable(), job.getMergeType());
RoutineLoadJob job = hasTargetTable()
? Env.getCurrentEnv().getRoutineLoadManager().checkPrivAndGetJob(getDbName(), getJobName())
: Env.getCurrentEnv().getRoutineLoadManager().getJob(getDbName(), getJobName());
if (MapUtils.isNotEmpty(loadPropertyMap)) {
this.routineLoadDesc = CreateRoutineLoadInfo.checkLoadProperties(ctx, loadPropertyMap,
job.getDbFullName(), job.getTableName(), job.isMultiTable(), job.getMergeType());
Comment thread
0AyanamiRei marked this conversation as resolved.
}
// check data source properties
checkDataSourceProperties();
checkPartialUpdate();
if (hasTargetTable()) {
validateTargetTable(ctx, job);
Comment thread
0AyanamiRei marked this conversation as resolved.
Comment thread
0AyanamiRei marked this conversation as resolved.
}
if (analyzedJobProperties.isEmpty() && MapUtils.isEmpty(dataSourceMapProperties)
&& routineLoadDesc == null) {
&& routineLoadDesc == null && !hasTargetTable()) {
throw new AnalysisException("No properties are specified");
}
}
Expand Down Expand Up @@ -344,6 +373,37 @@ private void checkPartialUpdate() throws UserException {
}
}

private void validateTargetTable(ConnectContext ctx, RoutineLoadJob job) throws UserException {
if (job.getDataSourceType() != LoadDataSourceType.KAFKA) {
throw new AnalysisException("ALTER ROUTINE LOAD target table change only supports Kafka jobs");
}
if (job.isMultiTable()) {
throw new AnalysisException("ALTER ROUTINE LOAD target table change only supports single-table job");
}
String dbFullName = job.getDbFullName();
if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, InternalCatalog.INTERNAL_CATALOG_NAME,
dbFullName, targetTableName, PrivPredicate.LOAD)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, "LOAD",
ctx.getQualifiedUser(), ctx.getRemoteIP(), dbFullName + ": " + targetTableName);
}
Database db = Env.getCurrentInternalCatalog().getDbOrAnalysisException(dbFullName);
Table table = db.getTableOrAnalysisException(targetTableName);
Comment thread
0AyanamiRei marked this conversation as resolved.
if (!(table instanceof OlapTable)) {
throw new AnalysisException("ALTER ROUTINE LOAD target table only supports OLAP table");
}
OlapTable olapTable = (OlapTable) table;
if (olapTable.isTemporary()) {
throw new AnalysisException("Do not support load for temporary table " + olapTable.getDisplayName());
}
if (job.isLoadToSingleTablet()
&& !(olapTable.getDefaultDistributionInfo() instanceof RandomDistributionInfo)) {
throw new AnalysisException(
"if load_to_single_tablet set to true, the olap table must be with random distribution");
}
job.validateTargetTable(db, olapTable);
this.targetTableId = olapTable.getId();
}

@Override
public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
return visitor.visitAlterRoutineLoadCommand(this, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,20 @@ public class AlterRoutineLoadJobOperationLog implements Writable {
private Map<String, String> jobProperties;
@SerializedName(value = "dataSourceProperties")
private AbstractDataSourceProperties dataSourceProperties;
@SerializedName(value = "targetTableId")
private long targetTableId;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Prevent old FE followers from silently dropping the target switch. This field is added to the existing OP_ALTER_ROUTINE_LOAD_JOB JSON record, so an older electable FE recognizes the opcode and replays the known empty job/source delta, while Gson ignores the unknown targetTableId and the old Kafka replay path never changes tableId. During a rolling upgrade, if the old master fails after one upgraded follower rejoins, that new binary can become master while another follower still runs the old binary; after it switches a paused job from A to B, failover to the old follower makes beginTxn and task planning use A's ID and sends the continued stream back to A. The missing-field test covers only old-log -> new-reader compatibility, not this new-writer -> old-reader direction. Gate this ALTER until every electable FE advertises support, or use a versioned record/protocol that an old FE cannot silently accept, and add a mixed-version replay/failover test.


public AlterRoutineLoadJobOperationLog(long jobId, Map<String, String> jobProperties,
AbstractDataSourceProperties dataSourceProperties) {
this(jobId, jobProperties, dataSourceProperties, 0L);
}

public AlterRoutineLoadJobOperationLog(long jobId, Map<String, String> jobProperties,
AbstractDataSourceProperties dataSourceProperties, long targetTableId) {
this.jobId = jobId;
this.jobProperties = jobProperties;
this.dataSourceProperties = dataSourceProperties;
this.targetTableId = targetTableId;
}

public long getJobId() {
Expand All @@ -57,6 +65,10 @@ public AbstractDataSourceProperties getDataSourceProperties() {
return dataSourceProperties;
}

public long getTargetTableId() {
return targetTableId;
}

public static AlterRoutineLoadJobOperationLog read(DataInput in) throws IOException {
String json = Text.readString(in);
return GsonUtils.GSON.fromJson(json, AlterRoutineLoadJobOperationLog.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@
import org.apache.doris.load.routineload.kafka.KafkaRoutineLoadJob;
import org.apache.doris.load.routineload.kafka.KafkaTaskInfo;
import org.apache.doris.mysql.privilege.MockedAuth;
import org.apache.doris.nereids.trees.plans.commands.AlterRoutineLoadCommand;
import org.apache.doris.nereids.trees.plans.commands.info.CreateRoutineLoadInfo;
import org.apache.doris.nereids.trees.plans.commands.info.LabelNameInfo;
import org.apache.doris.nereids.trees.plans.commands.load.LoadProperty;
import org.apache.doris.nereids.trees.plans.commands.load.LoadSeparator;
import org.apache.doris.persist.AlterRoutineLoadJobOperationLog;
import org.apache.doris.persist.EditLog;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.thrift.TResourceInfo;

Expand All @@ -57,6 +60,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

Expand Down Expand Up @@ -237,6 +241,101 @@ public void testUpdateLagRebuildsConvertedPropertiesAfterReplay() throws UserExc
}
}

@Test
public void testModifyTargetTableWithJobAndDataSourceProperties() throws Exception {
KafkaRoutineLoadJob routineLoadJob = new KafkaRoutineLoadJob(1L, "kafka_routine_load_job", 1L,
101L, "127.0.0.1:9020", "topic1", UserIdentity.ADMIN);
Deencapsulation.setField(routineLoadJob, "state", RoutineLoadJob.JobState.PAUSED);
KafkaProgress progress = new KafkaProgress(Maps.newHashMap());
Deencapsulation.setField(routineLoadJob, "progress", progress);

Map<String, String> sourceProperties = Maps.newHashMap();
sourceProperties.put("property.client.id", "target-switch");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve the existing Kafka default in this custom-only combined ALTER. Although this statement supplies only client.id, KafkaDataSourceProperties.analyze() falls through to analyzeKafkaDefaultOffsetProperty(), which synthesizes kafka_default_offsets=OFFSET_END; modifyPropertiesInternal() then merges that value into the live job before assigning and journaling the new target. A job created with OFFSET_BEGINNING can therefore execute the advertised SET TARGET TABLE ... FROM KAFKA("property.client.id"=...) form and silently make every later-discovered partition start at the end, skipping its backlog. This test masks the overwrite because the job starts with the implicit END default and never asserts it. Keep the default absent from an ALTER delta unless it was explicitly supplied (or needed for explicit partitions), and cover live/replay/image preservation from OFFSET_BEGINNING.

KafkaDataSourceProperties dataSourceProperties = new KafkaDataSourceProperties(sourceProperties);
dataSourceProperties.setAlter(true);
dataSourceProperties.setTimezone("UTC");
dataSourceProperties.analyze();

Map<String, String> jobProperties = Maps.newHashMap();
jobProperties.put(CreateRoutineLoadInfo.MAX_ERROR_NUMBER_PROPERTY, "10");
AlterRoutineLoadCommand command = Mockito.mock(AlterRoutineLoadCommand.class);
Mockito.when(command.hasTargetTable()).thenReturn(true);
Mockito.when(command.getTargetTableId()).thenReturn(202L);
Mockito.when(command.getAnalyzedJobProperties()).thenReturn(jobProperties);
Mockito.when(command.getDataSourceProperties()).thenReturn(dataSourceProperties);

Env env = Mockito.mock(Env.class);
EditLog editLog = Mockito.mock(EditLog.class);
Mockito.when(env.getEditLog()).thenReturn(editLog);
try (MockedStatic<Env> envStatic = Mockito.mockStatic(Env.class)) {
envStatic.when(Env::getCurrentEnv).thenReturn(env);
routineLoadJob.modifyProperties(command);
}

Assert.assertEquals(202L, routineLoadJob.getTableId());
Assert.assertSame(progress, routineLoadJob.getProgress());
Assert.assertEquals(10L, ((Long) Deencapsulation.getField(routineLoadJob, "maxErrorNum")).longValue());
Assert.assertEquals("target-switch",
routineLoadJob.getCustomProperties().get("property.client.id"));
ArgumentCaptor<AlterRoutineLoadJobOperationLog> logCaptor =
ArgumentCaptor.forClass(AlterRoutineLoadJobOperationLog.class);
Mockito.verify(editLog).logAlterRoutineLoadJob(logCaptor.capture());
Assert.assertEquals(202L, logCaptor.getValue().getTargetTableId());
}

@Test
public void testModifyTargetTableOnly() throws Exception {
KafkaRoutineLoadJob routineLoadJob = new KafkaRoutineLoadJob(1L, "kafka_routine_load_job", 1L,
101L, "127.0.0.1:9020", "topic1", UserIdentity.ADMIN);
Deencapsulation.setField(routineLoadJob, "state", RoutineLoadJob.JobState.PAUSED);
KafkaProgress progress = new KafkaProgress(Maps.newHashMap());
Deencapsulation.setField(routineLoadJob, "progress", progress);

AlterRoutineLoadCommand command = Mockito.mock(AlterRoutineLoadCommand.class);
Mockito.when(command.hasTargetTable()).thenReturn(true);
Mockito.when(command.getTargetTableId()).thenReturn(202L);
Mockito.when(command.getAnalyzedJobProperties()).thenReturn(Maps.newHashMap());
Mockito.when(command.getDataSourceProperties()).thenReturn(null);

Env env = Mockito.mock(Env.class);
EditLog editLog = Mockito.mock(EditLog.class);
Mockito.when(env.getEditLog()).thenReturn(editLog);
try (MockedStatic<Env> envStatic = Mockito.mockStatic(Env.class)) {
envStatic.when(Env::getCurrentEnv).thenReturn(env);
routineLoadJob.modifyProperties(command);
}

Assert.assertEquals(202L, routineLoadJob.getTableId());
Assert.assertSame(progress, routineLoadJob.getProgress());
ArgumentCaptor<AlterRoutineLoadJobOperationLog> logCaptor =
ArgumentCaptor.forClass(AlterRoutineLoadJobOperationLog.class);
Mockito.verify(editLog).logAlterRoutineLoadJob(logCaptor.capture());
Assert.assertEquals(202L, logCaptor.getValue().getTargetTableId());
Assert.assertTrue(logCaptor.getValue().getJobProperties().isEmpty());
Assert.assertNull(logCaptor.getValue().getDataSourceProperties());
}

@Test
public void testReplayModifyPropertiesSwitchesTargetTableWithoutResettingProgress() {
KafkaRoutineLoadJob routineLoadJob = new KafkaRoutineLoadJob(1L, "kafka_routine_load_job", 1L,
101L, "127.0.0.1:9020", "topic1", UserIdentity.ADMIN);
Map<Integer, Long> partitionToOffset = Maps.newHashMap();
partitionToOffset.put(1, 123L);
KafkaProgress progress = new KafkaProgress(partitionToOffset);
Deencapsulation.setField(routineLoadJob, "progress", progress);

routineLoadJob.replayModifyProperties(new AlterRoutineLoadJobOperationLog(
1L, Maps.newHashMap(), null));
Assert.assertEquals(101L, routineLoadJob.getTableId());

routineLoadJob.replayModifyProperties(new AlterRoutineLoadJobOperationLog(
1L, Maps.newHashMap(), null, 202L));
Assert.assertEquals(202L, routineLoadJob.getTableId());
Assert.assertSame(progress, routineLoadJob.getProgress());
Assert.assertEquals(Long.valueOf(123L),
((KafkaProgress) routineLoadJob.getProgress()).getOffsetByPartition(1));
}

@Test
public void testUpdateProgressWarnsWhenReadCommittedTaskHasZeroRowsAndLag() throws UserException {
KafkaRoutineLoadJob routineLoadJob = new KafkaRoutineLoadJob(1L, "kafka_routine_load_job", 1L,
Expand Down
Loading
Loading