use of io.pravega.controller.store.VersionedMetadata in project pravega by pravega.
the class PersistentStreamBase method submitScale.
/**
* This method attempts to start a new scale workflow. For this it first computes epoch transition and stores it
* in the metadastore.
* This method can be called by manual scale or during the processing of auto-scale event. Which means there could be
* concurrent calls to this method.
*
* @param segmentsToSeal segments that will be sealed at the end of this scale operation.
* @param newRanges key ranges of new segments to be created
* @param scaleTimestamp scaling timestamp
* @return : list of newly created segments with current epoch
*/
@Override
public CompletableFuture<VersionedMetadata<EpochTransitionRecord>> submitScale(final List<Long> segmentsToSeal, final List<Map.Entry<Double, Double>> newRanges, final long scaleTimestamp, final VersionedMetadata<EpochTransitionRecord> existing, OperationContext context) {
Preconditions.checkNotNull(context, "Operation context cannot be null");
return verifyNotSealed(context).thenCompose(v -> {
if (existing == null) {
return getEpochTransition(context);
} else {
return CompletableFuture.completedFuture(existing);
}
}).thenCompose(record -> getActiveEpochRecord(true, context).thenCompose(currentEpoch -> getConfiguration(context).thenCompose(config -> {
if (!record.getObject().equals(EpochTransitionRecord.EMPTY)) {
// and new ranges are identical). else throw scale conflict exception
if (!RecordHelper.verifyRecordMatchesInput(segmentsToSeal, newRanges, false, record.getObject())) {
log.debug(context.getRequestId(), "scale conflict, another scale operation is ongoing");
throw new EpochTransitionOperationExceptions.ConflictException();
}
return CompletableFuture.completedFuture(record);
} else {
// check input is valid and satisfies preconditions
if (!RecordHelper.canScaleFor(segmentsToSeal, currentEpoch)) {
return updateEpochTransitionNode(new VersionedMetadata<>(EpochTransitionRecord.EMPTY, record.getVersion()), context).thenApply(x -> {
log.warn(context.getRequestId(), "scale precondition failed {}", segmentsToSeal);
throw new EpochTransitionOperationExceptions.PreConditionFailureException();
});
}
if (!RecordHelper.validateInputRange(segmentsToSeal, newRanges, currentEpoch)) {
log.error(context.getRequestId(), "scale input invalid {} {}", segmentsToSeal, newRanges);
throw new EpochTransitionOperationExceptions.InputInvalidException();
}
int numberOfSegmentsPostScale = currentEpoch.getSegments().size() - segmentsToSeal.size() + newRanges.size();
if (numberOfSegmentsPostScale < config.getScalingPolicy().getMinNumSegments()) {
log.warn(context.getRequestId(), "Scale cannot be performed as Min Segment Count will not hold {} {}", segmentsToSeal, newRanges);
throw new EpochTransitionOperationExceptions.PreConditionFailureException();
}
EpochTransitionRecord epochTransition = RecordHelper.computeEpochTransition(currentEpoch, segmentsToSeal, newRanges, scaleTimestamp);
return updateEpochTransitionNode(new VersionedMetadata<>(epochTransition, record.getVersion()), context).thenApply(version -> {
log.info(context.getRequestId(), "scale for stream {}/{} accepted. Segments to seal = {}", scope, name, epochTransition.getSegmentsToSeal());
return new VersionedMetadata<>(epochTransition, version);
});
}
})));
}
use of io.pravega.controller.store.VersionedMetadata in project pravega by pravega.
the class PersistentStreamBase method completeTruncation.
@Override
public CompletableFuture<Void> completeTruncation(VersionedMetadata<StreamTruncationRecord> record, OperationContext context) {
Preconditions.checkNotNull(context, "operation context cannot be null");
Preconditions.checkNotNull(record);
Preconditions.checkArgument(record.getObject().isUpdating());
StreamTruncationRecord current = record.getObject();
if (current.isUpdating()) {
StreamTruncationRecord completedProp = StreamTruncationRecord.complete(current);
return Futures.toVoid(setTruncationData(new VersionedMetadata<>(completedProp, record.getVersion()), context));
} else {
// idempotent
return CompletableFuture.completedFuture(null);
}
}
use of io.pravega.controller.store.VersionedMetadata in project pravega by pravega.
the class PersistentStreamBase method scaleCreateNewEpoch.
@Override
public CompletableFuture<VersionedMetadata<EpochTransitionRecord>> scaleCreateNewEpoch(VersionedMetadata<EpochTransitionRecord> versionedMetadata, OperationContext context) {
Preconditions.checkNotNull(context, "Operation context cannot be null");
return getActiveEpochRecord(true, context).thenCompose(currentEpoch -> {
// only perform idempotent update. If update is already completed, do nothing.
if (currentEpoch.getEpoch() < versionedMetadata.getObject().getNewEpoch()) {
EpochTransitionRecord epochTransition = versionedMetadata.getObject();
// time
long time = Math.max(epochTransition.getTime(), currentEpoch.getCreationTime() + 1);
// new segments
ImmutableList.Builder<StreamSegmentRecord> newSegmentsBuilder = ImmutableList.builder();
epochTransition.getNewSegmentsWithRange().forEach((key, value) -> newSegmentsBuilder.add(newSegmentRecord(key, time, value.getKey(), value.getValue())));
// sealed segments
ImmutableList.Builder<StreamSegmentRecord> sealedSegmentsBuilder = ImmutableList.builder();
epochTransition.getSegmentsToSeal().forEach(x -> sealedSegmentsBuilder.add(currentEpoch.getSegment(x)));
// overall segments in epoch
ImmutableList.Builder<StreamSegmentRecord> builder = ImmutableList.builder();
currentEpoch.getSegments().forEach(x -> {
if (!epochTransition.getSegmentsToSeal().contains(x.segmentId())) {
builder.add(x);
}
});
ImmutableList<StreamSegmentRecord> newSegments = newSegmentsBuilder.build();
builder.addAll(newSegments);
ImmutableList<StreamSegmentRecord> newEpochSegments = builder.build();
// epoch record
return getSplitMergeCountsTillEpoch(currentEpoch, context).thenCompose(cumulativeSplitMergeCount -> {
EpochRecord epochRecord = new EpochRecord(epochTransition.getNewEpoch(), epochTransition.getNewEpoch(), newEpochSegments, time, getNewEpochSplitCount(cumulativeSplitMergeCount.getKey(), currentEpoch.getSegments(), newEpochSegments), getNewEpochMergeCount(cumulativeSplitMergeCount.getValue(), currentEpoch.getSegments(), newEpochSegments));
HistoryTimeSeriesRecord timeSeriesRecord = new HistoryTimeSeriesRecord(epochTransition.getNewEpoch(), epochTransition.getNewEpoch(), sealedSegmentsBuilder.build(), newSegments, epochRecord.getCreationTime());
return createEpochRecord(epochRecord, context).thenCompose(x -> updateHistoryTimeSeries(timeSeriesRecord, context)).thenCompose(x -> createSegmentSealedEpochRecords(epochTransition.getSegmentsToSeal(), epochTransition.getNewEpoch(), context)).thenApply(x -> versionedMetadata);
});
} else {
return CompletableFuture.completedFuture(versionedMetadata);
}
});
}
use of io.pravega.controller.store.VersionedMetadata in project pravega by pravega.
the class PersistentStreamBase method updateHistoryTimeSeries.
private CompletableFuture<Void> updateHistoryTimeSeries(HistoryTimeSeriesRecord record, OperationContext context) {
int historyChunk = record.getEpoch() / historyChunkSize.get();
boolean isFirst = record.getEpoch() % historyChunkSize.get() == 0;
if (isFirst) {
return createHistoryTimeSeriesChunk(historyChunk, record, context);
} else {
return getHistoryTimeSeriesChunkData(historyChunk, true, context).thenCompose(x -> {
HistoryTimeSeries historyChunkTimeSeries = x.getObject();
if (historyChunkTimeSeries.getLatestRecord().getEpoch() < record.getEpoch()) {
HistoryTimeSeries update = HistoryTimeSeries.addHistoryRecord(historyChunkTimeSeries, record);
return Futures.toVoid(updateHistoryTimeSeriesChunkData(historyChunk, new VersionedMetadata<>(update, x.getVersion()), context));
} else {
return CompletableFuture.completedFuture(null);
}
});
}
}
use of io.pravega.controller.store.VersionedMetadata in project pravega by pravega.
the class PersistentStreamBase method pingTransaction.
@Override
public CompletableFuture<VersionedTransactionData> pingTransaction(final VersionedTransactionData txnData, final long lease, OperationContext context) {
Preconditions.checkNotNull(context, "Operation context cannot be null");
// Update txn record with new lease value and return versioned tx data.
final int epoch = txnData.getEpoch();
final UUID txnId = txnData.getId();
final Version version = txnData.getVersion();
final long creationTime = txnData.getCreationTime();
final long maxExecutionExpiryTime = txnData.getMaxExecutionExpiryTime();
final TxnStatus status = txnData.getStatus();
final String writerId = txnData.getWriterId();
final long commitTime = txnData.getCommitTime();
final long position = txnData.getCommitOrder();
final ImmutableMap<Long, Long> commitOffsets = txnData.getCommitOffsets();
final ActiveTxnRecord newData = new ActiveTxnRecord(creationTime, System.currentTimeMillis() + lease, maxExecutionExpiryTime, status, writerId, commitTime, position, commitOffsets);
final VersionedMetadata<ActiveTxnRecord> data = new VersionedMetadata<>(newData, version);
return updateActiveTx(epoch, txnId, data, context).thenApply(updatedVersion -> new VersionedTransactionData(epoch, txnId, updatedVersion, status, creationTime, maxExecutionExpiryTime, writerId, commitTime, position, commitOffsets));
}
Aggregations