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

org.tentackle.dbms.ManagedConnectionMonitor Maven / Gradle / Ivy

There is a newer version: 21.16.1.0
Show newest version
/*
 * Tentackle - https://tentackle.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.tentackle.dbms;

import org.tentackle.common.Constants;
import org.tentackle.common.InterruptedRuntimeException;
import org.tentackle.common.Service;
import org.tentackle.common.ServiceFactory;
import org.tentackle.log.Logger;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


interface ManagedConnectionMonitorHolder {
  ManagedConnectionMonitor INSTANCE = createAndStartMonitor();

  private static ManagedConnectionMonitor createAndStartMonitor() {
    ManagedConnectionMonitor monitor = ServiceFactory.createService(ManagedConnectionMonitor.class, ManagedConnectionMonitor.class);
    monitor.start();
    return monitor;
  }
}


/**
 * Maintains a set of all open managed connections.
* The connections are held by a weak reference and the set is cleaned up once a minute.
* Optionally, idle connections with {@link ManagedConnection#isConnectionVerificationNecessary()} {@code == true} * will be verified (via dummy selects) periodically and to prevent premature closing by the database backend. * This is especially useful for databases running in the cloud, where the idle connection interval * cannot be deactivated or made longer than the idle times maintained by the {@link MpxConnectionManager}. *

* Notice: the monitor thread never stops! It is started when first referenced by * {@link ManagedConnectionMonitor#getInstance()}. */ @Service(ManagedConnectionMonitor.class) // defaults to self public class ManagedConnectionMonitor extends Thread { /** * Gets the running monitor thread. * * @return the thread (singleton) */ public static ManagedConnectionMonitor getInstance() { return ManagedConnectionMonitorHolder.INSTANCE; } private static boolean running; /** * Returns whether the monitor is running.
* Useful to avoid {@link #getInstance()} since this will start it, if not running yet. * * @return true if running, false if no {@link ManagedConnection}s created ever (remote server, for example) */ public static synchronized boolean isRunning() { return running; } private static synchronized void started() { running = true; } private static final Logger LOG = Logger.get(ManagedConnectionMonitor.class); private static final int WARN_CONNECTIONS_CLOSE_COUNT = 600; // warning level for excessive connection consumption private static final int INFO_CONNECTIONS_CLOSE_COUNT = 60; // info level for excessive connection consumption private static final String LOG_MESSAGE = "{0} managed connections closed within the last minute"; private final Set> managedConnections; // weak set! /** * Creates the monitor thread. */ public ManagedConnectionMonitor() { super("Managed Connection Monitor"); setDaemon(true); managedConnections = ConcurrentHashMap.newKeySet(); } /** * Registers a managed connection. * * @param managedConnection the managed connection */ public void registerManagedConnection(ManagedConnection managedConnection) { managedConnections.add(new WeakReference<>(managedConnection)); } /** * Gets a list of all open managed connections. * * @return the open connections */ public Collection getManagedConnections() { List openConnections = new ArrayList<>(); for (WeakReference managedConnectionRef : managedConnections) { ManagedConnection managedConnection = managedConnectionRef.get(); if (managedConnection != null && !managedConnection.isClosed()) { openConnections.add(managedConnection); } // we don't clean up here! this is done once a minute below... } return openConnections; } @Override public void run() { started(); LOG.info("{0} started", getName()); for (;;) { // loops forever try { pause(); loop(); } catch (RuntimeException rx) { LOG.severe("verification failed -> keep on running...", rx); } } } /** * Pauses the thread between loop runs. */ protected void pause() { try { sleep(Constants.MINUTE_MS); } catch (InterruptedException e) { throw new InterruptedRuntimeException(e); } } /** * A single loop run. */ protected void loop() { long currentTimeMillis = System.currentTimeMillis(); int closeCount = 0; for (Iterator> iter = managedConnections.iterator(); iter.hasNext(); ) { ManagedConnection managedConnection = iter.next().get(); if (managedConnection == null || managedConnection.isClosed()) { iter.remove(); closeCount++; } else { inspect(managedConnection, currentTimeMillis); } } if (closeCount >= WARN_CONNECTIONS_CLOSE_COUNT) { LOG.warning(LOG_MESSAGE, closeCount); } else if (closeCount >= INFO_CONNECTIONS_CLOSE_COUNT) { LOG.info(LOG_MESSAGE, closeCount); } else { LOG.fine(LOG_MESSAGE, closeCount); } } /** * Inspects the idle connection. * * @param managedConnection the connection * @param currentTimeMillis the current epochal time */ protected void inspect(ManagedConnection managedConnection, long currentTimeMillis) { if (managedConnection.isConnectionKeepAliveEnabled() && managedConnection.isConnectionVerificationNecessary(currentTimeMillis) && currentTimeMillis - managedConnection.getLastVerified() >= managedConnection.getConnectionInactivityTimeoutMs()) { if (managedConnection.verifyConnection()) { LOG.fine("{0} verified", managedConnection); } // else marked DEAD! -> will be cleaned up when used again } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy