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

reactor.pool.SimpleFifoPool Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
/*
 * Copyright (c) 2018-Present Pivotal Software Inc, 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.pool;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import reactor.core.publisher.Mono;
import reactor.util.concurrent.Queues;

/**
 * This implementation is based on MPMC queues for both idle resources and pending {@link Pool#acquire()} Monos,
 * resulting in serving pending borrowers in FIFO order.
 *
 * See {@link SimplePool} for other characteristics of the simple pool.
 *
 * @author Simon Baslé
 */
final class SimpleFifoPool extends SimplePool {

    private static final Queue TERMINATED = Queues.empty().get();

    volatile Queue>                                      pending;
    private static final AtomicReferenceFieldUpdater PENDING = AtomicReferenceFieldUpdater.newUpdater(
            SimpleFifoPool.class, Queue.class, "pending");

    public SimpleFifoPool(PoolConfig poolConfig) {
        super(poolConfig);
        this.pending = new ConcurrentLinkedQueue<>(); //unbounded MPMC
    }

    @Override
    boolean pendingOffer(Borrower pending) {
        int maxPending = poolConfig.maxPending();
        for (;;) {
            int currentPending = PENDING_COUNT.get(this);
            if (maxPending >= 0 && currentPending == maxPending) {
                pending.fail(new PoolAcquirePendingLimitException(maxPending));
                return false;
            }
            else if (PENDING_COUNT.compareAndSet(this, currentPending, currentPending + 1)) {
                this.pending.offer(pending); //unbounded
                return true;
            }
        }
    }

    @Override
    Borrower pendingPoll() {
        Queue> q = this.pending;
        Borrower b = q.poll();
        if (b != null) PENDING_COUNT.decrementAndGet(this);
        return b;
    }

    @Override
    void cancelAcquire(Borrower borrower) {
        if (!isDisposed()) { //ignore pool disposed
            Queue> q = this.pending;
            if (q.remove(borrower)) {
                PENDING_COUNT.decrementAndGet(this);
            }
        }
    }

    @Override
    public Mono disposeLater() {
        return Mono.defer(() -> {
            @SuppressWarnings("unchecked")
            Queue> q = PENDING.getAndSet(this, TERMINATED);
            if (q != TERMINATED) {
                while(!q.isEmpty()) {
                    q.poll().fail(new PoolShutdownException());
                }

                Mono destroyMonos = Mono.when();
                while (!elements.isEmpty()) {
                    destroyMonos = destroyMonos.and(destroyPoolable(elements.poll()));
                }
                return destroyMonos;
            }
            return Mono.empty();
        });
    }

    @Override
    public boolean isDisposed() {
        return PENDING.get(this) == TERMINATED;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy