/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2012, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This 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 software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.apmrouter.destination.incrementors; import java.sql.Connection; import java.sql.PreparedStatement; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import javax.sql.DataSource; import org.helios.apmrouter.metric.IMetric; import org.helios.apmrouter.metric.MetricType; import org.helios.apmrouter.server.ServerComponentBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jmx.export.annotation.ManagedAttribute; /** * <p>Title: IncrementorDestination</p> * <p>Description: Destination for handling incrementors</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.destination.incrementors.IncrementorDestination</code></p> */ public class IncrementorDestination extends ServerComponentBean implements Runnable { /** The H2 data source */ protected DataSource dataSource = null; /** The H2 connection */ protected Connection conn = null; /** The H2 prepared statement for increments */ protected PreparedStatement psIncrements = null; /** The H2 prepared statement for interval increments */ protected PreparedStatement psInterIncrements = null; /** The queue size */ protected int queueSize = 1000; /** The queue */ protected BlockingQueue<IMetric> queue; /** The queue processing thread */ protected Thread incrementProcessorThread = null; /** The keep running flag */ protected boolean keepRunning = false; /** * Creates a new IncrementorDestination */ public IncrementorDestination() { } /** * {@inheritDoc} * @see org.helios.apmrouter.destination.BaseDestination#doStart() */ protected void doStart() throws Exception { conn = dataSource.getConnection(); psIncrements = conn.prepareStatement("UPDATE INCREMENTOR SET INC_VALUE = INC_VALUE + ?, LAST_INC = CURRENT_TIMESTAMP WHERE METRIC_ID = ?"); psInterIncrements = conn.prepareStatement("UPDATE INTER_INCREMENTOR SET INC_VALUE = INC_VALUE + ?, LAST_INC = CURRENT_TIMESTAMP WHERE METRIC_ID = ?"); queue = new ArrayBlockingQueue<IMetric>(queueSize, false); incrementProcessorThread = new Thread(this, "IncrementProcessorThread"); incrementProcessorThread.setDaemon(true); keepRunning = true; incrementProcessorThread.start(); } /** * {@inheritDoc} * @see java.lang.Runnable#run() */ @Override public void run() { while(keepRunning) { try { IMetric metric = queue.poll(5000, TimeUnit.MILLISECONDS); if(metric!=null) { PreparedStatement ps = MetricType.INCREMENTOR==metric.getType() ? psIncrements : psInterIncrements; ps.setLong(1, metric.getLongValue()); ps.setLong(2, metric.getToken()); if(ps.executeUpdate()<1) { incr("FailedUpdates"); } } } catch (InterruptedException iex) { if(keepRunning) { Thread.interrupted(); } } catch (Exception ex) { incr("FailedUpdates"); error("Increment failed", ex); } } } /** * Adds the passed metric to the increment update queue * @param routable The metric to queue */ public void queue(IMetric routable) { try { if(!queue.offer(routable)) { incr("DroppedUpdates"); } } catch (Exception ex) { incr("DroppedUpdates"); } } /** * Sets the H2 datasource * @param dataSource the dataSource to set */ @Autowired(required=true) public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } @Override public Set<String> getSupportedMetricNames() { Set<String> _metrics = new HashSet<String>(super.getSupportedMetricNames()); _metrics.add("FailedUpdates"); _metrics.add("DroppedUpdates"); _metrics.add("CompletedUpdates"); return _metrics; } /** * Returns the incrementor update initial queue size * @return the incrementor update initial queue size */ @ManagedAttribute(description="The incrementor update initial queue size") public int getQueueSize() { return queueSize; } /** * Sets the incrementor update initial queue size * @param queueSize the incrementor update initial queue size */ public void setQueueSize(int queueSize) { this.queueSize = queueSize; } }