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

reactor.core.publisher.SinkManyUnicastNoBackpressure Maven / Gradle / Ivy

Go to download

Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC

There is a newer version: 3.40.2
Show newest version
/*
 * Copyright (c) 2020-2023 VMware Inc. or its affiliates, All Rights Reserved.
 *
 * 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
 *
 *   https://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 reactor.core.publisher;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.stream.Stream;

import org.reactivestreams.Subscription;

import reactor.core.CoreSubscriber;
import reactor.core.Scannable;
import reactor.core.publisher.Sinks.EmitResult;
import reactor.util.annotation.Nullable;
import reactor.util.context.Context;

final class SinkManyUnicastNoBackpressure extends Flux implements InternalManySink, Subscription, ContextHolder {

	public static  SinkManyUnicastNoBackpressure create() {
		return new SinkManyUnicastNoBackpressure<>();
	}

	enum State {
		INITIAL,
		SUBSCRIBED,
		TERMINATED,
		CANCELLED,
	}

	volatile State state;

	@SuppressWarnings("rawtypes")
	private static final AtomicReferenceFieldUpdater STATE = AtomicReferenceFieldUpdater.newUpdater(
			SinkManyUnicastNoBackpressure.class,
			State.class,
			"state"
	);

	private volatile CoreSubscriber actual = null;

	volatile long                                                      requested;
	@SuppressWarnings("rawtypes")
	static final AtomicLongFieldUpdater REQUESTED =
			AtomicLongFieldUpdater.newUpdater(SinkManyUnicastNoBackpressure.class, "requested");

	SinkManyUnicastNoBackpressure() {
		STATE.lazySet(this, State.INITIAL);
	}

	@Override
	public int currentSubscriberCount() {
		return state == State.SUBSCRIBED ? 1 : 0;
	}

	@Override
	public Flux asFlux() {
		return this;
	}

	@Override
	public void subscribe(CoreSubscriber actual) {
		Objects.requireNonNull(actual, "subscribe");

		CoreSubscriber wrapped =
				Operators.restoreContextOnSubscriberIfAutoCPEnabled(this, actual);

		if (!STATE.compareAndSet(this, State.INITIAL, State.SUBSCRIBED)) {
			Operators.reportThrowInSubscribe(wrapped, new IllegalStateException(
					"Unicast Sinks.Many allows only a single Subscriber"));
			return;
		}

		this.actual = wrapped;
		wrapped.onSubscribe(this);
	}

	@Override
	public void request(long n) {
		if (Operators.validate(n)) {
			Operators.addCap(REQUESTED, this, n);
		}
	}

	@Override
	public void cancel() {
		if (STATE.getAndSet(this, State.CANCELLED) == State.SUBSCRIBED) {
			actual = null;
		}
	}

	@Override
	public Context currentContext() {
		CoreSubscriber actual = this.actual;
		return actual != null ? actual.currentContext() : Context.empty();
	}

	@Override
	public Sinks.EmitResult tryEmitNext(T t) {
		Objects.requireNonNull(t, "t");

		switch (state) {
			case INITIAL:
				return Sinks.EmitResult.FAIL_ZERO_SUBSCRIBER;
			case SUBSCRIBED:
				if (requested == 0L) {
					return Sinks.EmitResult.FAIL_OVERFLOW;
				}

				actual.onNext(t);
				Operators.produced(REQUESTED, this, 1);
				return Sinks.EmitResult.OK;
			case TERMINATED:
				return Sinks.EmitResult.FAIL_TERMINATED;
			case CANCELLED:
				return Sinks.EmitResult.FAIL_CANCELLED;
			default:
				throw new IllegalStateException();
		}
	}

	@Override
	public EmitResult tryEmitError(Throwable t) {
		Objects.requireNonNull(t, "t");
		for(;;) { //for the benefit of retrying SUBSCRIBED
			State s = this.state;
			switch (s) {
				case INITIAL:
					return Sinks.EmitResult.FAIL_ZERO_SUBSCRIBER;
				case SUBSCRIBED:
					if (STATE.compareAndSet(this, s, State.TERMINATED)) {
						actual.onError(t);
						actual = null;
						return Sinks.EmitResult.OK;
					}
					continue;
				case TERMINATED:
					return Sinks.EmitResult.FAIL_TERMINATED;
				case CANCELLED:
					return Sinks.EmitResult.FAIL_CANCELLED;
				default:
					throw new IllegalStateException();
			}
		}
	}

	@Override
	public EmitResult tryEmitComplete() {
		for (;;) { //for the benefit of retrying SUBSCRIBED
			State s = this.state;
			switch (s) {
				case INITIAL:
					return Sinks.EmitResult.FAIL_ZERO_SUBSCRIBER;
				case SUBSCRIBED:
					if (STATE.compareAndSet(this, s, State.TERMINATED)) {
						actual.onComplete();
						actual = null;
						return EmitResult.OK;
					}
					continue;
				case TERMINATED:
					return Sinks.EmitResult.FAIL_TERMINATED;
				case CANCELLED:
					return Sinks.EmitResult.FAIL_CANCELLED;
				default:
					throw new IllegalStateException();
			}
		}
	}

	@Override
	public Stream inners() {
		CoreSubscriber a = actual;
		return a == null ? Stream.empty() : Stream.of(Scannable.from(a));
	}

	@Nullable
	@Override
	public Object scanUnsafe(Attr key) {
		if (key == Attr.ACTUAL) return actual;
		if (key == Attr.TERMINATED) return state == State.TERMINATED;
		if (key == Attr.CANCELLED) return state == State.CANCELLED;
		if (key == InternalProducerAttr.INSTANCE) return true;

		return null;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy