Skip to content

Commit c0db14b

Browse files
pthirunclaude
andcommitted
[controller] Add rewindEpochTimeInSecondsOverride to pass absolute epoch
timestamps through the pipeline Pass absolute epoch rewind timestamps directly through the Venice pipeline instead of converting epoch→relative→epoch which introduces drift. This unblocks EOP hybrid stores from using epoch-based rewind and eliminates time-of-use vs time-of-check drift for SOP stores. Changes: - Add rewindEpochTimeInSecondsOverride field to StoreMetaValue (v42) and AdminOperation (v96) Avro schemas - Thread the new parameter through VPJ → ControllerClient → CreateVersion → Admin → VeniceHelixAdmin → VeniceParentHelixAdmin → AdminExecutionTask - Store epoch override on HybridStoreConfig (interface + impl + ReadOnly) - Use epoch override directly in RealTimeTopicSwitcher.getRewindStartTime() when set (>=0), bypassing relative→epoch conversion - Default -1 sentinel preserves backward compatibility with existing callers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dd4a58e commit c0db14b

29 files changed

Lines changed: 1918 additions & 17 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ subprojects {
327327
// when actually using the new protocol. Example to pin KME to v12 when introducing v13:
328328
// project(':internal:venice-common').file('src/main/resources/avro/KafkaMessageEnvelope/v12', PathValidation.DIRECTORY)
329329
def versionOverrides = [
330-
project(':internal:venice-common').file('src/main/resources/avro/StoreMetaValue/v40', PathValidation.DIRECTORY)
330+
project(':internal:venice-common').file('src/main/resources/avro/StoreMetaValue/v42', PathValidation.DIRECTORY)
331331
]
332332

333333
def schemaDirs = [sourceDir]

clients/venice-push-job/src/main/java/com/linkedin/venice/hadoop/PushJobSetting.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public class PushJobSetting implements Serializable {
5353
public String kafkaInputTopic;
5454
public int repushSourceVersion;
5555
public long rewindTimeInSecondsOverride;
56+
public long rewindEpochTimeInSecondsOverride;
5657
public boolean pushToSeparateRealtimeTopicEnabled;
5758
public boolean kafkaInputCombinerEnabled;
5859
public boolean kafkaInputBuildNewDictEnabled;

clients/venice-push-job/src/main/java/com/linkedin/venice/hadoop/VenicePushJob.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@
126126
import com.linkedin.venice.jobs.ComputeJob;
127127
import com.linkedin.venice.jobs.DataWriterComputeJob;
128128
import com.linkedin.venice.message.KafkaKey;
129-
import com.linkedin.venice.meta.BufferReplayPolicy;
130129
import com.linkedin.venice.meta.HybridStoreConfig;
131130
import com.linkedin.venice.meta.Store;
132131
import com.linkedin.venice.meta.StoreInfo;
@@ -507,6 +506,7 @@ private PushJobSetting getPushJobSetting(VeniceProperties props) {
507506
pushJobSettingToReturn.inputURI = pushJobSettingToReturn.isSourceKafka ? "" : getInputURI(props);
508507
pushJobSettingToReturn.storeName = props.getString(VENICE_STORE_NAME_PROP);
509508
pushJobSettingToReturn.rewindTimeInSecondsOverride = props.getLong(REWIND_TIME_IN_SECONDS_OVERRIDE, NOT_SET);
509+
pushJobSettingToReturn.rewindEpochTimeInSecondsOverride = NOT_SET;
510510

511511
// If we didn't specify a rewind time
512512
if (pushJobSettingToReturn.rewindTimeInSecondsOverride == NOT_SET) {
@@ -523,14 +523,17 @@ private PushJobSetting getPushJobSetting(VeniceProperties props) {
523523
REWIND_EPOCH_TIME_IN_SECONDS_OVERRIDE,
524524
REWIND_EPOCH_TIME_IN_SECONDS_OVERRIDE));
525525
}
526-
// Set the rewindTimeInSecondsOverride to be the time that is now - the provided timestamp so that we rewind
527-
// from start of push to the provided timestamp with some extra buffer time since things aren't perfectly
528-
// instantaneous
526+
527+
// Store epoch directly for controllers that understand it
528+
pushJobSettingToReturn.rewindEpochTimeInSecondsOverride = rewindTimestamp;
529+
530+
// Compute relative fallback for old controllers that don't understand the epoch field
529531
long bufferTime = props.getLong(REWIND_EPOCH_TIME_BUFFER_IN_SECONDS_OVERRIDE, 60);
530532
pushJobSettingToReturn.rewindTimeInSecondsOverride = (nowInSeconds - rewindTimestamp) + bufferTime;
531-
// In order for this config to make sense to the user, the remote rewind policy needs to be validated to be
532-
// REWIND_FROM_SOP
533-
pushJobSettingToReturn.validateRemoteReplayPolicy = BufferReplayPolicy.REWIND_FROM_SOP;
533+
534+
// With epoch passthrough, the SOP restriction is no longer needed because the epoch
535+
// flows directly and works with any replay policy. The relative fallback is still sent
536+
// for backward compatibility with old controllers.
534537
}
535538
}
536539

@@ -2418,6 +2421,7 @@ void createNewStoreVersion(
24182421
Optional.ofNullable(setting.sourceGridFabric),
24192422
setting.livenessHeartbeatEnabled,
24202423
setting.rewindTimeInSecondsOverride,
2424+
setting.rewindEpochTimeInSecondsOverride,
24212425
setting.deferVersionSwap,
24222426
setting.targetedRegions,
24232427
pushJobSetting.repushSourceVersion,

clients/venice-push-job/src/test/java/com/linkedin/venice/hadoop/TestVenicePushJobCheckpoints.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,7 @@ private void configureControllerClientMock(
730730
any(),
731731
anyBoolean(),
732732
anyLong(),
733+
anyLong(),
733734
anyBoolean(),
734735
any(),
735736
anyInt(),

clients/venice-push-job/src/test/java/com/linkedin/venice/hadoop/VenicePushJobTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,7 @@ private VersionCreationResponse mockVersionCreationResponse(ControllerClient cli
17371737
any(),
17381738
anyBoolean(),
17391739
anyLong(),
1740+
anyLong(),
17401741
anyBoolean(),
17411742
any(),
17421743
anyInt(),

internal/venice-common/src/main/java/com/linkedin/venice/controllerapi/ControllerApiConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ public class ControllerApiConstants {
170170

171171
public static final String REWIND_TIME_IN_SECONDS_OVERRIDE = "rewind_time_in_seconds_override";
172172

173+
public static final String REWIND_EPOCH_TIME_IN_SECONDS_OVERRIDE = "rewind_epoch_time_in_seconds_override";
174+
173175
public static final String DEFER_VERSION_SWAP = "defer_version_swap";
174176

175177
public static final String REPUSH_SOURCE_VERSION = "repush_source_version";

internal/venice-common/src/main/java/com/linkedin/venice/controllerapi/ControllerClient.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import static com.linkedin.venice.controllerapi.ControllerApiConstants.REPLICATION_METADATA_VERSION_ID;
5555
import static com.linkedin.venice.controllerapi.ControllerApiConstants.REPUSH_SOURCE_VERSION;
5656
import static com.linkedin.venice.controllerapi.ControllerApiConstants.REPUSH_TTL_SECONDS;
57+
import static com.linkedin.venice.controllerapi.ControllerApiConstants.REWIND_EPOCH_TIME_IN_SECONDS_OVERRIDE;
5758
import static com.linkedin.venice.controllerapi.ControllerApiConstants.REWIND_TIME_IN_SECONDS_OVERRIDE;
5859
import static com.linkedin.venice.controllerapi.ControllerApiConstants.SCHEMA_COMPAT_TYPE;
5960
import static com.linkedin.venice.controllerapi.ControllerApiConstants.SCHEMA_ID;
@@ -321,6 +322,7 @@ public VersionCreationResponse requestTopicForWrites(
321322
sourceGridFabric,
322323
batchJobHeartbeatEnabled,
323324
rewindTimeInSecondsOverride,
325+
-1,
324326
false,
325327
null,
326328
-1,
@@ -355,6 +357,7 @@ public VersionCreationResponse requestTopicForWrites(
355357
sourceGridFabric,
356358
batchJobHeartbeatEnabled,
357359
rewindTimeInSecondsOverride,
360+
-1,
358361
deferVersionSwap,
359362
null,
360363
-1,
@@ -401,6 +404,7 @@ public VersionCreationResponse requestTopicForWrites(
401404
Optional<String> sourceGridFabric,
402405
boolean batchJobHeartbeatEnabled,
403406
long rewindTimeInSecondsOverride,
407+
long rewindEpochTimeInSecondsOverride,
404408
boolean deferVersionSwap,
405409
String targetedRegions,
406410
int repushSourceVersion,
@@ -419,6 +423,7 @@ public VersionCreationResponse requestTopicForWrites(
419423
.add(SOURCE_GRID_FABRIC, sourceGridFabric)
420424
.add(BATCH_JOB_HEARTBEAT_ENABLED, batchJobHeartbeatEnabled)
421425
.add(REWIND_TIME_IN_SECONDS_OVERRIDE, rewindTimeInSecondsOverride)
426+
.add(REWIND_EPOCH_TIME_IN_SECONDS_OVERRIDE, rewindEpochTimeInSecondsOverride)
422427
.add(DEFER_VERSION_SWAP, deferVersionSwap)
423428
.add(REPUSH_SOURCE_VERSION, repushSourceVersion)
424429
.add(SEPARATE_REAL_TIME_TOPIC_ENABLED, pushToSeparateRealtimeTopic)

internal/venice-common/src/main/java/com/linkedin/venice/controllerapi/RequestTopicForPushRequest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class RequestTopicForPushRequest {
1919
private boolean isWriteComputeEnabled = false;
2020
private boolean separateRealTimeTopicEnabled = false;
2121
private long rewindTimeInSecondsOverride = -1L;
22+
private long rewindEpochTimeInSecondsOverride = -1L;
2223
private boolean deferVersionSwap = false;
2324
private String targetedRegions = null;
2425
private int repushSourceVersion = -1;
@@ -86,6 +87,10 @@ public long getRewindTimeInSecondsOverride() {
8687
return rewindTimeInSecondsOverride;
8788
}
8889

90+
public long getRewindEpochTimeInSecondsOverride() {
91+
return rewindEpochTimeInSecondsOverride;
92+
}
93+
8994
public boolean isDeferVersionSwap() {
9095
return deferVersionSwap;
9196
}
@@ -138,6 +143,10 @@ public void setRewindTimeInSecondsOverride(long rewindTimeInSecondsOverride) {
138143
this.rewindTimeInSecondsOverride = rewindTimeInSecondsOverride;
139144
}
140145

146+
public void setRewindEpochTimeInSecondsOverride(long rewindEpochTimeInSecondsOverride) {
147+
this.rewindEpochTimeInSecondsOverride = rewindEpochTimeInSecondsOverride;
148+
}
149+
141150
public void setDeferVersionSwap(boolean deferVersionSwap) {
142151
this.deferVersionSwap = deferVersionSwap;
143152
}

internal/venice-common/src/main/java/com/linkedin/venice/meta/HybridStoreConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,9 @@ public interface HybridStoreConfig extends DataModelBackedStructure<StoreHybridC
3030

3131
void setRealTimeTopicName(String realTimeTopicName);
3232

33+
long getRewindEpochTimeInSecondsOverride();
34+
35+
void setRewindEpochTimeInSecondsOverride(long rewindEpochTimeInSecondsOverride);
36+
3337
HybridStoreConfig clone();
3438
}

internal/venice-common/src/main/java/com/linkedin/venice/meta/HybridStoreConfigImpl.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ public void setRealTimeTopicName(String realTimeTopicName) {
112112
this.hybridConfig.realTimeTopicName = realTimeTopicName;
113113
}
114114

115+
@Override
116+
public long getRewindEpochTimeInSecondsOverride() {
117+
return this.hybridConfig.rewindEpochTimeInSecondsOverride;
118+
}
119+
120+
@Override
121+
public void setRewindEpochTimeInSecondsOverride(long rewindEpochTimeInSecondsOverride) {
122+
this.hybridConfig.rewindEpochTimeInSecondsOverride = rewindEpochTimeInSecondsOverride;
123+
}
124+
115125
@Override
116126
public StoreHybridConfig dataModel() {
117127
return this.hybridConfig;
@@ -136,12 +146,14 @@ public int hashCode() {
136146

137147
@JsonIgnore
138148
public HybridStoreConfig clone() {
139-
return new HybridStoreConfigImpl(
149+
HybridStoreConfigImpl cloned = new HybridStoreConfigImpl(
140150
getRewindTimeInSeconds(),
141151
getOffsetLagThresholdToGoOnline(),
142152
getProducerTimestampLagThresholdToGoOnlineInSeconds(),
143153
getDataReplicationPolicy(),
144154
getBufferReplayPolicy(),
145155
getRealTimeTopicName());
156+
cloned.setRewindEpochTimeInSecondsOverride(getRewindEpochTimeInSecondsOverride());
157+
return cloned;
146158
}
147159
}

0 commit comments

Comments
 (0)