use of org.zalando.nakadi.exceptions.InvalidCursorException in project nakadi by zalando.
the class CursorsService method resetCursors.
public void resetCursors(final String subscriptionId, final List<NakadiCursor> cursors) throws ServiceUnavailableException, NoSuchSubscriptionException, UnableProcessException, OperationTimeoutException, ZookeeperException, InternalNakadiException, NoSuchEventTypeException, InvalidCursorException {
final Subscription subscription = subscriptionRepository.getSubscription(subscriptionId);
validateCursorsBelongToSubscription(subscription, cursors);
for (final NakadiCursor cursor : cursors) {
cursor.checkStorageAvailability();
}
final Map<TopicRepository, List<NakadiCursor>> topicRepositories = cursors.stream().collect(Collectors.groupingBy(c -> timelineService.getTopicRepository(c.getTimeline())));
for (final Map.Entry<TopicRepository, List<NakadiCursor>> entry : topicRepositories.entrySet()) {
entry.getKey().validateReadCursors(entry.getValue());
}
final ZkSubscriptionClient zkClient = zkSubscriptionFactory.createClient(subscription, "subscription." + subscriptionId + ".reset_cursors");
// In case if subscription was never initialized - initialize it
zkClient.runLocked(() -> StartingState.initializeSubscriptionLocked(zkClient, subscription, timelineService, cursorConverter));
// add 1 second to commit timeout in order to give time to finish reset if there is uncommitted events
if (!cursors.isEmpty()) {
final long timeout = TimeUnit.SECONDS.toMillis(nakadiSettings.getDefaultCommitTimeoutSeconds()) + TimeUnit.SECONDS.toMillis(1);
zkClient.resetCursors(cursors.stream().map(cursorConverter::convertToNoToken).collect(Collectors.toList()), timeout);
}
}
use of org.zalando.nakadi.exceptions.InvalidCursorException in project nakadi by zalando.
the class MultiTimelineEventConsumer method readEvents.
@Override
public List<ConsumedEvent> readEvents() {
if (timelinesChanged.compareAndSet(true, false)) {
try {
onTimelinesChanged();
} catch (final NakadiException | InvalidCursorException ex) {
throw new NakadiRuntimeException(ex);
}
}
final List<ConsumedEvent> result = poll();
for (final ConsumedEvent event : result) {
final EventTypePartition etp = event.getPosition().getEventTypePartition();
latestOffsets.put(etp, event.getPosition());
final String border = borderOffsets.get(etp);
final boolean timelineBorderReached = null != border && border.compareTo(event.getPosition().getOffset()) <= 0;
if (timelineBorderReached) {
timelinesChanged.set(true);
}
}
return result;
}
use of org.zalando.nakadi.exceptions.InvalidCursorException in project nakadi by zalando.
the class VersionZeroConverter method convert.
@Override
public NakadiCursor convert(final String eventTypeStr, final Cursor cursor) throws InternalNakadiException, NoSuchEventTypeException, ServiceUnavailableException, InvalidCursorException {
final String offset = cursor.getOffset();
if (Cursor.BEFORE_OLDEST_OFFSET.equalsIgnoreCase(offset)) {
final Timeline timeline = timelineService.getActiveTimelinesOrdered(eventTypeStr).get(0);
return timelineService.getTopicRepository(timeline).loadPartitionStatistics(timeline, cursor.getPartition()).orElseThrow(() -> new InvalidCursorException(PARTITION_NOT_FOUND)).getBeforeFirst();
} else if (!NUMBERS_ONLY_PATTERN.matcher(offset).matches()) {
throw new InvalidCursorException(CursorError.INVALID_OFFSET, cursor);
}
final Timeline timeline = timelineService.getAllTimelinesOrdered(eventTypeStr).get(0);
if (offset.startsWith("-")) {
return NakadiCursor.of(timeline, cursor.getPartition(), cursor.getOffset());
} else {
return NakadiCursor.of(timeline, cursor.getPartition(), StringUtils.leftPad(cursor.getOffset(), VERSION_ZERO_MIN_OFFSET_LENGTH, '0'));
}
}
use of org.zalando.nakadi.exceptions.InvalidCursorException in project nakadi by zalando.
the class VersionZeroConverter method convertBatched.
public List<NakadiCursor> convertBatched(final List<SubscriptionCursorWithoutToken> cursors) throws InvalidCursorException, InternalNakadiException, NoSuchEventTypeException, ServiceUnavailableException {
final NakadiCursor[] result = new NakadiCursor[cursors.size()];
for (int idx = 0; idx < cursors.size(); ++idx) {
final SubscriptionCursorWithoutToken cursor = cursors.get(idx);
if (Cursor.BEFORE_OLDEST_OFFSET.equalsIgnoreCase(cursor.getOffset())) {
// Preform begin checks afterwards to optimize calls
continue;
}
if (!NUMBERS_ONLY_PATTERN.matcher(cursor.getOffset()).matches()) {
throw new InvalidCursorException(CursorError.INVALID_OFFSET, cursor);
}
}
// now it is time for massive convert.
final LinkedHashMap<SubscriptionCursorWithoutToken, NakadiCursor> beginsToConvert = new LinkedHashMap<>();
final Map<SubscriptionCursorWithoutToken, Timeline> cursorTimelines = new HashMap<>();
final Map<TopicRepository, List<SubscriptionCursorWithoutToken>> repos = new HashMap<>();
for (int i = 0; i < result.length; ++i) {
if (null == result[i]) {
// cursor requires database hit
final SubscriptionCursorWithoutToken cursor = cursors.get(i);
final Timeline timeline = timelineService.getActiveTimelinesOrdered(cursor.getEventType()).get(0);
final TopicRepository topicRepo = timelineService.getTopicRepository(timeline);
beginsToConvert.put(cursor, null);
cursorTimelines.put(cursor, timeline);
repos.computeIfAbsent(topicRepo, k -> new ArrayList<>()).add(cursor);
}
}
for (final Map.Entry<TopicRepository, List<SubscriptionCursorWithoutToken>> entry : repos.entrySet()) {
final List<Optional<PartitionStatistics>> stats = entry.getKey().loadPartitionStatistics(entry.getValue().stream().map(scwt -> new TopicRepository.TimelinePartition(cursorTimelines.get(scwt), scwt.getPartition())).collect(Collectors.toList()));
for (int idx = 0; idx < entry.getValue().size(); ++idx) {
// Reinsert doesn't change the order
beginsToConvert.put(entry.getValue().get(idx), stats.get(idx).orElseThrow(() -> new InvalidCursorException(PARTITION_NOT_FOUND)).getBeforeFirst());
}
}
final Iterator<NakadiCursor> missingBegins = beginsToConvert.values().iterator();
return Stream.of(result).map(it -> null == it ? missingBegins.next() : it).collect(Collectors.toList());
}
use of org.zalando.nakadi.exceptions.InvalidCursorException in project nakadi by zalando.
the class VersionOneConverter method findCorrectTimelinedCursor.
private NakadiCursor findCorrectTimelinedCursor(final String eventType, final int order, final String partition, final String offset) throws InternalNakadiException, NoSuchEventTypeException, InvalidCursorException {
final List<Timeline> timelines = eventTypeCache.getTimelinesOrdered(eventType);
final Iterator<Timeline> timelineIterator = timelines.iterator();
Timeline timeline = null;
while (timelineIterator.hasNext()) {
final Timeline t = timelineIterator.next();
if (t.getOrder() == order) {
timeline = t;
break;
}
}
if (null == timeline) {
throw new InvalidCursorException(CursorError.UNAVAILABLE);
}
NakadiCursor cursor = NakadiCursor.of(timeline, partition, offset);
while (cursor.isLast()) {
// Will not check this call, because latest offset is not set for last timeline
timeline = timelineIterator.next();
cursor = NakadiCursor.of(timeline, partition, StaticStorageWorkerFactory.get(timeline).getBeforeFirstOffset());
}
return cursor;
}
Aggregations