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

reactor.pool.SimpleLifoPool 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.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import reactor.core.publisher.Mono;

/**
 * This implementation is based on {@link java.util.concurrent.ConcurrentLinkedQueue} MPMC queue
 * for idle resources and a {@link ConcurrentLinkedDeque} for pending {@link Pool#acquire()}
 * Monos, used as a stack ({@link java.util.Deque#offerFirst(Object)},
 * {@link Deque#pollFirst()}. This results in serving pending borrowers in LIFO order.
 *
 * See {@link SimplePool} for other characteristics of the simple pool.
 *
 * @author Simon Baslé
 */
final class SimpleLifoPool extends SimplePool {

    private static final ConcurrentLinkedDeque TERMINATED = new ConcurrentLinkedDeque();

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

    public SimpleLifoPool(PoolConfig poolConfig) {
        super(poolConfig);
        this.pending = new ConcurrentLinkedDeque<>(); //unbounded
    }

    @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.offerFirst(pending); //unbounded
                return true;
            }
        }
    }

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

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

    @Override
    public Mono disposeLater() {
        return Mono.defer(() -> {
            @SuppressWarnings("unchecked")
            ConcurrentLinkedDeque> q = PENDING.getAndSet(this, TERMINATED);
            if (q != TERMINATED) {
                Borrower p;
                while((p = q.pollFirst()) != null) {
                    p.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