/**
* Copyright 2014 SAP AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.spotter.ext.measurement.database;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.concurrent.Future;
import javax.net.ssl.HostnameVerifier;
import org.aim.api.exceptions.MeasurementException;
import org.aim.api.measurement.MeasurementData;
import org.aim.api.measurement.collector.AbstractDataSource;
import org.aim.api.measurement.collector.CollectorFactory;
import org.aim.artifacts.measurement.collector.FileDataSource;
import org.aim.artifacts.records.DBStatisticsRecrod;
import org.aim.description.InstrumentationDescription;
import org.aim.description.sampling.SamplingDescription;
import org.lpe.common.config.GlobalConfiguration;
import org.lpe.common.extension.IExtension;
import org.lpe.common.util.system.LpeSystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spotter.core.measurement.AbstractMeasurementAdapter;
/**
* Measurement adapter for sampling status of a Database Server. TODO: this
* class is specific
*
* @author Alexander Wert
*
*/
public class DBMSMeasurement extends AbstractMeasurementAdapter implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(DBMSMeasurement.class);
public static Integer instanceId = 1;
private AbstractDataSource dataSource;
private Future<?> measurementTask;
private Connection jdbcConnection;
private PreparedStatement sqlStatement;
private boolean running;
private boolean samplerActivated = false;
private long delay;
private String mySQLHost;
private String mySQLPort;
private String mySQLUser;
private String mySQLPW;
private String mySQLdatabase;
protected static final long DEFAULT_DELAY = 500;
/**
* Query string for Database MS status. TODO: it is specific yet,
* externalize
*/
private static final String SQL_QUERY = "SHOW STATUS WHERE Variable_name like "
+ "'Innodb_row_lock_waits' OR Variable_name like 'Queries' OR "
+ "Variable_name like 'Innodb_row_lock_time';";
/**
* Constructor.
*
* @param provider
* extension provider
*/
public DBMSMeasurement(IExtension<?> provider) {
super(provider);
}
@Override
public void enableMonitoring() throws MeasurementException {
if (samplerActivated) {
try {
String dbConnectionString = "jdbc:mysql://" + mySQLHost + ":"+ mySQLPort + "/" + mySQLdatabase;
jdbcConnection = DriverManager.getConnection(dbConnectionString,mySQLUser,mySQLPW);
sqlStatement = jdbcConnection.prepareStatement(SQL_QUERY);
} catch (Exception e) {
throw new RuntimeException(e);
}
measurementTask = LpeSystemUtils.submitTask(this);
}
}
@Override
public void disableMonitoring() throws MeasurementException {
if (samplerActivated) {
try {
running = false;
measurementTask.get();
if (sqlStatement != null) {
sqlStatement.close();
}
if (jdbcConnection != null) {
jdbcConnection.close();
}
} catch (Exception e) {
throw new MeasurementException(e);
}
}
}
@Override
public MeasurementData getMeasurementData() throws MeasurementException {
if (samplerActivated) {
return dataSource.read();
}
return new MeasurementData();
}
@Override
public void pipeToOutputStream(OutputStream oStream) throws MeasurementException {
if (samplerActivated) {
dataSource.pipeToOutputStream(oStream);
} else {
try {
oStream.close();
} catch (IOException e) {
throw new MeasurementException(e);
}
}
}
@Override
public void initialize() throws MeasurementException {
mySQLHost = getProperties().getProperty(DBMSMeasurementExtension.HOST);
mySQLPort = getProperties().getProperty(DBMSMeasurementExtension.PORT);
mySQLUser = getProperties().getProperty(DBMSMeasurementExtension.USER);
mySQLPW= getProperties().getProperty(DBMSMeasurementExtension.PASSWORD);
mySQLdatabase = getProperties().getProperty(DBMSMeasurementExtension.DATABASE);
Properties collectorProperties = GlobalConfiguration.getInstance().getProperties();
synchronized (instanceId) {
collectorProperties.setProperty(FileDataSource.ADDITIONAL_FILE_PREFIX_KEY, "MySQLSampler-" + instanceId);
instanceId++;
}
dataSource = CollectorFactory.createDataSource(FileDataSource.class.getName(), collectorProperties);
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public long getCurrentTime() {
return System.currentTimeMillis();
}
@Override
public void run() {
running = true;
try {
dataSource.enable();
long counter = 0;
while (running) {
sampleMySQLStatistics(counter);
counter++;
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
LOGGER.debug("Sleeptime interrupted.");
running = false;
}
}
dataSource.disable();
} catch (MeasurementException e) {
throw new RuntimeException(e);
}
}
private void sampleMySQLStatistics(long ownNumQueries) {
try {
ResultSet resultSet = sqlStatement.executeQuery();
String name = "";
long numQueueries = 0;
long numLockWaits = 0;
long lockTime = 0;
while (resultSet.next()) {
name = resultSet.getString("Variable_name");
if ("Queries".equals(name)) {
numQueueries = resultSet.getLong("Value") - ownNumQueries;
}
if ("Innodb_row_lock_waits".equals(name)) {
numLockWaits = resultSet.getLong("Value");
}
if ("Innodb_row_lock_time".equals(name)) {
lockTime = resultSet.getLong("Value");
}
continue;
}
resultSet.close();
DBStatisticsRecrod record = new DBStatisticsRecrod();
record.setTimeStamp(System.currentTimeMillis());
record.setNumQueueries(numQueueries);
record.setProcessId(mySQLHost);
record.setNumLockWaits(numLockWaits);
record.setLockTime(lockTime);
dataSource.newRecord(record);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public void storeReport(String path) throws MeasurementException {
// nothing to do here
}
@Override
public void prepareMonitoring(InstrumentationDescription monitoringDescription) throws MeasurementException {
for (SamplingDescription sDescr : monitoringDescription.getSamplingDescriptions()) {
if (sDescr.getResourceName().equals(SamplingDescription.SAMPLER_DATABASE_STATISTICS)) {
samplerActivated = true;
delay = sDescr.getDelay();
break;
}
}
}
@Override
public void resetMonitoring() throws MeasurementException {
samplerActivated = false;
}
}