private CompletableFuture<ScaleResponse> startScaleInternal(final Stream stream, final List<Long> sealedSegments, final Map<Double, Double> newKeyRanges, String method, long requestId) { Preconditions.checkNotNull(stream, "stream"); Preconditions.checkNotNull(sealedSegments, "sealedSegments"); Preconditions.checkNotNull(newKeyRanges, "newKeyRanges"); final CompletableFuture<ScaleResponse> result = this.retryConfig.runAsync(() -> { RPCAsyncCallback<ScaleResponse> callback = new RPCAsyncCallback<>(requestId, method); long scaleTimestamp = System.currentTimeMillis(); new ControllerClientTagger(client) .withTag(requestId, method, stream.getScope(), stream.getStreamName(), String.valueOf(scaleTimestamp)) .scale(ScaleRequest.newBuilder() .setStreamInfo(ModelHelper.createStreamInfo(stream.getScope(), stream.getStreamName())) .addAllSealedSegments(sealedSegments) .addAllNewKeyRanges(newKeyRanges.entrySet().stream() .map(x -> ScaleRequest.KeyRangeEntry.newBuilder() .setStart(x.getKey()).setEnd(x.getValue()).build()) .collect(Collectors.toList())) .setScaleTimestamp(scaleTimestamp) .build(), callback); return callback.getFuture(); }, this.executor); return result; }
private CompletableFuture<StreamSegmentSuccessors> getSegmentsBetweenStreamCuts(final StreamCut fromStreamCut, final StreamCut toStreamCut) { Exceptions.checkNotClosed(closed.get(), this); final Stream stream = fromStreamCut.asImpl().getStream(); long traceId = LoggerHelpers.traceEnter(log, "getSegments", stream); CompletableFuture<String> token = getOrRefreshDelegationTokenFor(stream.getScope(), stream.getStreamName()); final CompletableFuture<StreamCutRangeResponse> resultFuture = this.retryConfig.runAsync(() -> { RPCAsyncCallback<StreamCutRangeResponse> callback = new RPCAsyncCallback<>(traceId, "getSuccessorsFromCut"); client.getSegmentsBetween(ModelHelper.decode(stream.getScope(), stream.getStreamName(), getStreamCutMap(fromStreamCut), getStreamCutMap(toStreamCut)), callback); return callback.getFuture(); }, this.executor); return resultFuture.thenApply(response -> { log.debug("Received the following data from the controller {}", response.getSegmentsList()); return new StreamSegmentSuccessors(response.getSegmentsList().stream().map(ModelHelper::encode).collect(Collectors.toSet()), response.getDelegationToken()); }); }
@Override public CompletableFuture<StreamSegmentsWithPredecessors> getSuccessors(Segment segment) { Exceptions.checkNotClosed(closed.get(), this); long traceId = LoggerHelpers.traceEnter(log, "getSuccessors", segment); final CompletableFuture<SuccessorResponse> resultFuture = this.retryConfig.runAsync(() -> { RPCAsyncCallback<SuccessorResponse> callback = new RPCAsyncCallback<>(traceId, "getSuccessors"); client.getSegmentsImmediatlyFollowing(ModelHelper.decode(segment), callback); return callback.getFuture(); }, this.executor); return resultFuture.thenApply(successors -> { log.debug("Received the following data from the controller {}", successors.getSegmentsList()); Map<SegmentWithRange, List<Long>> result = new HashMap<>(); for (SuccessorResponse.SegmentEntry entry : successors.getSegmentsList()) { result.put(ModelHelper.encode(entry.getSegment()), entry.getValueList()); } return new StreamSegmentsWithPredecessors(result, successors.getDelegationToken()); }).whenComplete((x, e) -> { if (e != null) { log.warn("getSuccessors failed: ", e); } LoggerHelpers.traceLeave(log, "getSuccessors", traceId); }); }
@Override public CompletableFuture<Transaction.Status> checkTransactionStatus(final Stream stream, final UUID txId) { Exceptions.checkNotClosed(closed.get(), this); Preconditions.checkNotNull(stream, "stream"); Preconditions.checkNotNull(txId, "txId"); long traceId = LoggerHelpers.traceEnter(log, "checkTransactionStatus", stream, txId); final CompletableFuture<TxnState> result = this.retryConfig.runAsync(() -> { RPCAsyncCallback<TxnState> callback = new RPCAsyncCallback<>(traceId, "checkTransactionStatus"); client.checkTransactionState(TxnRequest.newBuilder() .setStreamInfo(ModelHelper.createStreamInfo(stream.getScope(), stream.getStreamName())) .setTxnId(ModelHelper.decode(txId)) .build(), callback); return callback.getFuture(); }, this.executor); return result.thenApply(status -> ModelHelper.encode(status.getState(), stream + " " + txId)) .whenComplete((x, e) -> { if (e != null) { log.warn("checkTransactionStatus failed: ", e); } LoggerHelpers.traceLeave(log, "checkTransactionStatus", traceId); }); }
@Override public CompletableFuture<TxnSegments> createTransaction(final Stream stream, final long lease) { Exceptions.checkNotClosed(closed.get(), this); Preconditions.checkNotNull(stream, "stream"); long traceId = LoggerHelpers.traceEnter(log, "createTransaction", stream, lease); final CompletableFuture<CreateTxnResponse> result = this.retryConfig.runAsync(() -> { RPCAsyncCallback<CreateTxnResponse> callback = new RPCAsyncCallback<>(traceId, "createTransaction"); client.createTransaction( CreateTxnRequest.newBuilder() .setStreamInfo(ModelHelper.createStreamInfo(stream.getScope(), stream.getStreamName())) .setLease(lease) .build(), callback); return callback.getFuture(); }, this.executor); return result.thenApply(this::convert) .whenComplete((x, e) -> { if (e != null) { log.warn("createTransaction failed: ", e); } LoggerHelpers.traceLeave(log, "createTransaction", traceId); }); }
@Override public CompletableFuture<Void> commitTransaction(final Stream stream, final UUID txId) { Exceptions.checkNotClosed(closed.get(), this); Preconditions.checkNotNull(stream, "stream"); Preconditions.checkNotNull(txId, "txId"); long traceId = LoggerHelpers.traceEnter(log, "commitTransaction", stream, txId); final CompletableFuture<TxnStatus> result = this.retryConfig.runAsync(() -> { RPCAsyncCallback<TxnStatus> callback = new RPCAsyncCallback<>(traceId, "commitTransaction"); client.commitTransaction(TxnRequest.newBuilder() .setStreamInfo(ModelHelper.createStreamInfo(stream.getScope(), stream.getStreamName())) .setTxnId(ModelHelper.decode(txId)) .build(), callback); return callback.getFuture(); }, this.executor); return Futures.toVoidExpecting(result, TxnStatus.newBuilder().setStatus(TxnStatus.Status.SUCCESS).build(), TxnFailedException::new) .whenComplete((x, e) -> { if (e != null) { log.warn("commitTransaction failed: ", e); } LoggerHelpers.traceLeave(log, "commitTransaction", traceId); }); }
/** * Invoke the simple scale down Test, produce no into a stream. * The test will periodically check if a scale event has occurred by talking to controller via * controller client. * * @throws InterruptedException if interrupted * @throws URISyntaxException If URI is invalid */ private CompletableFuture<Void> scaleDownTest() { final ControllerImpl controller = getController(); // overall wait for test to complete in 260 seconds (4.2 minutes) or scale down, whichever happens first. return Retry.withExpBackoff(10, 10, 30, Duration.ofSeconds(10).toMillis()) .retryingOn(ScaleOperationNotDoneException.class) .throwingOn(RuntimeException.class) .runAsync(() -> controller.getCurrentSegments(SCOPE, SCALE_DOWN_STREAM_NAME) .thenAccept(x -> { if (x.getSegments().size() == 2) { throw new ScaleOperationNotDoneException(); } else { log.info("scale down done successfully"); } }), scaleExecutorService); }
@Override public CompletableFuture<Void> pingTransaction(Stream stream, UUID txId, long lease) { Exceptions.checkNotClosed(closed.get(), this); long traceId = LoggerHelpers.traceEnter(log, "pingTransaction", stream, txId, lease); final CompletableFuture<PingTxnStatus> result = this.retryConfig.runAsync(() -> { RPCAsyncCallback<PingTxnStatus> callback = new RPCAsyncCallback<>(traceId, "pingTransaction"); client.pingTransaction(PingTxnRequest.newBuilder().setStreamInfo( ModelHelper.createStreamInfo(stream.getScope(), stream.getStreamName())) .setTxnId(ModelHelper.decode(txId)) .setLease(lease).build(), callback); return callback.getFuture(); }, this.executor); return Futures.toVoidExpecting(result, PingTxnStatus.newBuilder().setStatus(PingTxnStatus.Status.OK).build(), PingFailedException::new) .whenComplete((x, e) -> { if (e != null) { log.warn("pingTransaction failed: ", e); } LoggerHelpers.traceLeave(log, "pingTransaction", traceId); }); }
@Override public CompletableFuture<PravegaNodeUri> getEndpointForSegment(final String qualifiedSegmentName) { Exceptions.checkNotClosed(closed.get(), this); Exceptions.checkNotNullOrEmpty(qualifiedSegmentName, "qualifiedSegmentName"); long traceId = LoggerHelpers.traceEnter(log, "getEndpointForSegment", qualifiedSegmentName); final CompletableFuture<NodeUri> result = this.retryConfig.runAsync(() -> { RPCAsyncCallback<NodeUri> callback = new RPCAsyncCallback<>(traceId, "getEndpointForSegment"); Segment segment = Segment.fromScopedName(qualifiedSegmentName); client.getURI(ModelHelper.createSegmentId(segment.getScope(), segment.getStreamName(), segment.getSegmentId()), callback); return callback.getFuture(); }, this.executor); return result.thenApply(ModelHelper::encode) .whenComplete((x, e) -> { if (e != null) { log.warn("getEndpointForSegment failed: ", e); } LoggerHelpers.traceLeave(log, "getEndpointForSegment", traceId); }); }
@Override public CompletableFuture<Boolean> isSegmentOpen(final Segment segment) { Exceptions.checkNotClosed(closed.get(), this); long traceId = LoggerHelpers.traceEnter(log, "isSegmentOpen", segment); final CompletableFuture<SegmentValidityResponse> result = this.retryConfig.runAsync(() -> { RPCAsyncCallback<SegmentValidityResponse> callback = new RPCAsyncCallback<>(traceId, "isSegmentOpen"); client.isSegmentValid(ModelHelper.createSegmentId(segment.getScope(), segment.getStreamName(), segment.getSegmentId()), callback); return callback.getFuture(); }, this.executor); return result.thenApply(SegmentValidityResponse::getResponse) .whenComplete((x, e) -> { if (e != null) { log.warn("isSegmentOpen failed: ", e); } LoggerHelpers.traceLeave(log, "isSegmentOpen", traceId); }); }
@Override public CompletableFuture<String> getOrRefreshDelegationTokenFor(String scope, String streamName) { Exceptions.checkNotClosed(closed.get(), this); Exceptions.checkNotNullOrEmpty(scope, "scope"); Exceptions.checkNotNullOrEmpty(streamName, "stream"); long traceId = LoggerHelpers.traceEnter(log, "getOrRefreshDelegationTokenFor", scope, streamName); final CompletableFuture<DelegationToken> result = this.retryConfig.runAsync(() -> { RPCAsyncCallback<DelegationToken> callback = new RPCAsyncCallback<>(traceId, "getOrRefreshDelegationTokenFor"); client.getDelegationToken(ModelHelper.createStreamInfo(scope, streamName), callback); return callback.getFuture(); }, this.executor); return result.thenApply( token -> token.getDelegationToken()) .whenComplete((x, e) -> { if (e != null) { log.warn("getCurrentSegments failed: ", e); } LoggerHelpers.traceLeave(log, "getCurrentSegments", traceId); }); }
private CompletableFuture<Void> processEvent(WriterMock requestEventWriter) throws InterruptedException { return Retry.withExpBackoff(100, 10, 5, 1000) .retryingOn(TaskExceptions.StartException.class) .throwingOn(RuntimeException.class) .runAsync(() -> { ControllerEvent event; try { event = requestEventWriter.getEventQueue().take(); } catch (InterruptedException e) { throw new RuntimeException(e); } return streamRequestHandler.processEvent(event) .exceptionally(e -> { requestEventWriter.getEventQueue().add(event); throw new CompletionException(e); }); }, executor); }
private boolean createScopeWithSimpleRetry(String scopeName, URI controllerURI) throws ExecutionException, InterruptedException { // Need to retry since there is a delay for the mesos DNS name to resolve correctly. @Cleanup final ControllerImpl controllerClient = new ControllerImpl(ControllerImplConfig.builder() .clientConfig(ClientConfig.builder() .controllerURI(controllerURI) .build()) .build(), executorService); CompletableFuture<Boolean> retryResult = Retry.withExpBackoff(500, 2, 10, 5000) .retryingOn(Exception.class) .throwingOn(IllegalArgumentException.class) .runAsync(() -> controllerClient.createScope(scopeName), executorService); return retryResult.get(); }
private CompletableFuture<Integer> retryFuture(final long delay, final int multiplier, final int attempts, final long maxDelay, final boolean success, final ScheduledExecutorService executorService) { loopCounter.set(0); accumulator.set(0); return Retry.withExpBackoff(delay, multiplier, attempts, maxDelay) .retryingOn(RetryableException.class) .throwingOn(NonretryableException.class) .runAsync(() -> futureComputation(success, executorService), executorService); }
@Override public void sealSegment() { val future = RETRY_SCHEDULE.retryingOn(ConnectionFailedException.class) .throwingOn(NoSuchSegmentException.class) .runAsync(() -> sealSegmentAsync(segmentId, delegationToken), connectionFactory.getInternalExecutor()); future.join(); }
@Override public void truncateSegment(long offset) { val future = RETRY_SCHEDULE.retryingOn(ConnectionFailedException.class) .throwingOn(NoSuchSegmentException.class) .runAsync(() -> truncateSegmentAsync(segmentId, offset, delegationToken), connectionFactory.getInternalExecutor()); future.join(); }
@Override public SegmentInfo getSegmentInfo() { val future = RETRY_SCHEDULE.retryingOn(ConnectionFailedException.class) .throwingOn(NoSuchSegmentException.class) .runAsync(() -> getStreamSegmentInfo(delegationToken), connectionFactory.getInternalExecutor()); StreamSegmentInfo info = Futures.getThrowingException(future); return new SegmentInfo(segmentId, info.getStartOffset(), info.getWriteOffset(), info.isSealed(), info.getLastModified()); }
@Override public boolean compareAndSetAttribute(SegmentAttribute attribute, long expectedValue, long newValue) { Exceptions.checkNotClosed(closed.get(), this); val future = RETRY_SCHEDULE.retryingOn(ConnectionFailedException.class) .throwingOn(NoSuchSegmentException.class) .runAsync(() -> updatePropertyAsync(attribute.getValue(), expectedValue, newValue, delegationToken), connectionFactory.getInternalExecutor()); return Futures.getThrowingException(future).isSuccess(); }
@Override public long fetchCurrentSegmentLength() { Exceptions.checkNotClosed(closed.get(), this); val future = RETRY_SCHEDULE.retryingOn(ConnectionFailedException.class) .throwingOn(NoSuchSegmentException.class) .runAsync(() -> getStreamSegmentInfo(delegationToken), connectionFactory.getInternalExecutor()); return Futures.getThrowingException(future).getWriteOffset(); }
@Override public long fetchProperty(SegmentAttribute attribute) { Exceptions.checkNotClosed(closed.get(), this); val future = RETRY_SCHEDULE.retryingOn(ConnectionFailedException.class) .throwingOn(NoSuchSegmentException.class) .runAsync(() -> getPropertyAsync(attribute.getValue(), delegationToken), connectionFactory.getInternalExecutor()); return Futures.getThrowingException(future).getValue(); }