use of io.pravega.shared.controller.event.UpdateReaderGroupEvent in project pravega by pravega.
the class UpdateReaderGroupTask method execute.
@Override
public CompletableFuture<Void> execute(final UpdateReaderGroupEvent request) {
String scope = request.getScope();
String readerGroup = request.getRgName();
long requestId = request.getRequestId();
long generation = request.getGeneration();
UUID readerGroupId = request.getReaderGroupId();
boolean isTransition = request.isTransitionToFromSubscriber();
ImmutableSet<String> streamsToBeUnsubscribed = request.getRemoveStreams();
final OperationContext context = streamMetadataStore.createRGContext(scope, readerGroup, requestId);
return RetryHelper.withRetriesAsync(() -> streamMetadataStore.getReaderGroupId(scope, readerGroup, context, executor).thenCompose(id -> {
if (!id.equals(readerGroupId)) {
log.warn(requestId, "Skipping processing of Reader Group update request {} as UUID did not match.", requestId);
return CompletableFuture.completedFuture(null);
}
return streamMetadataStore.getReaderGroupConfigRecord(scope, readerGroup, context, executor).thenCompose(rgConfigRecord -> {
if (rgConfigRecord.getObject().getGeneration() != generation) {
log.warn(requestId, "Skipping processing of Reader Group update request as generation did not match.");
return CompletableFuture.completedFuture(null);
}
if (rgConfigRecord.getObject().isUpdating()) {
if (isTransition) {
// update Stream metadata tables, only if RG is a Subscriber
Iterator<String> streamIter = rgConfigRecord.getObject().getStartingStreamCuts().keySet().iterator();
String scopedRGName = NameUtils.getScopedReaderGroupName(scope, readerGroup);
Iterator<String> removeStreamsIter = streamsToBeUnsubscribed.stream().iterator();
return Futures.loop(removeStreamsIter::hasNext, () -> {
Stream stream = Stream.of(removeStreamsIter.next());
return streamMetadataStore.deleteSubscriber(stream.getScope(), stream.getStreamName(), scopedRGName, rgConfigRecord.getObject().getGeneration(), context, executor);
}, executor).thenCompose(v -> {
// updated config suggests this is a subscriber RG so addSubscriber
if (!ReaderGroupConfig.StreamDataRetention.NONE.equals(ReaderGroupConfig.StreamDataRetention.values()[rgConfigRecord.getObject().getRetentionTypeOrdinal()])) {
return Futures.loop(streamIter::hasNext, () -> {
Stream stream = Stream.of(streamIter.next());
return streamMetadataStore.addSubscriber(stream.getScope(), stream.getStreamName(), scopedRGName, rgConfigRecord.getObject().getGeneration(), context, executor);
}, executor);
}
return CompletableFuture.completedFuture(null);
}).thenCompose(v -> streamMetadataStore.completeRGConfigUpdate(scope, readerGroup, rgConfigRecord, context, executor));
}
// We get here for non-transition updates
return streamMetadataStore.completeRGConfigUpdate(scope, readerGroup, rgConfigRecord, context, executor);
}
return CompletableFuture.completedFuture(null);
});
}), UPDATE_RETRY_PREDICATE, Integer.MAX_VALUE, executor);
}
use of io.pravega.shared.controller.event.UpdateReaderGroupEvent in project pravega by pravega.
the class StreamMetadataTasksTest method readerGroupFailureTests.
@Test(timeout = 30000)
public void readerGroupFailureTests() throws InterruptedException {
WriterMock requestEventWriter = new WriterMock(streamMetadataTasks, executor);
streamMetadataTasks.setRequestEventWriter(requestEventWriter);
UpdateReaderGroupEvent badUpdateEvent = new UpdateReaderGroupEvent(SCOPE, "rg3", 2L, UUID.randomUUID(), 0L, false, ImmutableSet.of());
requestEventWriter.writeEvent(badUpdateEvent);
AssertExtensions.assertFutureThrows("DataNotFoundException", processFailingEvent(requestEventWriter), e -> Exceptions.unwrap(e) instanceof StoreException.DataNotFoundException);
String scopedStreamName = "scope/stream";
ReaderGroupConfig rgConf = ReaderGroupConfig.builder().disableAutomaticCheckpoints().stream(scopedStreamName).retentionType(ReaderGroupConfig.StreamDataRetention.NONE).build();
CreateReaderGroupEvent badCreateEvent = buildCreateRGEvent(SCOPE, "rg", rgConf, 1L, System.currentTimeMillis());
requestEventWriter.writeEvent(badCreateEvent);
AssertExtensions.assertFutureThrows("DataNotFoundException", processFailingEvent(requestEventWriter), e -> Exceptions.unwrap(e) instanceof StoreException.DataNotFoundException);
DeleteReaderGroupEvent badDeleteEvent = new DeleteReaderGroupEvent(SCOPE, "rg3", 1L, UUID.randomUUID());
requestEventWriter.writeEvent(badDeleteEvent);
AssertExtensions.assertFutureThrows("DataNotFoundException", processFailingEvent(requestEventWriter), e -> Exceptions.unwrap(e) instanceof StoreException.DataNotFoundException);
}
use of io.pravega.shared.controller.event.UpdateReaderGroupEvent in project pravega by pravega.
the class StreamMetadataTasks method updateReaderGroup.
/**
* Update Reader Group Configuration.
*
* @param scope Reader Group scope.
* @param rgName Reader Group name.
* @param config New Reader Group config.
* @param requestId request id.
* @return updation status.
*/
public CompletableFuture<UpdateReaderGroupResponse> updateReaderGroup(final String scope, final String rgName, final ReaderGroupConfig config, long requestId) {
final OperationContext context = streamMetadataStore.createRGContext(scope, rgName, requestId);
return RetryHelper.withRetriesAsync(() -> {
// 1. check if Reader Group exists...
return streamMetadataStore.checkReaderGroupExists(scope, rgName, context, executor).thenCompose(exists -> {
if (!exists) {
UpdateReaderGroupResponse response = UpdateReaderGroupResponse.newBuilder().setStatus(UpdateReaderGroupResponse.Status.RG_NOT_FOUND).setGeneration(config.getGeneration()).build();
return CompletableFuture.completedFuture(response);
}
// 2. check for generation && ID match with existing config
return streamMetadataStore.getReaderGroupConfigRecord(scope, rgName, context, executor).thenCompose(rgConfigRecord -> {
if (rgConfigRecord.getObject().getGeneration() != config.getGeneration()) {
UpdateReaderGroupResponse response = UpdateReaderGroupResponse.newBuilder().setStatus(UpdateReaderGroupResponse.Status.INVALID_CONFIG).setGeneration(config.getGeneration()).build();
return CompletableFuture.completedFuture(response);
}
if (!rgConfigRecord.getObject().isUpdating()) {
return streamMetadataStore.getReaderGroupId(scope, rgName, context, executor).thenCompose(rgId -> {
if (!config.getReaderGroupId().equals(rgId)) {
UpdateReaderGroupResponse response = UpdateReaderGroupResponse.newBuilder().setStatus(UpdateReaderGroupResponse.Status.INVALID_CONFIG).setGeneration(config.getGeneration()).build();
return CompletableFuture.completedFuture(response);
}
ImmutableSet<String> removeStreams = getStreamsToBeUnsubscribed(rgConfigRecord.getObject(), config);
boolean isTransition = isTransitionToOrFromSubscriber(rgConfigRecord.getObject(), config);
UpdateReaderGroupEvent event = new UpdateReaderGroupEvent(scope, rgName, requestId, rgId, rgConfigRecord.getObject().getGeneration() + 1, isTransition, removeStreams);
// 3. Create Reader Group Metadata and submit event
return eventHelperFuture.thenCompose(eventHelper -> eventHelper.addIndexAndSubmitTask(event, () -> streamMetadataStore.startRGConfigUpdate(scope, rgName, config, context, executor)).thenCompose(x -> eventHelper.checkDone(() -> isRGUpdated(scope, rgName, executor, context)).thenCompose(y -> streamMetadataStore.getReaderGroupConfigRecord(scope, rgName, context, executor).thenApply(configRecord -> {
UpdateReaderGroupResponse response = UpdateReaderGroupResponse.newBuilder().setStatus(UpdateReaderGroupResponse.Status.SUCCESS).setGeneration(configRecord.getObject().getGeneration()).build();
return response;
}))));
});
} else {
log.error(requestId, "Reader group config update failed as another update was in progress.");
UpdateReaderGroupResponse response = UpdateReaderGroupResponse.newBuilder().setStatus(UpdateReaderGroupResponse.Status.FAILURE).setGeneration(config.getGeneration()).build();
return CompletableFuture.completedFuture(response);
}
});
});
}, e -> Exceptions.unwrap(e) instanceof RetryableException, READER_GROUP_OPERATION_MAX_RETRIES, executor);
}
Aggregations