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

org.apache.kafka.clients.consumer.internals.WakeupTrigger Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.kafka.clients.consumer.internals;

import org.apache.kafka.common.KafkaException;
import org.apache.kafka.common.errors.WakeupException;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Ensures blocking APIs can be woken up by the consumer.wakeup().
 */
public class WakeupTrigger {
    private final AtomicReference pendingTask = new AtomicReference<>(null);

    /**
     * Wakeup a pending task.  If there isn't any pending task, return a WakeupFuture, so that the subsequent call
     * would know wakeup was previously called.
     * 

* If there are active tasks, complete it with WakeupException, then unset pending task (return null here. * If the current task has already been woken-up, do nothing. */ public void wakeup() { pendingTask.getAndUpdate(task -> { if (task == null) { return new WakeupFuture(); } else if (task instanceof ActiveFuture) { ActiveFuture active = (ActiveFuture) task; boolean wasTriggered = active.future().completeExceptionally(new WakeupException()); // If the Future was *already* completed when we invoke completeExceptionally, the WakeupException // will be ignored. If it was already completed, we then need to return a new WakeupFuture so that the // next call to setActiveTask will throw the WakeupException. return wasTriggered ? null : new WakeupFuture(); } else if (task instanceof FetchAction) { FetchAction fetchAction = (FetchAction) task; fetchAction.fetchBuffer().wakeup(); return new WakeupFuture(); } else { return task; } }); } /** * If there is no pending task, set the pending task active. * If wakeup was called before setting an active task, the current task will complete exceptionally with * WakeupException right * away. * if there is an active task, throw exception. * @param currentTask * @param * @return */ public CompletableFuture setActiveTask(final CompletableFuture currentTask) { Objects.requireNonNull(currentTask, "currentTask cannot be null"); pendingTask.getAndUpdate(task -> { if (task == null) { return new ActiveFuture(currentTask); } else if (task instanceof WakeupFuture) { currentTask.completeExceptionally(new WakeupException()); return null; } else if (task instanceof DisabledWakeups) { return task; } // last active state is still active throw new KafkaException("Last active task is still active"); }); return currentTask; } public void setFetchAction(final FetchBuffer fetchBuffer) { final AtomicBoolean throwWakeupException = new AtomicBoolean(false); pendingTask.getAndUpdate(task -> { if (task == null) { return new FetchAction(fetchBuffer); } else if (task instanceof WakeupFuture) { throwWakeupException.set(true); return null; } else if (task instanceof DisabledWakeups) { return task; } // last active state is still active throw new IllegalStateException("Last active task is still active"); }); if (throwWakeupException.get()) { throw new WakeupException(); } } public void disableWakeups() { pendingTask.set(new DisabledWakeups()); } public void clearTask() { pendingTask.getAndUpdate(task -> { if (task == null) { return null; } else if (task instanceof ActiveFuture || task instanceof FetchAction) { return null; } return task; }); } public void maybeTriggerWakeup() { final AtomicBoolean throwWakeupException = new AtomicBoolean(false); pendingTask.getAndUpdate(task -> { if (task == null) { return null; } else if (task instanceof WakeupFuture) { throwWakeupException.set(true); return null; } else { return task; } }); if (throwWakeupException.get()) { throw new WakeupException(); } } Wakeupable getPendingTask() { return pendingTask.get(); } interface Wakeupable { } // Set to block wakeups from happening and pending actions to be registered. static class DisabledWakeups implements Wakeupable { } static class ActiveFuture implements Wakeupable { private final CompletableFuture future; public ActiveFuture(final CompletableFuture future) { this.future = future; } public CompletableFuture future() { return future; } } static class WakeupFuture implements Wakeupable { } static class FetchAction implements Wakeupable { private final FetchBuffer fetchBuffer; public FetchAction(FetchBuffer fetchBuffer) { this.fetchBuffer = fetchBuffer; } public FetchBuffer fetchBuffer() { return fetchBuffer; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy