All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.streamnative.pulsar.handlers.kop.PendingTopicFutures Maven / Gradle / Ivy

There is a newer version: 3.3.1.5
Show newest version
/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.streamnative.pulsar.handlers.kop;

import com.google.common.annotations.VisibleForTesting;
import io.streamnative.pulsar.handlers.kop.storage.PartitionLog;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import lombok.Getter;
import lombok.NonNull;

/**
 * Pending futures of PersistentTopic.
 * It's used when multiple produce requests encountered while the partition's PersistentTopic was not available.
 */
public class PendingTopicFutures {

    private int count = 0;
    private CompletableFuture currentTopicFuture;

    public PendingTopicFutures() {}


    private synchronized void decrementCount() {
        count--;
    }

    public synchronized void addListener(CompletableFuture topicFuture,
                            @NonNull Consumer persistentTopicConsumer,
                            @NonNull Consumer exceptionConsumer) {
        if (count == 0) {
            count = 1;
            // The first pending future comes
            currentTopicFuture = topicFuture.thenApply(persistentTopic -> {
                persistentTopicConsumer.accept(persistentTopic);
                decrementCount();
                return TopicThrowablePair.withTopic(persistentTopic);
            }).exceptionally(e -> {
                exceptionConsumer.accept(e.getCause());
                decrementCount();
                return TopicThrowablePair.withThrowable(e.getCause());
            });
        } else {
            count++;
            // The next pending future reuses the completed result of the previous topic future
            currentTopicFuture = currentTopicFuture.thenApply(topicThrowablePair -> {
                if (topicThrowablePair.getThrowable() == null) {
                    persistentTopicConsumer.accept(topicThrowablePair.getPersistentTopicOpt());
                } else {
                    exceptionConsumer.accept(topicThrowablePair.getThrowable());
                }
                decrementCount();
                return topicThrowablePair;
            }).exceptionally(e -> {
                exceptionConsumer.accept(e.getCause());
                decrementCount();
                return TopicThrowablePair.withThrowable(e.getCause());
            });
        }
    }

    @VisibleForTesting
    public synchronized int waitAndGetSize() throws ExecutionException, InterruptedException {
        currentTopicFuture.get();
        return count;
    }

    @VisibleForTesting
    public synchronized int size() {
        return count;
    }
}

class TopicThrowablePair {
    @Getter
    private final PartitionLog persistentTopicOpt;
    @Getter
    private final Throwable throwable;

    public static TopicThrowablePair withTopic(final PartitionLog persistentTopicOpt) {
        return new TopicThrowablePair(persistentTopicOpt, null);
    }

    public static TopicThrowablePair withThrowable(final Throwable throwable) {
        return new TopicThrowablePair(null, throwable);
    }

    private TopicThrowablePair(final PartitionLog persistentTopicOpt, final Throwable throwable) {
        this.persistentTopicOpt = persistentTopicOpt;
        this.throwable = throwable;
    }
};




© 2015 - 2024 Weber Informatics LLC | Privacy Policy