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

io.ebean.datasource.pool.BusyConnectionBuffer Maven / Gradle / Ivy

package io.ebean.datasource.pool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;

/**
 * A buffer especially designed for Busy PooledConnections.
 * 

* All thread safety controlled externally (by PooledConnectionQueue). *

*

* It has a set of 'slots' and PooledConnections know which slot they went into * and this allows for fast addition and removal (by slotId without looping). * The capacity will increase on demand by the 'growBy' amount. *

* * @author rbygrave */ class BusyConnectionBuffer { private static final Logger logger = LoggerFactory.getLogger(BusyConnectionBuffer.class); private PooledConnection[] slots; private final int growBy; private int size; private int pos = -1; /** * Create the buffer with an initial capacity and fixed growBy. * We generally do not want the buffer to grow very often. * * @param capacity the initial capacity * @param growBy the fixed amount to grow the buffer by. */ protected BusyConnectionBuffer(int capacity, int growBy) { this.slots = new PooledConnection[capacity]; this.growBy = growBy; } /** * We can only grow (not shrink) the capacity. */ protected void setCapacity(int newCapacity) { if (newCapacity > slots.length) { PooledConnection[] current = this.slots; this.slots = new PooledConnection[newCapacity]; System.arraycopy(current, 0, this.slots, 0, current.length); } } public String toString() { return Arrays.toString(slots); } protected int getCapacity() { return slots.length; } protected int size() { return size; } protected boolean isEmpty() { return size == 0; } protected int add(PooledConnection pc) { if (size == slots.length) { // grow the capacity setCapacity(slots.length + growBy); } int slot = nextEmptySlot(); pc.setSlotId(slot); slots[slot] = pc; return ++size; } protected boolean remove(PooledConnection pc) { int slotId = pc.getSlotId(); if (slots[slotId] != pc) { PooledConnection heldBy = slots[slotId]; logger.warn("Failed to remove from slot[{}] PooledConnection[{}] - HeldBy[{}]", pc.getSlotId(), pc, heldBy); return false; } slots[slotId] = null; --size; return true; } /** * Collect the load statistics from all the busy connections. */ void collectStatistics(PooledConnectionStatistics.LoadValues values, boolean reset) { for (int i = 0; i < slots.length; i++) { if (slots[i] != null) { values.plus(slots[i].getStatistics().getValues(reset)); } } } /** * Close connections that should be considered leaked. */ void closeBusyConnections(long leakTimeMinutes) { long olderThanTime = System.currentTimeMillis() - (leakTimeMinutes * 60000); logger.debug("Closing busy connections using leakTimeMinutes {}", leakTimeMinutes); for (int i = 0; i < slots.length; i++) { if (slots[i] != null) { //tmp.add(slots[i]); PooledConnection pc = slots[i]; //noinspection StatementWithEmptyBody if (pc.isLongRunning() || pc.getLastUsedTime() > olderThanTime) { // PooledConnection has been used recently or // expected to be longRunning so not closing... } else { slots[i] = null; --size; closeBusyConnection(pc); } } } } private void closeBusyConnection(PooledConnection pc) { try { logger.warn("DataSourcePool closing busy connection? " + pc.getFullDescription()); System.out.println("CLOSING busy connection: " + pc.getFullDescription()); pc.closeConnectionFully(false); } catch (Exception ex) { // this should never actually happen logger.error("Error when closing potentially leaked connection " + pc.getDescription(), ex); } } /** * Returns information describing connections that are currently being used. */ String getBusyConnectionInformation(boolean toLogger) { if (toLogger) { logger.info("Dumping [{}] busy connections: (Use datasource.xxx.capturestacktrace=true ... to get stackTraces)", size()); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < slots.length; i++) { if (slots[i] != null) { PooledConnection pc = slots[i]; if (toLogger) { logger.info("Busy Connection - {}", pc.getFullDescription()); } else { sb.append(pc.getFullDescription()).append("\r\n"); } } } return sb.toString(); } /** * Return the position of the next empty slot. */ private int nextEmptySlot() { // search forward while (++pos < slots.length) { if (slots[pos] == null) { return pos; } } // search from beginning pos = -1; while (++pos < slots.length) { if (slots[pos] == null) { return pos; } } // not expecting this throw new RuntimeException("No Empty Slot Found?"); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy