/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2010-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.rrd.tcp;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.rrd.RrdDataSource;
import org.opennms.netmgt.rrd.RrdGraphDetails;
import org.opennms.netmgt.rrd.RrdStrategy;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Provides a TCP socket-based implementation of RrdStrategy that pushes update commands
* out in a simple serialized format.
*
* @author ranger
* @version $Id: $
*/
public class QueuingTcpRrdStrategy implements RrdStrategy<TcpRrdStrategy.RrdDefinition,String> {
private final BlockingQueue<PerformanceDataReading> m_queue = new LinkedBlockingQueue<PerformanceDataReading>(50000);
private final ConsumerThread m_consumerThread;
private final TcpRrdStrategy m_delegate;
private int m_skippedReadings = 0;
private static class PerformanceDataReading {
private String m_filename;
private String m_owner;
private String m_data;
public PerformanceDataReading(String filename, String owner, String data) {
m_filename = filename;
m_owner = owner;
m_data = data;
}
public String getFilename() {
return m_filename;
}
public String getOwner() {
return m_owner;
}
public String getData() {
return m_data;
}
}
private static class ConsumerThread extends Thread {
private final BlockingQueue<PerformanceDataReading> m_myQueue;
private final TcpRrdStrategy m_strategy;
public ConsumerThread(final TcpRrdStrategy strategy, final BlockingQueue<PerformanceDataReading> queue) {
m_strategy = strategy;
m_myQueue = queue;
this.setName(this.getClass().getSimpleName());
}
public void run() {
try {
while (true) {
Collection<PerformanceDataReading> sendMe = new ArrayList<PerformanceDataReading>();
if (m_myQueue.drainTo(sendMe) > 0) {
RrdOutputSocket socket = new RrdOutputSocket(m_strategy.getHost(), m_strategy.getPort());
for (PerformanceDataReading reading : sendMe) {
socket.addData(reading.getFilename(), reading.getOwner(), reading.getData());
}
socket.writeData();
} else {
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
ThreadCategory.getInstance(this.getClass()).warn("InterruptedException caught in QueuingTcpRrdStrategy$ConsumerThread, closing thread");
} catch (Throwable e) {
ThreadCategory.getInstance(this.getClass()).fatal("Unexpected exception caught in QueuingTcpRrdStrategy$ConsumerThread, closing thread", e);
}
}
}
/**
* <p>Constructor for QueuingTcpRrdStrategy.</p>
*
* @param delegate a {@link org.opennms.netmgt.rrd.tcp.TcpRrdStrategy} object.
*/
public QueuingTcpRrdStrategy(TcpRrdStrategy delegate) {
m_delegate = delegate;
m_consumerThread = new ConsumerThread(delegate, m_queue);
m_consumerThread.start();
}
/** {@inheritDoc} */
public void setConfigurationProperties(Properties configurationParameters) {
m_delegate.setConfigurationProperties(configurationParameters);
}
/**
* <p>getDefaultFileExtension</p>
*
* @return a {@link java.lang.String} object.
*/
public String getDefaultFileExtension() {
return m_delegate.getDefaultFileExtension();
}
/** {@inheritDoc} */
public TcpRrdStrategy.RrdDefinition createDefinition(String creator, String directory, String rrdName, int step, List<RrdDataSource> dataSources, List<String> rraList) throws Exception {
return new TcpRrdStrategy.RrdDefinition(directory, rrdName);
}
/**
* <p>createFile</p>
*
* @param rrdDef a {@link org.opennms.netmgt.rrd.tcp.TcpRrdStrategy.RrdDefinition} object.
* @throws java.lang.Exception if any.
*/
public void createFile(TcpRrdStrategy.RrdDefinition rrdDef) throws Exception {
// Do nothing
}
/** {@inheritDoc} */
public String openFile(String fileName) throws Exception {
return fileName;
}
/** {@inheritDoc} */
public void updateFile(String fileName, String owner, String data) throws Exception {
if (m_queue.offer(new PerformanceDataReading(fileName, owner, data), 500, TimeUnit.MILLISECONDS)) {
if (m_skippedReadings > 0) {
ThreadCategory.getInstance().warn("Skipped " + m_skippedReadings + " performance data message(s) because of queue overflow");
m_skippedReadings = 0;
}
} else {
m_skippedReadings++;
}
}
/**
* <p>closeFile</p>
*
* @param rrd a {@link java.lang.String} object.
* @throws java.lang.Exception if any.
*/
public void closeFile(String rrd) throws Exception {
// Do nothing
}
/** {@inheritDoc} */
public Double fetchLastValue(String rrdFile, String ds, int interval) throws NumberFormatException {
return m_delegate.fetchLastValue(rrdFile, ds, interval);
}
/** {@inheritDoc} */
public Double fetchLastValue(String rrdFile, String ds, String consolidationFunction, int interval) throws NumberFormatException {
return m_delegate.fetchLastValue(rrdFile, ds, consolidationFunction, interval);
}
/** {@inheritDoc} */
public Double fetchLastValueInRange(String rrdFile, String ds, int interval, int range) throws NumberFormatException {
return m_delegate.fetchLastValueInRange(rrdFile, ds, interval, range);
}
/** {@inheritDoc} */
public InputStream createGraph(String command, File workDir) throws IOException {
return m_delegate.createGraph(command, workDir);
}
/** {@inheritDoc} */
public RrdGraphDetails createGraphReturnDetails(String command, File workDir) throws IOException {
return m_delegate.createGraphReturnDetails(command, workDir);
}
/**
* <p>getGraphLeftOffset</p>
*
* @return a int.
*/
public int getGraphLeftOffset() {
return m_delegate.getGraphLeftOffset();
}
/**
* <p>getGraphRightOffset</p>
*
* @return a int.
*/
public int getGraphRightOffset() {
return m_delegate.getGraphRightOffset();
}
/**
* <p>getGraphTopOffsetWithText</p>
*
* @return a int.
*/
public int getGraphTopOffsetWithText() {
return m_delegate.getGraphTopOffsetWithText();
}
/**
* <p>getStats</p>
*
* @return a {@link java.lang.String} object.
*/
public String getStats() {
return m_delegate.getStats();
}
/** {@inheritDoc} */
public void promoteEnqueuedFiles(Collection<String> rrdFiles) {
m_delegate.promoteEnqueuedFiles(rrdFiles);
}
}