/* * Copyright 2001-2008 Steven Grimm <koreth[remove] at midwinter dot com> * Licensed under the Apache License, Version 2.0 (the "License") * $Id: DbConnection.java 3442 2006-08-10 09:26:43Z gbevin $ */ package com.uwyn.rife.database; import com.uwyn.rife.database.exceptions.DbQueryException; import com.uwyn.rife.scheduler.Executor; import com.uwyn.rife.scheduler.Task; /** * Periodic probe job to keep connections non-idle and probe for dead ones. * This is primarily useful for MySQL, which closes connections after a * period of inactivity. * * <p>This should be run using a scheduler participant. For example, to * probe the "mysql" Datasource once a minute: * * <pre> <scheduler> * <task classname="com.uwyn.rife.database.DbProbeExecutor" * frequency="* * * * *"> * <option name="datasource">mysql</option> * <option name="query">select 1</option> * </task> * </scheduler></pre> * * <p>There are two optional parameters. * <dl> * <dt><code>datasource</code></dt> * <dd>The name of the Datasource to probe. If not specified, the * default is "datasource".</dd> * <dt><code>query</code></td> * <dd>The dummy query to send. If not specified, the default is * "select 1".</dd> * </dl> * @author Steven Grimm (koreth[remove] at midwinter dot com) * @version $Revision: $ * @since 1.6 */ public class DbProbeExecutor extends Executor { @Override public boolean executeTask(Task task) { try { String ds_name = task.getTaskoptionValue("datasource"); if (null == ds_name) { ds_name = "datasource"; } String query = task.getTaskoptionValue("query"); if (null == query) { query = "select 1"; } Datasource ds = Datasources.getRepInstance().getDatasource(ds_name); if (null == ds) { throw new DbQueryException("Can't find Datasource '" + ds_name + "'"); } ConnectionPool cp = ds.getPool(); if (null == cp) { throw new DbQueryException("Datasource '" + ds_name + "' has no ConnectionPool"); } /* * Now fetch all the connections that should be in the pool, * and run a dummy statement on each of them to keep it from * going idle. * * This relies on the fact that ConnectionPool returns * DbConnection objects in a round-robin fashion. We can just * fetch the next connection the appropriate number of times * and be guaranteed to hit all of them. * * If there are transactions active on other threads, we will * not be given those threads' DbConnection objects, so we * might end up being handed the same connection twice. No * harm in that, and any connection that has an active * transaction isn't idle anyway so doesn't need to be probed. */ synchronized (cp) { for (int i = 0; i < cp.getPoolsize(); i++) { DbConnection conn = ds.getConnection(); if (null == conn) { throw new DbQueryException("Can't get connection"); } DbPreparedStatement stmt = conn.getPreparedStatement(query); if (null == stmt) { throw new DbQueryException("Can't prepare dummy statement"); } try { /* * Probe the connection. If this fails, RIFE will remove * the connection from the pool automatically. */ stmt.executeQuery(); } finally { stmt.close(); conn.close(); } } } } catch (Exception e) { throw new DbQueryException("Can't probe MySQL connection", e); } return true; } @Override public String getHandledTasktype() { return "MySqlProbe"; } }