use of io.pravega.controller.store.stream.OperationContext in project pravega by pravega.
the class CommitEventProcessor method process.
@Override
protected void process(CommitEvent event, Position position) {
String scope = event.getScope();
String stream = event.getStream();
int epoch = event.getEpoch();
UUID txnId = event.getTxid();
OperationContext context = streamMetadataStore.createContext(scope, stream);
log.debug("Committing transaction {} on stream {}/{}", event.getTxid(), event.getScope(), event.getStream());
streamMetadataStore.getActiveEpoch(scope, stream, context, false, executor).thenComposeAsync(pair -> {
// complete before transitioning the stream to new epoch.
if (epoch < pair.getKey()) {
return CompletableFuture.completedFuture(null);
} else if (epoch == pair.getKey()) {
// If the transaction's epoch is same as the stream's current epoch, commit it.
return completeCommit(scope, stream, epoch, txnId, context, this.streamMetadataTasks.retrieveDelegationToken());
} else {
// Otherwise, postpone commit operation until the stream transitions to next epoch.
return postponeCommitEvent(event);
}
}).whenCompleteAsync((result, error) -> {
if (error != null) {
log.error("Failed committing transaction {} on stream {}/{}", txnId, scope, stream);
} else {
log.debug("Successfully committed transaction {} on stream {}/{}", txnId, scope, stream);
if (processedEvents != null) {
processedEvents.offer(event);
}
}
}, executor).join();
}
use of io.pravega.controller.store.stream.OperationContext in project pravega by pravega.
the class StreamMetadataTasks method sealStream.
/**
* Seal a stream.
*
* @param scope scope.
* @param stream stream name.
* @param contextOpt optional context
* @return update status.
*/
public CompletableFuture<UpdateStreamStatus.Status> sealStream(String scope, String stream, OperationContext contextOpt) {
final OperationContext context = contextOpt == null ? streamMetadataStore.createContext(scope, stream) : contextOpt;
// 1. post event for seal.
SealStreamEvent event = new SealStreamEvent(scope, stream);
return writeEvent(event).thenCompose(x -> streamMetadataStore.getState(scope, stream, false, context, executor)).thenCompose(state -> {
if (state.equals(State.SEALED)) {
return CompletableFuture.completedFuture(true);
} else {
return streamMetadataStore.setState(scope, stream, State.SEALING, context, executor);
}
}).thenCompose(result -> {
if (result) {
return checkDone(() -> isSealed(scope, stream, context)).thenApply(x -> UpdateStreamStatus.Status.SUCCESS);
} else {
return CompletableFuture.completedFuture(UpdateStreamStatus.Status.FAILURE);
}
}).exceptionally(ex -> {
log.warn("Exception thrown in trying to notify sealed segments {}", ex.getMessage());
return handleUpdateStreamError(ex);
});
}
use of io.pravega.controller.store.stream.OperationContext in project pravega by pravega.
the class StreamTransactionMetadataTasks method createTxnBody.
/**
* Creates txn on the specified stream.
*
* Post-condition:
* 1. If txn creation succeeds, then
* (a) txn node is created in the store,
* (b) txn segments are successfully created on respective segment stores,
* (c) txn is present in the host-txn index of current host,
* (d) txn's timeout is being tracked in timeout service.
*
* 2. If process fails after creating txn node, but before responding to the client, then since txn is
* present in the host-txn index, some other controller process shall abort the txn after maxLeaseValue
*
* 3. If timeout service tracks timeout of specified txn,
* then txn is also present in the host-txn index of current process.
*
* Invariant:
* The following invariants are maintained throughout the execution of createTxn, pingTxn and sealTxn methods.
* 1. If timeout service tracks timeout of a txn, then txn is also present in the host-txn index of current process.
* 2. If txn znode is updated, then txn is also present in the host-txn index of current process.
*
* @param scope scope name.
* @param stream stream name.
* @param lease txn lease.
* @param scaleGracePeriod amount of time for which txn may remain open after scale operation is initiated.
* @param ctx context.
* @return identifier of the created txn.
*/
CompletableFuture<Pair<VersionedTransactionData, List<Segment>>> createTxnBody(final String scope, final String stream, final long lease, final long scaleGracePeriod, final OperationContext ctx) {
// Step 1. Validate parameters.
CompletableFuture<Void> validate = validate(lease, scaleGracePeriod);
long maxExecutionPeriod = Math.min(MAX_EXECUTION_TIME_MULTIPLIER * lease, Duration.ofDays(1).toMillis());
UUID txnId = UUID.randomUUID();
TxnResource resource = new TxnResource(scope, stream, txnId);
// Step 2. Add txn to host-transaction index.
CompletableFuture<Void> addIndex = validate.thenComposeAsync(ignore -> streamMetadataStore.addTxnToIndex(hostId, resource, 0), executor).whenComplete((v, e) -> {
if (e != null) {
log.debug("Txn={}, failed adding txn to host-txn index of host={}", txnId, hostId);
} else {
log.debug("Txn={}, added txn to host-txn index of host={}", txnId, hostId);
}
});
// Step 3. Create txn node in the store.
CompletableFuture<VersionedTransactionData> txnFuture = addIndex.thenComposeAsync(ignore -> streamMetadataStore.createTransaction(scope, stream, txnId, lease, maxExecutionPeriod, scaleGracePeriod, ctx, executor), executor).whenComplete((v, e) -> {
if (e != null) {
log.debug("Txn={}, failed creating txn in store", txnId);
} else {
log.debug("Txn={}, created in store", txnId);
}
});
// Step 4. Notify segment stores about new txn.
CompletableFuture<List<Segment>> segmentsFuture = txnFuture.thenComposeAsync(txnData -> streamMetadataStore.getActiveSegments(scope, stream, txnData.getEpoch(), ctx, executor), executor);
CompletableFuture<Void> notify = segmentsFuture.thenComposeAsync(activeSegments -> notifyTxnCreation(scope, stream, activeSegments, txnId), executor).whenComplete((v, e) -> log.debug("Txn={}, notified segments stores", txnId));
// Step 5. Start tracking txn in timeout service
return notify.whenCompleteAsync((result, ex) -> {
int version = 0;
long executionExpiryTime = System.currentTimeMillis() + maxExecutionPeriod;
if (!txnFuture.isCompletedExceptionally()) {
version = txnFuture.join().getVersion();
executionExpiryTime = txnFuture.join().getMaxExecutionExpiryTime();
}
timeoutService.addTxn(scope, stream, txnId, version, lease, executionExpiryTime, scaleGracePeriod);
log.debug("Txn={}, added to timeout service on host={}", txnId, hostId);
}, executor).thenApplyAsync(v -> new ImmutablePair<>(txnFuture.join(), segmentsFuture.join()), executor);
}
use of io.pravega.controller.store.stream.OperationContext in project pravega by pravega.
the class ControllerService method checkTransactionStatus.
/**
* Checks transaction status.
* @param scope scope
* @param stream stream name
* @param txnId transaction id
* @param requestId request id
* @return Transaction state future
*/
public CompletableFuture<TxnState> checkTransactionStatus(final String scope, final String stream, final UUID txnId, final long requestId) {
Exceptions.checkNotNullOrEmpty(scope, "scope");
Exceptions.checkNotNullOrEmpty(stream, "stream");
Preconditions.checkNotNull(txnId, "txnId");
OperationContext context = streamStore.createStreamContext(scope, stream, requestId);
return streamStore.transactionStatus(scope, stream, txnId, context, executor).thenApplyAsync(res -> TxnState.newBuilder().setState(TxnState.State.valueOf(res.name())).build(), executor);
}
use of io.pravega.controller.store.stream.OperationContext in project pravega by pravega.
the class ControllerService method getSegmentsImmediatelyFollowing.
public CompletableFuture<Map<SegmentRange, List<Long>>> getSegmentsImmediatelyFollowing(SegmentId segment, long requestId) {
Preconditions.checkNotNull(segment, "segment");
String scope = segment.getStreamInfo().getScope();
String stream = segment.getStreamInfo().getStream();
OperationContext context = streamStore.createStreamContext(scope, stream, requestId);
return streamStore.getSuccessors(scope, stream, segment.getSegmentId(), context, executor).thenApply(successors -> successors.entrySet().stream().collect(Collectors.toMap(entry -> ModelHelper.createSegmentRange(scope, stream, entry.getKey().segmentId(), entry.getKey().getKeyStart(), entry.getKey().getKeyEnd()), Map.Entry::getValue)));
}
Aggregations