com.aerospike.client.cluster.Pool Maven / Gradle / Ivy
Show all versions of aerospike-client-jdk8 Show documentation
/*
* Copyright 2012-2021 Aerospike, Inc.
*
* Portions may be licensed to Aerospike, Inc. under one or more contributor
* license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
*
* 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 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 com.aerospike.client.cluster;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
/**
* Concurrent bounded LIFO stack of connections.
*
* The standard library concurrent stack, ConcurrentLinkedDequeue, will not suffice
* because it's not bounded and it's size() method is too expensive.
*/
public final class Pool {
private final Connection[] conns;
private int head;
private int tail;
private int size;
final int minSize;
private final ReentrantLock lock;
final AtomicInteger total; // total connections: inUse + inPool
public Pool(int minSize, int maxSize) {
this.minSize = minSize;
conns = new Connection[maxSize];
lock = new ReentrantLock(false);
total = new AtomicInteger();
}
public int capacity() {
return conns.length;
}
/**
* Return number of connections that might be closed.
*/
public int excess() {
return total.get() - minSize;
}
/**
* Insert connection at head of stack.
*/
public boolean offer(Connection conn) {
if (conn == null) {
throw new NullPointerException();
}
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (size == conns.length) {
return false;
}
final Connection[] conns = this.conns;
conns[head] = conn;
if (++head == conns.length) {
head = 0;
}
size++;
return true;
}
finally {
lock.unlock();
}
}
/**
* Pop connection from head of stack.
*/
public Connection poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (size == 0) {
return null;
}
if (head == 0) {
head = conns.length - 1;
}
else {
head--;
}
size--;
final Connection[] conns = this.conns;
final Connection conn = conns[head];
conns[head] = null;
return conn;
}
finally {
lock.unlock();
}
}
/**
* Close connections that are idle for more than maxSocketIdle up to count.
*/
void closeIdle(Node node, int count) {
final Cluster cluster = node.cluster;
while (count > 0) {
// Lock on each iteration to give fairness to other
// threads polling for connections.
Connection conn;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (size == 0) {
return;
}
// The oldest connection is at tail.
final Connection[] conns = this.conns;
conn = conns[tail];
if (cluster.isConnCurrentTrim(conn.getLastUsed())) {
return;
}
conns[tail] = null;
if (++tail == conns.length) {
tail = 0;
}
size--;
}
finally {
lock.unlock();
}
// Close connection outside of lock.
closeIdle(node, conn);
count--;
}
}
void closeIdle(Node node, Connection conn) {
total.getAndDecrement();
node.closeIdleConnection(conn);
}
/**
* Return item count.
*/
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return size;
}
finally {
lock.unlock();
}
}
}