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

reactor.core.publisher.SinksSpecs 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-2022 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.time.Duration;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import reactor.core.Disposable;
import reactor.core.publisher.Sinks.Empty;
import reactor.core.publisher.Sinks.Many;
import reactor.core.publisher.Sinks.One;
import reactor.core.scheduler.Scheduler;
import reactor.util.concurrent.Queues;

final class SinksSpecs {

	static final Sinks.RootSpec  UNSAFE_ROOT_SPEC = new UnsafeSpecImpl();
	static final DefaultSinksSpecs DEFAULT_SINKS    = new DefaultSinksSpecs();

	abstract static class AbstractSerializedSink {

		volatile int                                                   wip;
		static final AtomicIntegerFieldUpdater WIP =
				AtomicIntegerFieldUpdater.newUpdater(AbstractSerializedSink.class, "wip");

		volatile Thread                                                          lockedAt;
		static final AtomicReferenceFieldUpdater LOCKED_AT =
				AtomicReferenceFieldUpdater.newUpdater(AbstractSerializedSink.class, Thread.class, "lockedAt");

		boolean tryAcquire(Thread currentThread) {
			if (WIP.get(this) == 0 && WIP.compareAndSet(this, 0, 1)) {
				// lazySet in thread A here is ok because:
				// 1. initial state is `null`
				// 2. `LOCKED_AT.get(this) != currentThread` from a different thread B could see outdated null or an outdated old thread
				// 3. but that old thread cannot be B: since we're in thread B, it must have executed the compareAndSet which would have loaded the update from A
				// 4. Seeing `null` or `C` is equivalent from seeing `A` from the perspective of the condition (`!= currentThread` is still true in all three cases)
				LOCKED_AT.lazySet(this, currentThread);
			}
			else {
				if (LOCKED_AT.get(this) != currentThread) {
					return false;
				}
				WIP.incrementAndGet(this);
			}
			return true;
		}
	}


	static final class UnsafeSpecImpl
		implements Sinks.RootSpec, Sinks.ManySpec, Sinks.ManyWithUpstreamUnsafeSpec, Sinks.MulticastSpec, Sinks.MulticastReplaySpec {

		final Sinks.UnicastSpec unicastSpec;

		UnsafeSpecImpl() {
			this.unicastSpec = new UnicastSpecImpl(false);
		}

		@Override
		public  Empty empty() {
			return new SinkEmptyMulticast<>();
		}

		@Override
		public  One one() {
			return new SinkOneMulticast<>();
		}

		@Override
		public Sinks.ManySpec many() {
			return this;
		}

		@Override
		public Sinks.UnicastSpec unicast() {
			return this.unicastSpec;
		}

		@Override
		public Sinks.MulticastSpec multicast() {
			return this;
		}

		@Override
		public Sinks.MulticastReplaySpec replay() {
			return this;
		}

		@Override
		public Sinks.ManyWithUpstreamUnsafeSpec manyWithUpstream() {
			return this;
		}

		@Override
		public  Sinks.Many onBackpressureBuffer() {
			return new SinkManyEmitterProcessor<>(true, Queues.SMALL_BUFFER_SIZE);
		}

		@Override
		public  Sinks.Many onBackpressureBuffer(int bufferSize) {
			return new SinkManyEmitterProcessor<>(true, bufferSize);
		}

		@Override
		public  Sinks.Many onBackpressureBuffer(int bufferSize, boolean autoCancel) {
			return new SinkManyEmitterProcessor<>(autoCancel, bufferSize);
		}

		@Override
		public  Many directAllOrNothing() {
			return new SinkManyBestEffort<>(true);
		}

		@Override
		public  Many directBestEffort() {
			return new SinkManyBestEffort<>(false);
		}

		@Override
		public  Many all() {
			return SinkManyReplayProcessor.create();
		}

		@Override
		public  Many all(int batchSize) {
			return SinkManyReplayProcessor.create(batchSize);
		}

		@Override
		public  Many latest() {
			return SinkManyReplayProcessor.cacheLast();
		}

		@Override
		public  Many latestOrDefault(T value) {
			return SinkManyReplayProcessor.cacheLastOrDefault(value);
		}

		@Override
		public  Many limit(int historySize) {
			return SinkManyReplayProcessor.create(historySize);
		}

		@Override
		public  Many limit(Duration maxAge) {
			return SinkManyReplayProcessor.createTimeout(maxAge);
		}

		@Override
		public  Many limit(Duration maxAge, Scheduler scheduler) {
			return SinkManyReplayProcessor.createTimeout(maxAge, scheduler);
		}

		@Override
		public  Many limit(int historySize, Duration maxAge) {
			return SinkManyReplayProcessor.createSizeAndTimeout(historySize, maxAge);
		}

		@Override
		public  Many limit(int historySize, Duration maxAge, Scheduler scheduler) {
			return SinkManyReplayProcessor.createSizeAndTimeout(historySize, maxAge, scheduler);
		}

		@Override
		public  Sinks.ManyWithUpstream multicastOnBackpressureBuffer() {
			return new SinkManyEmitterProcessor<>(true, Queues.SMALL_BUFFER_SIZE);
		}

		@Override
		public  Sinks.ManyWithUpstream multicastOnBackpressureBuffer(int bufferSize, boolean autoCancel) {
			return new SinkManyEmitterProcessor<>(autoCancel, bufferSize);
		}
	}

	//Note: RootSpec is now reserved for Sinks.unsafe()
	static final class DefaultSinksSpecs implements Sinks.ManySpec, Sinks.MulticastSpec, Sinks.MulticastReplaySpec {

		final Sinks.UnicastSpec unicastSpec; //needed because UnicastSpec method names overlap with MulticastSpec

		DefaultSinksSpecs() {
			//there will only one instance of serialized UnicastSpecImpl as there is only one instance of  SafeRootSpecImpl
			this.unicastSpec = new UnicastSpecImpl(true);
		}

		 & ContextHolder> Empty wrapEmpty(EMPTY original) {
			return new SinkEmptySerialized<>(original, original);
		}

		 & ContextHolder> One wrapOne(ONE original) {
			return new SinkOneSerialized<>(original, original);
		}

		 & ContextHolder> Many wrapMany(MANY original) {
			return new SinkManySerialized<>(original, original);
		}

		Sinks.ManySpec many() {
			return this;
		}

		 Empty empty() {
			return wrapEmpty(new SinkEmptyMulticast<>());
		}

		 One one() {
			return wrapOne(new SinkOneMulticast<>());
		}

		@Override
		public Sinks.UnicastSpec unicast() {
			return this.unicastSpec;
		}

		@Override
		public Sinks.MulticastSpec multicast() {
			return this;
		}

		@Override
		public Sinks.MulticastReplaySpec replay() {
			return this;
		}

		@Override
		public  Many onBackpressureBuffer() {
			return wrapMany(new SinkManyEmitterProcessor<>(true, Queues.SMALL_BUFFER_SIZE));
		}

		@Override
		public  Many onBackpressureBuffer(int bufferSize) {
			return wrapMany(new SinkManyEmitterProcessor<>(true, bufferSize));
		}

		@Override
		public  Many onBackpressureBuffer(int bufferSize, boolean autoCancel) {
			return wrapMany(new SinkManyEmitterProcessor<>(autoCancel, bufferSize));
		}

		@Override
		public  Many directAllOrNothing() {
			final SinkManyBestEffort original = SinkManyBestEffort.createAllOrNothing();
			return wrapMany(original);
		}

		@Override
		public  Many directBestEffort() {
			final SinkManyBestEffort original = SinkManyBestEffort.createBestEffort();
			return wrapMany(original);
		}


		@Override
		public  Many all() {
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.create();
			return wrapMany(original);
		}

		@Override
		public  Many all(int batchSize) {
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.create(batchSize, true);
			return wrapMany(original);
		}

		@Override
		public  Many latest() {
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.cacheLast();
			return wrapMany(original);
		}

		@Override
		public  Many latestOrDefault(T value) {
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.cacheLastOrDefault(value);
			return wrapMany(original);
		}

		@Override
		public  Many limit(int historySize) {
			if (historySize <= 0) {
				throw new IllegalArgumentException("historySize must be > 0");
			}
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.create(historySize);
			return wrapMany(original);
		}

		@Override
		public  Many limit(Duration maxAge) {
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.createTimeout(maxAge);
			return wrapMany(original);
		}

		@Override
		public  Many limit(Duration maxAge, Scheduler scheduler) {
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.createTimeout(maxAge, scheduler);
			return wrapMany(original);
		}

		@Override
		public  Many limit(int historySize, Duration maxAge) {
			if (historySize <= 0) {
				throw new IllegalArgumentException("historySize must be > 0");
			}
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.createSizeAndTimeout(historySize, maxAge);
			return wrapMany(original);
		}

		@Override
		public  Many limit(int historySize, Duration maxAge, Scheduler scheduler) {
			if (historySize <= 0) {
				throw new IllegalArgumentException("historySize must be > 0");
			}
			final SinkManyReplayProcessor original = SinkManyReplayProcessor.createSizeAndTimeout(historySize, maxAge, scheduler);
			return wrapMany(original);
		}
	}

	static final class UnicastSpecImpl implements Sinks.UnicastSpec {

		final boolean serialized;

		UnicastSpecImpl(boolean serialized) {
			this.serialized = serialized;
		}

		 & ContextHolder> Many wrapMany(MANY original) {
			if (serialized) {
				return new SinkManySerialized<>(original, original);
			}
			return original;
		}

		@Override
		public  Many onBackpressureBuffer() {
			final SinkManyUnicast original = SinkManyUnicast.create();
			return wrapMany(original);
		}

		@Override
		public  Many onBackpressureBuffer(Queue queue) {
			final SinkManyUnicast original = SinkManyUnicast.create(queue);
			return wrapMany(original);
		}

		@Override
		public  Many onBackpressureBuffer(Queue queue, Disposable endCallback) {
			final SinkManyUnicast original = SinkManyUnicast.create(queue, endCallback);
			return wrapMany(original);
		}

		@Override
		public  Many onBackpressureError() {
			final SinkManyUnicastNoBackpressure original = SinkManyUnicastNoBackpressure.create();
			return wrapMany(original);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy