From 4e2c1cd369a368d293e8b17662daa30d4c51c7e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EB=85=B8=EC=9E=AC=ED=98=B8=28JaeHo=20Noh=29/Data=20Infras?=
=?UTF-8?q?tructure=ED=8C=80/SKP?=
Date: Thu, 2 Jun 2016 09:32:10 +0900
Subject: [PATCH 1/5] =?UTF-8?q?daemon=20=EC=8A=A4=ED=81=AC=EB=A6=BD?=
=?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
bin/start-checkmate.sh | 37 +++++++++++++++++++++++++++++++++++++
bin/stop-checkmate.sh | 15 +++++++++++++++
2 files changed, 52 insertions(+)
create mode 100755 bin/start-checkmate.sh
create mode 100755 bin/stop-checkmate.sh
diff --git a/bin/start-checkmate.sh b/bin/start-checkmate.sh
new file mode 100755
index 0000000..2b34afe
--- /dev/null
+++ b/bin/start-checkmate.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+bin=`dirname "$0"`
+bin=`cd "${bin}/.."; pwd`
+
+export CM_HOME="${bin}"
+
+CM_LOG_DIR=${CM_HOME}/logs
+CM_CONF_DIR=${CM_HOME}/conf
+CM_PID_DIR=${CM_HOME}/pid
+
+if [ ! -d ${CM_LOG_DIR} ]; then
+ mkdir ${CM_LOG_DIR}
+ if [ "$?" != "0" ]; then
+ echo "ERROR mkdir ${CM_LOG_DIR}"
+ exit 1
+ fi
+fi
+if [ ! -d ${CM_PID_DIR} ]; then
+ mkdir ${CM_PID_DIR}
+ if [ "$?" != "0" ]; then
+ echo "ERROR mkdir ${CM_PID_DIR}"
+ exit 1
+ fi
+fi
+START_TIME=`date "+%Y%m%d_%H%M%S"`
+
+CLASSPATH=${CM_CONF_DIR}:${CM_HOME}/lib/*:${CLASSPATH}
+
+if [ "${JVM_ARGS}" == "" ]; then
+ JVM_ARGS="-enableassertions -enablesystemassertions -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly -Xms256m -Xmx512m"
+fi
+JVM_ARGS="${JVM_ARGS} -DCM_HOME=${CM_HOME}"
+DEBUG_ARGS="-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -verbose:gc -Xloggc:${CM_LOG_DIR}/checkmate_${START_TIME}.gc"
+
+nohup java $JVM_ARGS -cp "$CLASSPATH" com.skplanet.checkmate.CheckMateServer "$@" > ${CM_LOG_DIR}/checkmate_${START_TIME}.out 2>&1 &
+echo $! > ${CM_PID_DIR}/checkmate.pid
diff --git a/bin/stop-checkmate.sh b/bin/stop-checkmate.sh
new file mode 100755
index 0000000..b5db44a
--- /dev/null
+++ b/bin/stop-checkmate.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+bin=`dirname "$0"`
+bin=`cd "${bin}/.."; pwd`
+
+export CM_HOME="${bin}"
+
+CM_PID_DIR=${CM_HOME}/pid
+
+if [ -f ${CM_PID_DIR}/checkmate.pid ]; then
+ pid=`cat ${CM_PID_DIR}/checkmate.pid`
+ echo "kill -9 ${pid}"
+ kill -9 "${pid}"
+ rm ${CM_PID_DIR}/checkmate.pid
+fi
From 6ae6c3a72e5dc04ce3c3f7bfdf0e75e3b5eccc67 Mon Sep 17 00:00:00 2001
From: 1002571
Date: Wed, 27 Jul 2016 12:05:46 +0900
Subject: [PATCH 2/5] =?UTF-8?q?[CM-10]=20checkmate=20=EB=A9=94=EB=AA=A8?=
=?UTF-8?q?=EB=A6=AC=EB=A6=AD=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
CheckMate 서버의 메모리릭 수정하고 js 에서 과도한 loop 발생하는 부분 수정함
---
.gitignore | 2 +
conf/.gitignore | 2 +
conf/checkmate.ini.sample | 9 +-
conf/log4j.properties | 34 +-
conf/querycache.ini.sample | 3 +-
pom.xml | 15 -
src/main/java/com/beans/ClustersBean.java | 12 +-
.../skplanet/checkmate/CheckMateServer.java | 307 +++------
.../com/skplanet/checkmate/CheckMateWeb.java | 129 ++++
.../querycache/QCClientWebSocket.java | 136 ----
.../checkmate/querycache/QCCluster.java | 531 ++++++--------
.../querycache/QCClusterManager.java | 215 ++----
.../querycache/QCClusterOptions.java | 41 ++
.../checkmate/querycache/QCQuery.java | 407 +++++++----
.../checkmate/querycache/QCQueryMail.java | 47 +-
.../checkmate/querycache/QCServer.java | 648 ++++++++----------
.../querycache/QCWebSocketClient.java | 224 ++++++
.../data/ClusterServerPoolInfo.java | 37 +
.../data/ClusterServerSysStats.java | 42 ++
.../querycache/data/QCQueryEvent.java | 54 ++
.../querycache/data/QCQueryImport.java | 98 +++
.../querycache/data/ServerConDesc.java | 27 +
.../querycache/data/ServerObjectPool.java | 41 ++
.../querycache/data/ServerQueries.java | 22 +
.../querycache/data/ServerRuntimeInfo.java | 33 +
.../querycache/data/ServerSystemInfo.java | 47 ++
.../querycache/data/ServerSystemStats.java | 27 +
.../querycache/data/ServerThreadInfo.java | 41 ++
.../checkmate/servlet/CMApiServletQC.java | 115 ++--
.../servlet/CMQCServerWebSocket.java | 51 +-
.../servlet/CMWebSocketServletQC.java | 8 +-
.../skplanet/checkmate/utils/HttpUtil.java | 90 ++-
.../skplanet/checkmate/utils/MailSender.java | 355 +++++-----
.../checkmate/yarn/YarnResourceManager.java | 2 +-
www/css/querycache.css | 18 +-
www/qc/queries.funcs.html | 29 +-
36 files changed, 2175 insertions(+), 1724 deletions(-)
create mode 100644 conf/.gitignore
create mode 100644 src/main/java/com/skplanet/checkmate/CheckMateWeb.java
delete mode 100644 src/main/java/com/skplanet/checkmate/querycache/QCClientWebSocket.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/QCClusterOptions.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/QCWebSocketClient.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ClusterServerPoolInfo.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ClusterServerSysStats.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/QCQueryEvent.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/QCQueryImport.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ServerConDesc.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ServerObjectPool.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ServerQueries.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ServerRuntimeInfo.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ServerSystemInfo.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ServerSystemStats.java
create mode 100644 src/main/java/com/skplanet/checkmate/querycache/data/ServerThreadInfo.java
diff --git a/.gitignore b/.gitignore
index e81ea6b..9460bc7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,5 @@ tmp/*
.idea
*.iml
checkmate-dist
+/target/
+/logs/
diff --git a/conf/.gitignore b/conf/.gitignore
new file mode 100644
index 0000000..df63422
--- /dev/null
+++ b/conf/.gitignore
@@ -0,0 +1,2 @@
+/checkmate.ini
+/querycache.ini
diff --git a/conf/checkmate.ini.sample b/conf/checkmate.ini.sample
index c91cfa3..c2e9f8d 100644
--- a/conf/checkmate.ini.sample
+++ b/conf/checkmate.ini.sample
@@ -1 +1,8 @@
-WebServicePort = 60080
+[global]
+WebPort = 60080
+
+[email]
+SmtpServer =
+SmtpFrom = CheckMate
+SmtpPort = 25
+MailRecipients =
diff --git a/conf/log4j.properties b/conf/log4j.properties
index 6762096..b95eca3 100644
--- a/conf/log4j.properties
+++ b/conf/log4j.properties
@@ -1,4 +1,4 @@
-checkmate.root.logger=INFO,DRFA,RFA,console
+checkmate.root.logger=INFO,DRFA,console
checkmate.log.dir=${CM_HOME}/logs
checkmate.log.file=checkmate.log
checkmate.warn.log.file=warn.checkmate.log
@@ -15,38 +15,10 @@ log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DRFA.File=${checkmate.log.dir}/${checkmate.log.file}
log4j.appender.DRFA.DatePattern=.yyyy-MM-dd
log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout
-log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
-
-# WARN
-log4j.appender.RFA=org.apache.log4j.DailyRollingFileAppender
-log4j.appender.RFA.File=${checkmate.log.dir}/${checkmate.warn.log.file}
-log4j.appender.RFA.DatePattern=.yyyy-MM-dd
-log4j.appender.RFA.layout=org.apache.log4j.PatternLayout
-log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
-log4j.appender.RFA.Threshold=WARN
+log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2}(%L): %m%n
# Console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n
-
-# querycache log
-checkmate.querycache.log.file=querycache.log
-log4j.logger.querycache=DEBUG,DRFAquerycache
-log4j.appender.DRFAquerycache=org.apache.log4j.DailyRollingFileAppender
-log4j.appender.DRFAquerycache.File=${checkmate.log.dir}/${checkmate.querycache.log.file}
-log4j.appender.DRFAquerycache.DatePattern=.yyyy-MM-dd
-log4j.appender.DRFAquerycache.layout=org.apache.log4j.PatternLayout
-log4j.appender.DRFAquerycache.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
-
-
-# querycache log
-checkmate.api.log.file=api.log
-log4j.logger.api=DEBUG,DRFAapi
-log4j.appender.DRFAapi=org.apache.log4j.DailyRollingFileAppender
-log4j.appender.DRFAapi.File=${checkmate.log.dir}/${checkmate.api.log.file}
-log4j.appender.DRFAapi.DatePattern=.yyyy-MM-dd
-log4j.appender.DRFAapi.layout=org.apache.log4j.PatternLayout
-log4j.appender.DRFAapi.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
-
+log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %-5p %c{2}(%L): %m%n
diff --git a/conf/querycache.ini.sample b/conf/querycache.ini.sample
index 9ebdba7..d494eac 100644
--- a/conf/querycache.ini.sample
+++ b/conf/querycache.ini.sample
@@ -1,7 +1,8 @@
-PartialUpdateInterval = 3000
+[global]
FullUpdateInterval = 10000
Clusters = "myCluster"
[myCluster]
WebPort = 8080
Servers = localhost
+MaxCompleteQueries = 100
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 43ba042..9c8a2bb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -168,21 +168,6 @@
javax.mail
1.5.4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
io.dropwizard.metrics
metrics-core
diff --git a/src/main/java/com/beans/ClustersBean.java b/src/main/java/com/beans/ClustersBean.java
index 026bf66..6365596 100644
--- a/src/main/java/com/beans/ClustersBean.java
+++ b/src/main/java/com/beans/ClustersBean.java
@@ -1,18 +1,22 @@
package com.beans;
-import com.skplanet.checkmate.querycache.QCClusterManager;
-
import java.util.ArrayList;
import java.util.Collection;
+import com.skplanet.checkmate.CheckMateServer;
+
/**
* Created by nazgul33 on 15. 2. 6.
*/
public class ClustersBean implements java.io.Serializable {
- Collection qcClusters = new ArrayList<>();
+
+
+ private static final long serialVersionUID = 2387849279567737354L;
+
+ private Collection qcClusters = new ArrayList<>();
public ClustersBean() {
- qcClusters.addAll( QCClusterManager.getInstance().getClusterList() );
+ qcClusters.addAll( CheckMateServer.getClusterManager().getClusterNameList() );
}
public Collection getQcClusters() {
diff --git a/src/main/java/com/skplanet/checkmate/CheckMateServer.java b/src/main/java/com/skplanet/checkmate/CheckMateServer.java
index d5d0a37..3800245 100644
--- a/src/main/java/com/skplanet/checkmate/CheckMateServer.java
+++ b/src/main/java/com/skplanet/checkmate/CheckMateServer.java
@@ -1,270 +1,127 @@
package com.skplanet.checkmate;
-import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.servlets.MetricsServlet;
-import com.skplanet.checkmate.querycache.QCClusterManager;
-import com.skplanet.checkmate.servlet.CMApiServletQC;
-import com.skplanet.checkmate.servlet.CMWebSocketServletQC;
-import com.skplanet.checkmate.utils.MailSender;
-import com.skplanet.checkmate.yarn.YarnMonitor;
+import java.io.File;
+
import org.apache.commons.configuration.HierarchicalINIConfiguration;
import org.apache.commons.configuration.SubnodeConfiguration;
-import org.apache.tomcat.InstanceManager;
-import org.apache.tomcat.SimpleInstanceManager;
-import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
-import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
-import org.eclipse.jetty.jsp.JettyJspServlet;
-import org.eclipse.jetty.plus.annotation.ContainerInitializer;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.ContextHandlerCollection;
-import org.eclipse.jetty.server.handler.HandlerList;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.*;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import com.codahale.metrics.MetricRegistry;
+import com.skplanet.checkmate.querycache.QCClusterManager;
+import com.skplanet.checkmate.utils.MailSender;
/**
* Hello world!
*
*/
-public class CheckMateServer
-{
- private static final Logger LOG = LoggerFactory.getLogger("main");
+public class CheckMateServer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CheckMateServer.class);
+
private static final MetricRegistry metrics = new MetricRegistry();
- public static MetricRegistry getMetrics() {
- return metrics;
- }
+ private File confDir;
+
+ private final HierarchicalINIConfiguration ini;
- private void StartClusterManagers() {
- LOG.info("Starting QueryCache Cluster Thread");
- QCClusterManager.getInstance().startThread();
+ private QCClusterManager clusterManager;
+ private CheckMateWeb webServer;
-// LOG.info("Starting Yarn Monitor");
-// YarnMonitor.getInstance();
- }
- private void ShutdownClusterManagers() {
- LOG.info("Shutting down QueryCache Cluster Thread");
- QCClusterManager.getInstance().finishThread();
- }
-
- private Server webServer = null;
- private int webServicePort;
- private String home = null;
- private String wwwroot = null;
- private static final String WEBROOT_INDEX = "/www/";
+ private static CheckMateServer _this = null;
+
+ private CheckMateServer(File homeDir) throws Exception {
- private URI getWebRootResourceUri() throws FileNotFoundException, URISyntaxException, MalformedURLException
- {
- // try local resource first
- wwwroot = home + "/www";
- URL indexUri = new File(wwwroot).toURI().toURL();
- if (indexUri == null)
- {
- // fallback to resources in jar
- wwwroot = WEBROOT_INDEX;
- indexUri = this.getClass().getResource(wwwroot);
- throw new FileNotFoundException("Unable to find resource " + wwwroot);
- }
- // Points to wherever /webroot/ (the resource) is
- return indexUri.toURI();
- }
+ confDir = new File(homeDir, "conf");
- private File getScratchDir() throws IOException
- {
- File scratchDir = new File(home, "/tmp/jetty-jsp");
+ File iniFile = new File(confDir,"checkmate.ini");
+ LOG.info("reading checkmate configuration from " + iniFile);
- if (!scratchDir.exists())
+ ini = new HierarchicalINIConfiguration(iniFile);
+
+ SubnodeConfiguration globalSection = ini.getSection("global");
+ globalSection.setThrowExceptionOnMissing(true);
+
+ // MailSender
{
- LOG.info("making scratch directory " + scratchDir.toString());
- if (!scratchDir.mkdirs())
- {
- LOG.error("making scratch directory failed.");
- throw new IOException("Unable to create scratch directory: " + scratchDir);
+ SubnodeConfiguration email = ini.getSection("email");
+ email.setThrowExceptionOnMissing(true);
+
+ String server = email.getString("SmtpServer", null);
+ String from = email.getString("SmtpFrom", "CheckMate");
+ int port = email.getInt("SmtpPort", 25);
+ String tos = email.getString("MailRecipients", null);
+
+ if (server != null && !server.isEmpty() && tos != null && !tos.isEmpty()) {
+ MailSender.initialize(server, port, from, tos.split(","));
+ } else {
+ LOG.info("mail sender not initialized");
}
}
- return scratchDir;
+
+ // ClusterManager
+ clusterManager = new QCClusterManager(confDir);
+
+ // WebServer
+ {
+ int port = globalSection.getInt("WebPort", 8080);
+ webServer = new CheckMateWeb(port, homeDir, metrics);
+ }
}
-
- private List jspInitializers()
- {
- JettyJasperInitializer sci = new JettyJasperInitializer();
- ContainerInitializer initializer = new ContainerInitializer(sci, null);
- List initializers = new ArrayList<>();
- initializers.add(initializer);
- return initializers;
+
+ public static CheckMateServer getInstance() {
+ return _this;
}
-
- private ClassLoader getUrlClassLoader()
- {
- ClassLoader jspClassLoader = new URLClassLoader(new URL[0], this.getClass().getClassLoader());
- return jspClassLoader;
+
+ public static QCClusterManager getClusterManager() {
+ return _this.clusterManager;
}
-
- private ServletHolder jspServletHolder()
- {
- ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class);
- holderJsp.setInitOrder(0);
- holderJsp.setInitParameter("logVerbosityLevel", "DEBUG");
- holderJsp.setInitParameter("fork", "false");
- holderJsp.setInitParameter("xpoweredBy", "false");
- holderJsp.setInitParameter("compilerTargetVM", "1.7");
- holderJsp.setInitParameter("compilerSourceVM", "1.7");
- holderJsp.setInitParameter("keepgenerated", "true");
- return holderJsp;
+
+ public static MetricRegistry getMetrics() {
+ return metrics;
}
- private ServletHolder defaultServletHolder(URI baseUri)
- {
- ServletHolder holderDefault = new ServletHolder("default", DefaultServlet.class);
- LOG.info("Base URI: " + baseUri);
- holderDefault.setInitParameter("resourceBase", baseUri.toASCIIString());
- holderDefault.setInitParameter("dirAllowed", "false");
- holderDefault.setInitParameter("redirectWelcome", "true");
- holderDefault.setInitParameter("welcomeServlets", "false");
+ private void startClusterManagers() {
+
+ LOG.info("Starting QueryCache Cluster Thread");
+ clusterManager.start();
- return holderDefault;
+// LOG.info("Starting Yarn Monitor");
+// YarnMonitor.getInstance();
}
-
- private WebAppContext getWebAppContext(URI baseUri, File scratchDir)
- {
- WebAppContext context = new WebAppContext();
- context.setContextPath("/");
- context.setAttribute("javax.servlet.context.tempdir", scratchDir);
- context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
- ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/.*taglibs.*\\.jar$");
- context.setResourceBase(baseUri.toASCIIString());
- context.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers());
- context.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager());
- context.addBean(new ServletContainerInitializersStarter(context), true);
- context.setClassLoader(getUrlClassLoader());
-
- context.addServlet(jspServletHolder(), "*.jsp");
- // Add Application Servlets
- // context.addServlet(BeanMapper.class, "*.cm");
- context.addServlet(defaultServletHolder(baseUri), "/");
- return context;
+
+ private void startWebServer() throws Exception {
+ webServer.runWebServer();
}
-
- public Server runWebInterface() throws Exception {
- // create web service
- LOG.info("Starting web interface...");
- webServer = new Server(webServicePort);
-
- URI baseUri = getWebRootResourceUri();
-
- System.setProperty("org.apache.jasper.compiler.disablejsr199","false");
-
-// ServletContextHandler apiImpala = new ServletContextHandler(ServletContextHandler.SESSIONS);
-// apiImpala.setContextPath("/api/impala");
-// apiImpala.addServlet(new ServletHolder(new QCWebApiServlet()), "/*");
-
- ServletContextHandler apiQc = new ServletContextHandler(ServletContextHandler.SESSIONS);
- apiQc.setContextPath("/api/qc");
- apiQc.addServlet(new ServletHolder(new CMWebSocketServletQC()), "/websocket/*");
- apiQc.addServlet(new ServletHolder(new CMApiServletQC()), "/*");
-
- ServletContextHandler metrics = new ServletContextHandler(ServletContextHandler.SESSIONS);
- metrics.setContextPath("/api/metrics");
- metrics.addServlet(new ServletHolder(new MetricsServlet(getMetrics())), "/metrics");
-
- File scratchDir = getScratchDir();
- ServletContextHandler webappHandler = getWebAppContext(baseUri, scratchDir);
-
- ContextHandlerCollection contextCollection = new ContextHandlerCollection();
- contextCollection.setHandlers( new Handler[] { apiQc, metrics, webappHandler } );
-
- HandlerList handlers = new HandlerList();
- handlers.setHandlers(new Handler[]{contextCollection});
- webServer.setHandler(handlers);
- webServer.start();
- LOG.info("Started web interface...");
-
- return webServer;
+
+ private void stopClusterManagers() {
+ LOG.info("Shutting down QueryCache Cluster Thread");
+ clusterManager.stop();
}
- private final HierarchicalINIConfiguration clusterConfigFile;
- private MailSender mailSender = null;
- private List mailRecipients = null;
+ public static void main( String[] args ) {
- public CheckMateServer() throws Exception {
- home = System.getenv("CM_HOME");
- if (home == null) {
- home = "./";
+ String cmHome = System.getenv("CM_HOME");
+ if (cmHome == null) {
+ throw new RuntimeException("$CM_HOME undefined");
}
-
- String conf = home + "/conf/checkmate.ini";
- LOG.info("reading checkmate configuration from " + conf);
-
- clusterConfigFile = new HierarchicalINIConfiguration(conf);
- SubnodeConfiguration globalSection = clusterConfigFile.getSection(null);
- globalSection.setThrowExceptionOnMissing(true);
- webServicePort = globalSection.getInt("WebServicePort", 8080);
-
- // init mail sender
- String smtpServer = globalSection.getString("SmtpServer", null);
- String smtpFrom = globalSection.getString("SmtpFrom", "CheckMate");
- int smtpPort = globalSection.getInt("SmtpPort", 25);
- String recipients = globalSection.getString("MailRecipients", null);
-
- if (smtpServer != null && recipients != null) {
- mailRecipients = Arrays.asList( recipients.split(",") );
- mailSender = new MailSender(smtpServer, smtpFrom, smtpPort, mailRecipients);
- new Thread(mailSender).start();
- }
- }
-
- public HierarchicalINIConfiguration getClusterConfigFile() {
- return clusterConfigFile;
- }
-
- public List getMailRecipients() {
- return mailRecipients;
- }
-
- public MailSender getMailSender() {
- return mailSender;
- }
-
- private static CheckMateServer server = null;
- public static CheckMateServer getInstance() {
- return server;
- }
-
- public static void main( String[] args )
- {
- try {
- server = new CheckMateServer();
- server.StartClusterManagers();
+
+ File homeDir = new File(cmHome);
+ try {
+ _this = new CheckMateServer(homeDir);
+ _this.startClusterManagers();
} catch (Exception e) {
LOG.error("error initializing CheckMateServer", e);
System.exit(1);
}
try {
- server.runWebInterface();
+ _this.startWebServer();
} catch (Exception e) {
- LOG.error("exception while starting web interface");
+ LOG.error("exception while starting web interface", e);
System.exit(1);
}
-
- // run forever until interrupted.
- try {
- server.webServer.join();
- } catch (Exception e) {
- LOG.error("Checkmate Interrupted." + e.toString());
- }
- server.ShutdownClusterManagers();
+
+ _this.stopClusterManagers();
}
}
diff --git a/src/main/java/com/skplanet/checkmate/CheckMateWeb.java b/src/main/java/com/skplanet/checkmate/CheckMateWeb.java
new file mode 100644
index 0000000..e325de3
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/CheckMateWeb.java
@@ -0,0 +1,129 @@
+package com.skplanet.checkmate;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tomcat.InstanceManager;
+import org.apache.tomcat.SimpleInstanceManager;
+import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
+import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
+import org.eclipse.jetty.jsp.JettyJspServlet;
+import org.eclipse.jetty.plus.annotation.ContainerInitializer;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.server.handler.HandlerList;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.servlets.MetricsServlet;
+import com.skplanet.checkmate.servlet.CMApiServletQC;
+import com.skplanet.checkmate.servlet.CMWebSocketServletQC;
+
+public class CheckMateWeb {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CheckMateWeb.class);
+
+ private Server webServer = null;
+
+ public CheckMateWeb(int port, File rootDir, MetricRegistry metric) throws Exception {
+ LOG.info("Starting web interface...");
+ webServer = new Server(port);
+
+ File webRoot = new File(rootDir,"www");
+ if (!webRoot.exists()) {
+ throw new FileNotFoundException("Unable to find resource " + webRoot);
+ }
+ // Points to wherever /www/ (the resource) is
+ URI baseUri = webRoot.toURI();
+
+ System.setProperty("org.apache.jasper.compiler.disablejsr199","false");
+
+ // ServletContextHandler apiImpala = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ // apiImpala.setContextPath("/api/impala");
+ // apiImpala.addServlet(new ServletHolder(new QCWebApiServlet()), "/*");
+
+ ServletContextHandler apiQc = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ apiQc.setContextPath("/api/qc");
+ apiQc.addServlet(new ServletHolder(new CMWebSocketServletQC()), "/websocket/*");
+ apiQc.addServlet(new ServletHolder(new CMApiServletQC()), "/*");
+
+ ServletContextHandler metrics = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ metrics.setContextPath("/api/metrics");
+ metrics.addServlet(new ServletHolder(new MetricsServlet(metric)), "/metrics");
+
+ // File scratchDir = getScratchDir();
+ WebAppContext context = new WebAppContext();
+ context.setContextPath("/");
+ // context.setAttribute("javax.servlet.context.tempdir", scratchDir);
+ context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
+ ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/.*taglibs.*\\.jar$");
+ context.setResourceBase(webRoot.toString());
+ context.setAttribute("org.eclipse.jetty.containerInitializers", getJspInitializers());
+ context.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager());
+ context.addBean(new ServletContainerInitializersStarter(context), true);
+ context.setClassLoader(getUrlClassLoader());
+ context.addServlet(getJspServletHolder(), "*.jsp");
+ context.addServlet(getDefaultServletHolder(baseUri), "/");
+ // ServletContextHandler webappHandler = getWebAppContext(baseUri, scratchDir);
+
+ ContextHandlerCollection contextCollection = new ContextHandlerCollection();
+ contextCollection.setHandlers( new Handler[] { apiQc, metrics, context } );
+
+ HandlerList handlers = new HandlerList();
+ handlers.setHandlers(new Handler[]{contextCollection});
+ webServer.setHandler(handlers);
+ }
+
+ private List getJspInitializers() {
+ JettyJasperInitializer sci = new JettyJasperInitializer();
+ ContainerInitializer initializer = new ContainerInitializer(sci, null);
+ List initializers = new ArrayList<>();
+ initializers.add(initializer);
+ return initializers;
+ }
+
+ private ClassLoader getUrlClassLoader() {
+ ClassLoader jspClassLoader = new URLClassLoader(new URL[0], this.getClass().getClassLoader());
+ return jspClassLoader;
+ }
+
+ private ServletHolder getJspServletHolder() {
+ ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class);
+ holderJsp.setInitOrder(0);
+ holderJsp.setInitParameter("logVerbosityLevel", "DEBUG");
+ holderJsp.setInitParameter("fork", "false");
+ holderJsp.setInitParameter("xpoweredBy", "false");
+ holderJsp.setInitParameter("compilerTargetVM", "1.7");
+ holderJsp.setInitParameter("compilerSourceVM", "1.7");
+ holderJsp.setInitParameter("keepgenerated", "true");
+ return holderJsp;
+ }
+
+ private ServletHolder getDefaultServletHolder(URI baseUri) {
+ ServletHolder holderDefault = new ServletHolder("default", DefaultServlet.class);
+ LOG.info("Base URI: " + baseUri);
+ holderDefault.setInitParameter("resourceBase", baseUri.toASCIIString());
+ holderDefault.setInitParameter("dirAllowed", "false");
+ holderDefault.setInitParameter("redirectWelcome", "true");
+ holderDefault.setInitParameter("welcomeServlets", "false");
+
+ return holderDefault;
+ }
+
+ public void runWebServer() throws Exception {
+
+ webServer.start();
+ webServer.join();
+ }
+}
diff --git a/src/main/java/com/skplanet/checkmate/querycache/QCClientWebSocket.java b/src/main/java/com/skplanet/checkmate/querycache/QCClientWebSocket.java
deleted file mode 100644
index 2ca8086..0000000
--- a/src/main/java/com/skplanet/checkmate/querycache/QCClientWebSocket.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package com.skplanet.checkmate.querycache;
-
-import com.google.gson.Gson;
-import org.eclipse.jetty.websocket.api.Session;
-import org.eclipse.jetty.websocket.api.WebSocketListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import sun.misc.Request;
-
-/**
- * Created by nazgul33 on 15. 2. 23.
- */
-public class QCClientWebSocket implements WebSocketListener {
- private static final boolean DEBUG = false;
- private static final Logger LOG = LoggerFactory.getLogger("websocket-client-qc");
-
- private Session outbound = null;
- private QCServer server = null;
-
- private static class RequestMsg {
- public String request;
- public String channel;
- public String data;
- }
-
- public QCClientWebSocket(QCServer server) {
- this.server = server;
- }
-
- @Override
- public void onWebSocketBinary(byte[] payload, int offset, int len)
- {
- /* not interested */
- }
-
- @Override
- public void onWebSocketClose(int statusCode, String reason)
- {
- LOG.info("WebSocket to " + server.name + " closed");
- this.outbound = null;
- server.removeRtWebSocket();
- }
-
- @Override
- public void onWebSocketConnect(Session session) {
- this.outbound = session;
- LOG.info("WebSocket to " + server.name + " established");
-
- RequestMsg req = new RequestMsg();
- req.request = "subscribe";
- req.channel = "runningQueries";
-
- Gson gson = new Gson();
- String msg = gson.toJson(req);
-
- sendMessage(msg);
- }
-
- @Override
- public void onWebSocketError(Throwable cause) {
- LOG.error("websocket error", cause);
- if (this.outbound == null) {
- // connection error. server's websocket should be cleared.
- server.removeRtWebSocket();
- }
- }
-
- public static final String evtStrQueryAdded = "runningQueryAdded";
- public static final String evtStrQueryUpdated = "runningQueryUpdated";
- public static final String evtStrQueryRemoved = "runningQueryRemoved";
- public static final String evtStrResult = "result";
- public static final String evtStrPong = "pong";
- private static class RunningQueryEvent {
- public String msgType = null;
- public String result = null;
- public QCQuery.QueryImport query = null;
- public String queryId = null;
- }
-
- @Override
- public void onWebSocketText(String message) {
- Gson gson = new Gson();
- RunningQueryEvent evt = null;
- try {
- evt = gson.fromJson(message, RunningQueryEvent.class);
- } catch (Exception e) {
- LOG.error("Gson exception :", message);
- }
-
- if (evt == null || evt.msgType == null) {
- LOG.error("invalid event object received.", message);
- return;
- }
-
- QCQuery q;
- switch (evt.msgType) {
- case evtStrQueryAdded:
- case evtStrQueryUpdated:
- if (evt.query != null) {
- LOG.debug("new RT query");
- q = new QCQuery(server, evt.query);
- server.processAddQueryEvent(q);
- }
- break;
- case evtStrQueryRemoved:
- if (evt.query != null) {
- LOG.debug("removing RT query");
- q = new QCQuery(server, evt.query);
- server.processRemoveQueryEvent(q);
- }
- break;
- case evtStrResult:
- LOG.info("result " + evt.result);
- break;
- case evtStrPong:
- LOG.debug("pong!!");
- break;
- default:
- LOG.warn("ignoring message", message);
- break;
- }
- }
-
- public void sendMessage(String message) {
- if (outbound == null || !outbound.isOpen())
- return;
- outbound.getRemote().sendString(message, null);
- }
-
- public void ping() {
- Gson gson = new Gson();
- RequestMsg msg = new RequestMsg();
- msg.request = "ping";
- sendMessage(gson.toJson(msg));
- }
-}
diff --git a/src/main/java/com/skplanet/checkmate/querycache/QCCluster.java b/src/main/java/com/skplanet/checkmate/querycache/QCCluster.java
index 8caaebb..5b38267 100644
--- a/src/main/java/com/skplanet/checkmate/querycache/QCCluster.java
+++ b/src/main/java/com/skplanet/checkmate/querycache/QCCluster.java
@@ -1,370 +1,273 @@
package com.skplanet.checkmate.querycache;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.codahale.metrics.Histogram;
import com.codahale.metrics.SlidingTimeWindowReservoir;
import com.google.gson.Gson;
import com.skplanet.checkmate.CheckMateServer;
+import com.skplanet.checkmate.querycache.data.ClusterServerPoolInfo;
+import com.skplanet.checkmate.querycache.data.ClusterServerSysStats;
+import com.skplanet.checkmate.querycache.data.QCQueryEvent;
+import com.skplanet.checkmate.querycache.data.ServerObjectPool;
import com.skplanet.checkmate.servlet.CMQCServerWebSocket;
-import com.skplanet.checkmate.utils.MailSender;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.awt.*;
-import java.util.*;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by nazgul33 on 15. 1. 27.
*/
public class QCCluster {
- private static final boolean DEBUG = false;
- private static final Logger LOG = LoggerFactory.getLogger("querycache");
- private static final int MAX_COMPLETE_QUERIES = 100;
- private static final String RQE_ADDED = "runningQueryAdded";
- private static final String RQE_UPDATED = "runningQueryUpdated";
- private static final String RQE_REMOVED = "runningQueryRemoved";
+
+ private static final Logger LOG = LoggerFactory.getLogger(QCCluster.class);
+
+ private String name;
+ private QCClusterOptions opt;
+
+ private Map serverMap = new HashMap<>();
+
+ private Timer notifyTimer = new Timer(true);
+ private Histogram histogram;
+
+ private long fullUpdateInterval;
+ private Timer updateTimer = new Timer(true);
+
+// private static final long longRunningLimit = 900L * 1000L; // 900 sec
- static public class Options {
- public int webPort = 8080;
- public int partialUpdateInterval = 3000;
- public int fullUpdateInterval = 10000;
- public String[] servers;
- }
-
- public final String name;
- private Map servers;
- private Options opt;
-
- private Timer notifyTimer = new Timer();
- Histogram histogram;
+ private final static long retentionTime = 200;
+ private final LinkedList evtQueueList = new LinkedList<>();
+
+ private Map realtimeMessageReceiverMap = new HashMap<>();
+ private AtomicInteger realtimeMessageReceiversId = new AtomicInteger(0);
- public QCCluster(String name, Options opt) {
+ public QCCluster(String name, QCClusterOptions opt, long fullUpdateInterval) throws URISyntaxException {
+
this.name = name;
this.opt = opt;
-
- servers = new HashMap<>();
- for (String serverName : opt.servers) {
- if (servers.containsKey(serverName)) {
- System.console().printf("duplicate server name %s\n", serverName);
- System.exit(1);
+ this.fullUpdateInterval = fullUpdateInterval;
+
+ for (String serverName : opt.getServers()) {
+ if (serverMap.containsKey(serverName)) {
+ LOG.warn("duplicate server name {}", serverName);
+ } else {
+ serverMap.put(serverName, new QCServer(this, serverName));
}
- servers.put(serverName, new QCServer(serverName, this));
}
-
- TimerTask wsNotifyTask = new TimerTask() {
- @Override
- public void run() {
- notifySubscribers();
- }
- };
- notifyTimer.scheduleAtFixedRate(wsNotifyTask, 0, 50);
- notifyTimer.scheduleAtFixedRate(queryAnomalyDetectorTask, 5000L, 5000L);
-
histogram = new Histogram( new SlidingTimeWindowReservoir(5L, TimeUnit.MINUTES) );
+
CheckMateServer.getMetrics().register("queries."+name, histogram);
}
- public void updateCounters() {
- int count = 0;
- for (Map.Entry entry : servers.entrySet()) {
- count += entry.getValue().updateQueryCount();
- }
- histogram.update(count);
- }
- public Map getServers() {
- return servers;
- }
+ public String getName() {
+ return name;
+ }
public QCServer getServer(String name) {
- return servers.get(name);
- }
-
- public void Update() {
- // update all servers
- Date start = new Date();
- for (Map.Entry entry : servers.entrySet()) {
- QCServer server = entry.getValue();
- server.Update();
-
- // update sysinfo
- QCServer.SysInfoCollection sysInfo = server.getSysInfoCollection();
- if (sysInfo != null) {
- SystemInfo mySysInfo = sysInfoMap.get(server.name);
- if ( mySysInfo == null) {
- mySysInfo = new SystemInfo();
- mySysInfo.server = server.name;
- sysInfoMap.put(server.name, mySysInfo);
- }
- mySysInfo.jvm = sysInfo.jvm;
- mySysInfo.system = sysInfo.system;
- mySysInfo.threads = sysInfo.threads;
- }
-
- QCServer.ObjectPool objPoolInfo = server.getObjectPool();
- Collection connPoolInfo = server.getConnections();
- if (objPoolInfo != null && connPoolInfo != null) {
- PoolInfo myPoolInfo = poolInfoMap.get(server.name);
- if ( myPoolInfo == null) {
- myPoolInfo = new PoolInfo();
- myPoolInfo.server = server.name;
- poolInfoMap.put(server.name, myPoolInfo);
- }
- myPoolInfo.objPool = objPoolInfo;
- myPoolInfo.connPoolList = connPoolInfo;
- }
- }
- Date end = new Date();
- if (DEBUG) {
- LOG.debug("Updating cluster " + name + " took " + (end.getTime() - start.getTime()) + " ms");
- }
-
- refreshExportedCompleteQueries();
+ return serverMap.get(name);
}
-
- public Options getOpt() {
+
+ public QCClusterOptions getOptions() {
return opt;
}
-
- MailSender mailSender = CheckMateServer.getInstance().getMailSender();
- private class EventAnomalyDetector {
- private static final long longRunningLimit = 900L * 1000L; // 900 sec
- boolean longRunningQuery = false;
- QCQuery.QueryExport query = null;
-
- void detect() {
- long now = System.currentTimeMillis();
- if ( query == null )
- return;
-
- if (!longRunningQuery) {
- if (query.startTime + longRunningLimit < now &&
- ("EXEC".equals(query.state) || "INIT".equals(query.state))) {
- longRunningQuery = true;
-
- LOG.info("Slow query {}:{}", query.backend, query.id);
- if (mailSender != null) mailSender.addMail(
- new QCQueryMail(query, "Slow Query by " + query.user, "Slow query detected by CheckMate.")
- );
- }
- }
- }
+
+ public void start() {
+
+ for (QCServer server:serverMap.values()) {
+ server.start();
+ }
+
+ notifyTimer.schedule(new TimerTask() {
+ // CheckMate 의 websocket 에 연결된 client 에게 실행중인 쿼리를 발송하는 타이머
+ @Override
+ public void run() {
+ notifySubscribers();
+ }
+ }, 0, 50);
+
+// notifyTimer.schedule(new TimerTask() {
+// @Override
+// public void run() {
+// List list = new ArrayList<>();
+// synchronized (runningQueriesMap) {
+// for (QCQuery query:runningQueriesMap.values()) {
+// if (isAnomalQuery(query)) {
+// list.add(query);
+// }
+// }
+// }
+// processAnomalQuery(list);
+// }
+// }, 5000L, 5000L);
+
+ updateTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ updateApi();
+ }
+ }, 0, fullUpdateInterval);
+
+ updateTimer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ updateCounters();
+ }
+ }, 60*1000, 60*1000);
}
-
- private final HashMap detectorMap = new HashMap<>();
-
- TimerTask queryAnomalyDetectorTask = new TimerTask() {
- @Override
- public void run() {
- Map dMap;
- synchronized (detectorMap) {
- dMap = new HashMap<>(detectorMap);
- }
- for ( Map.Entry entry : dMap.entrySet() ) {
- entry.getValue().detect();
- }
- }
- };
-
- private static class RunningQueryEvent {
- public long timestamp = System.currentTimeMillis();
- public String msgType = null;
- public QCQuery.QueryExport query = null;
- public String cuqId = null;
- }
-
- private final Map exportedRunningQueriesMap = new HashMap<>();
- public QCQuery.QueryExport getExportedRunningQueryByCuqId(String cuqId) {
- QCQuery.QueryExport q;
- synchronized (exportedRunningQueriesMap) {
- q = exportedRunningQueriesMap.get(cuqId);
- }
- return q;
+
+ public void close() {
+ updateTimer.cancel();
+
+ for (QCServer server:serverMap.values()) {
+ server.stop();
+ }
}
-
- public void addExportedRunningQuery(QCQuery q) {
- QCQuery.QueryExport eq = q.export();
- boolean queryUpdated;
- synchronized (exportedRunningQueriesMap) {
- queryUpdated = (exportedRunningQueriesMap.put(eq.cuqId, eq) != null);
- }
- synchronized (detectorMap) {
- EventAnomalyDetector det = detectorMap.get(eq.cuqId);
- if (det != null)
- det.query = eq;
- else {
- det = new EventAnomalyDetector();
- det.query = eq;
- detectorMap.put(eq.cuqId, det);
- }
+
+ private void updateCounters() {
+ int count = 0;
+ for (QCServer server:serverMap.values()) {
+ count += server.getAndResetQueryCount();
}
-
- RunningQueryEvent evt = new RunningQueryEvent();
- evt.msgType = queryUpdated? RQE_UPDATED:RQE_ADDED;
- evt.query = eq;
- evt.cuqId = eq.cuqId;
- addRunningQueryEvent(evt);
+ histogram.update(count);
}
-
- public void removeExportedRunningQuery(QCQuery q) {
- synchronized (exportedRunningQueriesMap) {
- exportedRunningQueriesMap.remove(q.cuqId);
- }
- synchronized (detectorMap) {
- detectorMap.remove(q.cuqId);
+
+ private void updateApi() {
+ // update all servers
+ for (QCServer server:serverMap.values()) {
+ server.updateApi();
}
- QCQuery.QueryExport eq = q.export();
- RunningQueryEvent evt = new RunningQueryEvent();
- evt.msgType = RQE_REMOVED;
- evt.query = eq;
- evt.cuqId = eq.cuqId;
- addRunningQueryEvent(evt);
}
-
- public Collection getExportedRunningQueries() {
- List ql = new ArrayList<>();
- synchronized (exportedRunningQueriesMap) {
- ql.addAll(exportedRunningQueriesMap.values());
- }
- Collections.sort(ql, new Comparator() {
+
+ public List getServerInfo() {
+ List list = new ArrayList<>(serverMap.size());
+ for (QCServer server:serverMap.values()) {
+ list.add(new ClusterServerSysStats(server.getName(), server.getSystemStats()));
+ }
+ Collections.sort(list, new Comparator() {
@Override
- public int compare(QCQuery.QueryExport o1, QCQuery.QueryExport o2) {
- return ((o1.startTime - o2.startTime) < 0) ? -1 : (o1.startTime == o2.startTime) ? 0 : 1;
+ public int compare(ClusterServerSysStats o1, ClusterServerSysStats o2) {
+ return o1.getServer().compareTo(o2.getServer());
}
});
- return ql;
+ return list;
}
- // complete query update accelerators
- private final List tmpCompleteQueries = new ArrayList<>();
- void queueCompleteQuery(QCQuery q) {
- synchronized (tmpCompleteQueries) {
- tmpCompleteQueries.add(q);
- }
- }
-
- private final LinkedList exportedCompleteQueries = new LinkedList<>();
- private void refreshExportedCompleteQueries() {
- synchronized (tmpCompleteQueries) {
- Collections.sort(tmpCompleteQueries, new Comparator() {
- @Override
- public int compare(QCQuery o1, QCQuery o2) {
- return (o2.endTime > o1.endTime) ? 1 : (o2.endTime == o1.endTime) ? 0 : -1;
- }
- });
-
- synchronized (exportedCompleteQueries) {
- for (QCQuery q: tmpCompleteQueries) {
- // addFirst() to make most recent query comes first.
- exportedCompleteQueries.addFirst(q.export());
- }
-
- // maintain size of exportedCompleteQueries
- int toRemove = exportedCompleteQueries.size() - MAX_COMPLETE_QUERIES;
- if (toRemove > 0) {
- for (int i=0; i getPoolInfo() {
+ List list = new ArrayList<>(serverMap.size());
+ for (QCServer server:serverMap.values()) {
+ list.add(new ClusterServerPoolInfo(server.getName(),
+ server.getObjectPool(), server.getConnDescList()));
+ }
+ Collections.sort(list, new Comparator() {
+ @Override
+ public int compare(ClusterServerPoolInfo o1, ClusterServerPoolInfo o2) {
+ return o1.getServer().compareTo(o2.getServer());
}
- tmpCompleteQueries.clear();
- }
+ });
+ return list;
}
- // TODO: getting subset of complete queries
- public Collection getExportedCompleteQueries() {
- List ql = new ArrayList<>();
- synchronized (exportedCompleteQueries) {
- ql.addAll(exportedCompleteQueries);
+ // Web UI
+ public QCQuery getRunningQueryByCuqId(String cuqId) {
+ for (QCServer server:serverMap.values()) {
+ return server.getRunningQueryByCuqId(cuqId);
}
- return ql;
- }
-
- static public class SystemInfo {
- public String server;
- public QCServer.RuntimeInfo jvm;
- public QCServer.SystemInfo system;
- public QCServer.ThreadInfo threads;
+ return null;
}
- private final Map sysInfoMap = new HashMap<>();
- public Collection getSystemInfo() {
- List l = new ArrayList<>();
- synchronized (sysInfoMap) {
- l.addAll(sysInfoMap.values());
+
+ // Web UI
+ public List getRunningQueries() {
+ List list = new ArrayList<>();
+ for (QCServer server:serverMap.values()) {
+ list.addAll(server.getRunningQueryList());
}
-
- Collections.sort(l, new Comparator() {
+ Collections.sort(list, new Comparator() {
@Override
- public int compare(SystemInfo o1, SystemInfo o2) {
- return o1.server.compareTo(o2.server);
+ public int compare(QCQuery o1, QCQuery o2) {
+ return Long.compare(o2.getStartTime(), o1.getStartTime());
}
});
- return l;
+ return list;
}
-
- static public class PoolInfo {
- public String server;
- public QCServer.ObjectPool objPool;
- public Collection connPoolList;
- }
-
- private final Map poolInfoMap = new HashMap<>();
- public Collection getPoolInfo() {
- List l = new ArrayList<>();
- synchronized (poolInfoMap) {
- l.addAll(poolInfoMap.values());
+
+ public List getCompleteQueries() {
+ List list = new ArrayList<>();
+ for (QCServer server:serverMap.values()) {
+ list.addAll(server.getCompleteQueryList());
}
- Collections.sort(l, new Comparator() {
+ Collections.sort(list, new Comparator() {
@Override
- public int compare(PoolInfo o1, PoolInfo o2) {
- return o1.server.compareTo(o2.server);
+ public int compare(QCQuery o1, QCQuery o2) {
+ return Long.compare(o2.getStartTime(), o1.getStartTime());
}
});
- return l;
- }
-
- private Map realtimeMessageReceivers = new HashMap<>();
- AtomicInteger realtimeMessageReceiversId = new AtomicInteger(0);
-
- public int subscribe(CMQCServerWebSocket ws) {
- int id = realtimeMessageReceiversId.getAndAdd(1);
- realtimeMessageReceivers.put(id, ws);
- return id;
+ return list;
}
-
- public void unSubscribe(int id) {
- realtimeMessageReceivers.remove(id);
- }
-
- private final static long retentionTime = 200;
- private final LinkedList evtQueue = new LinkedList<>();
- private void addRunningQueryEvent(RunningQueryEvent evt) {
- synchronized (evtQueue) {
- if (RQE_REMOVED.equals(evt.msgType)) {
- Iterator it = evtQueue.iterator();
+
+ public void addQueryEvent(String type, QCQuery query) {
+
+ QCQueryEvent evt = new QCQueryEvent(type, query);
+
+ synchronized (evtQueueList) {
+ if (QCQueryEvent.RUN_QUERY_REMOVED.equals(evt.getMsgType())) {
+ Iterator it = evtQueueList.iterator();
while (it.hasNext()) {
- RunningQueryEvent rqe = it.next();
- String cuqId = (rqe.cuqId != null)? rqe.cuqId:rqe.query.cuqId;
- if (evt.cuqId.equals(cuqId)) {
+ QCQueryEvent rqe = it.next();
+ if (evt.getCuqId().equals(rqe.getCuqId())) {
it.remove();
}
}
}
-
- evtQueue.addLast(evt);
+ evtQueueList.addLast(evt);
}
}
- public void notifySubscribers() {
+
+ /**
+ * CheckMate 의 websocket 에 연결된 client 등록
+ * @param ws
+ * @return
+ */
+ public int subscribe(CMQCServerWebSocket ws) {
+ int id = realtimeMessageReceiversId.getAndAdd(1);
+ realtimeMessageReceiverMap.put(id, ws);
+ return id;
+ }
+
+ /**
+ * CheckMate 의 websocket 연결이 끊기면 client 삭제
+ * @param id
+ */
+ public void unsubscribe(int id) {
+ realtimeMessageReceiverMap.remove(id);
+ }
+
+ /**
+ * CheckMate 의 websocket 에 연결한 client running query event 전송
+ */
+ private void notifySubscribers() {
+
long retainAfter = System.currentTimeMillis() - retentionTime; // send events older than 200ms
- LinkedList el = new LinkedList<>();
- synchronized (evtQueue) {
- Iterator it = evtQueue.iterator();
+ List el = new ArrayList<>();
+ synchronized (evtQueueList) {
+ Iterator it = evtQueueList.iterator();
while (it.hasNext()) {
- RunningQueryEvent evt = it.next();
- if (evt.timestamp < retainAfter) {
- el.addLast(evt);
+ QCQueryEvent evt = it.next();
+ if (evt.getTimestamp() < retainAfter) {
+ el.add(evt);
it.remove();
}
}
@@ -372,13 +275,27 @@ public void notifySubscribers() {
if (el.size()>0) {
Gson gson = new Gson();
- for (RunningQueryEvent evt: el) {
+ for (QCQueryEvent evt: el) {
String msg = gson.toJson(evt);
- for (CMQCServerWebSocket ws : realtimeMessageReceivers.values()) {
+ for (CMQCServerWebSocket ws : realtimeMessageReceiverMap.values()) {
ws.sendMessage(msg);
}
}
- el.clear();
}
}
+
+// private boolean isAnomalQuery(QCQuery query) {
+// return query.isAnormal() == false &&
+// (query.getStartTime() + longRunningLimit) < System.currentTimeMillis() &&
+// ("EXEC".equals(query.getState()) || "INIT".equals(query.getState()) );
+// }
+//
+// private void processAnomalQuery(List list) {
+// for (QCQuery query:list) {
+// query.setAnormal(true);
+// LOG.info("Slow query {}:{}", query.getBackend(), query.getId());
+// MailSender.send(
+// new QCQueryMail(query, "[QC] Slow Query by "+ query.getUser(), "Slow query detected by CheckMate."));
+// }
+// }
}
diff --git a/src/main/java/com/skplanet/checkmate/querycache/QCClusterManager.java b/src/main/java/com/skplanet/checkmate/querycache/QCClusterManager.java
index 777bdd0..7d8a7e6 100644
--- a/src/main/java/com/skplanet/checkmate/querycache/QCClusterManager.java
+++ b/src/main/java/com/skplanet/checkmate/querycache/QCClusterManager.java
@@ -1,193 +1,88 @@
package com.skplanet.checkmate.querycache;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalINIConfiguration;
import org.apache.commons.configuration.SubnodeConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-
/**
* Created by nazgul33 on 15. 1. 27.
*/
public class QCClusterManager {
- private static final Logger LOG = LoggerFactory.getLogger("querycache");
- private static QCClusterManager qcMgr = null;
-
- private Map clusterConfigMap = new HashMap<>();
-
- private int fullUpdateInterval = 10 * 1000;
- private int pingWebSocketsInterval = 5 * 1000;
-
- private void readConfiguration() {
- String home = System.getenv("CM_HOME");
- if (home == null) {
- home = "./";
- }
- String conf = home + "/conf/querycache.ini";
- HierarchicalINIConfiguration clusterConfigFile = null;
- String[] clusterNames;
- QCCluster.Options options[];
-
+
+ private static final Logger LOG = LoggerFactory.getLogger(QCClusterManager.class);
+
+ private Map clusterMap = new HashMap<>();
+
+ public QCClusterManager(File confDir) throws Exception {
+
+ File iniFile = new File(confDir, "querycache.ini");
+ HierarchicalINIConfiguration ini = null;
+
+ Map optionMap = new HashMap<>();
+ int fullUpdateInterval;
try {
- LOG.info("reading checkmate::querycache configuration from " + conf);
- clusterConfigFile = new HierarchicalINIConfiguration(conf);
- SubnodeConfiguration globalSection = clusterConfigFile.getSection(null);
+ LOG.info("reading checkmate::querycache configuration from " + iniFile);
+ ini = new HierarchicalINIConfiguration(iniFile);
+
+ SubnodeConfiguration globalSection = ini.getSection("global");
globalSection.setThrowExceptionOnMissing(true);
- clusterNames = globalSection.getStringArray("Clusters");
- fullUpdateInterval = globalSection.getInt("FullUpdateInterval");
-
- for (String cn: clusterNames) {
- SubnodeConfiguration sc = clusterConfigFile.getSection(cn);
- QCCluster.Options opt = new QCCluster.Options();
- opt.webPort = sc.getInt("WebPort");
- opt.servers = sc.getStringArray("Servers");
-
- if (clusterConfigFile.containsKey(cn)) {
+
+ String[] cnames = globalSection.getStringArray("Clusters");
+ for (String cname: cnames) {
+
+ SubnodeConfiguration sc = ini.getSection(cname);
+ QCClusterOptions opt = new QCClusterOptions();
+ opt.setWebPort(sc.getInt("WebPort"));
+ opt.setServers(sc.getStringArray("Servers"));
+ opt.setServerMaxCompleteQueries(sc.getInt("MaxCompleteQueries", 100));
+
+ if (ini.containsKey(cname)) {
throw new ConfigurationException("duplicate cluster definition");
}
- clusterConfigMap.put(cn, opt);
+ optionMap.put(cname, opt);
}
+ fullUpdateInterval = globalSection.getInt("FullUpdateInterval", 10 * 1000);
}
catch (Exception e) {
- LOG.error("error loading configuration.", e);
- System.exit(1);
- }
- }
-
- public class QCClusterThread implements Runnable {
- private class QCClusterFullUpdateTask extends TimerTask {
- @Override
- public void run() {
- if ( !QCClusterThread.this.fullUpdateTaskRunning.compareAndSet(false, true) ) {
- // update task is running. skip this time....
- LOG.warn("a full update task is running. skipping full update task");
- return;
- }
-
- QCClusterManager.qcMgr.UpdateClusters();
- lastFullUpdate = new Date();
- QCClusterThread.this.fullUpdateTaskRunning.set(false);
- }
+ throw new Exception("error loading configuration. "+iniFile, e);
}
- private class QCClusterWebSocketPingTask extends TimerTask {
- @Override
- public void run() {
- QCClusterManager.qcMgr.pingWebSockets();
- }
- }
-
- private class QCCounterUpdateTask extends TimerTask {
- @Override
- public void run() {
- for (QCCluster cluster: clusters) {
- cluster.updateCounters();
- }
- }
- }
- TimerTask qcTimerFull = new QCClusterFullUpdateTask();
- TimerTask qcTimerPingWebSockets = new QCClusterWebSocketPingTask();
- TimerTask qcCounterUpdateTask = new QCCounterUpdateTask();
-
- AtomicBoolean fullUpdateTaskRunning = new AtomicBoolean(false);
- Date lastFullUpdate = new Date();
-
- @Override
- public void run() {
- Timer timerFull = new Timer(true);
- Timer timerPingWebSockets = new Timer(true);
- Timer timerCounterUpdateTask = new Timer(true);
-
- timerFull.scheduleAtFixedRate(qcTimerFull, 0, fullUpdateInterval);
- timerPingWebSockets.scheduleAtFixedRate(qcTimerPingWebSockets, 0, pingWebSocketsInterval);
- timerCounterUpdateTask.scheduleAtFixedRate(qcCounterUpdateTask, 60*1000, 60*1000);
- while (!QCClusterManager.this.quitThread) {
- try {
- Thread.sleep(100);
- } catch (Exception e) {
- }
- }
-
- timerFull.cancel();
- timerPingWebSockets.cancel();
- }
- }
-
- public static QCClusterManager getInstance() {
- if (qcMgr == null) {
- qcMgr = new QCClusterManager();
- }
-
- return qcMgr;
- }
-
- private List clusters = new ArrayList<>();
- private Thread qcClusterThread = new Thread(this.new QCClusterThread());
- private boolean quitThread = false;
-
- protected QCClusterManager() {
- readConfiguration();
-
// initialize clusters;
- for (Map.Entry entry: clusterConfigMap.entrySet()) {
- QCCluster cluster = new QCCluster(entry.getKey(), entry.getValue());
- clusters.add(cluster);
+ for (String cname:optionMap.keySet()) {
+ QCCluster cluster = new QCCluster(cname, optionMap.get(cname), fullUpdateInterval);
+ clusterMap.put(cname, cluster);
}
-
- // initialize thread;
- qcClusterThread = new Thread(this.new QCClusterThread());
}
- public void startThread() {
- qcClusterThread.start();
+ public void start() {
+ for (QCCluster cluster:clusterMap.values()) {
+ cluster.start();
+ }
}
// stop
- public void finishThread() {
- quitThread = true;
- try {
- qcClusterThread.join();
- } catch (Exception e) {
- LOG.error("exception while waiting for thread " + e.toString());
- }
+ public void stop() {
+ for (QCCluster cluster:clusterMap.values()) {
+ cluster.close();
+ }
}
- public void UpdateClusters() {
- for (QCCluster cluster: clusters) {
- cluster.Update();
- }
- }
-
- public QCCluster getCluster(String clusterName) {
- for (QCCluster c: clusters) {
- if (c.name.equals(clusterName)) {
- return c;
- }
- }
- return null;
- }
-
- public Collection getClusterList() {
- List cl = new ArrayList<>();
- for (QCCluster c: clusters) {
- cl.add(c.name);
- }
- return cl;
+
+ public QCCluster getCluster(String name) {
+ return clusterMap.get(name);
}
- private void pingWebSockets() {
- for (QCCluster cluster: clusters) {
- for (QCServer server: cluster.getServers().values()) {
- QCClientWebSocket ws = server.getRtWebSocket();
- if (ws == null) {
- server.connectRealtimeWebSocket();
- }
- else {
- ws.ping();
- }
- }
- }
+ public List getClusterNameList() {
+ List list = new ArrayList<>(clusterMap.keySet());
+ Collections.sort(list);
+ return list;
}
}
diff --git a/src/main/java/com/skplanet/checkmate/querycache/QCClusterOptions.java b/src/main/java/com/skplanet/checkmate/querycache/QCClusterOptions.java
new file mode 100644
index 0000000..3d4ebb1
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/QCClusterOptions.java
@@ -0,0 +1,41 @@
+package com.skplanet.checkmate.querycache;
+
+public class QCClusterOptions {
+ private int webPort = 8080;
+ private int partialUpdateInterval = 3000;
+ private int fullUpdateInterval = 10000;
+ private int serverMaxCompleteQueries = 100;
+
+ private String[] servers;
+
+ public int getWebPort() {
+ return webPort;
+ }
+ public void setWebPort(int webPort) {
+ this.webPort = webPort;
+ }
+ public int getPartialUpdateInterval() {
+ return partialUpdateInterval;
+ }
+ public void setPartialUpdateInterval(int partialUpdateInterval) {
+ this.partialUpdateInterval = partialUpdateInterval;
+ }
+ public int getFullUpdateInterval() {
+ return fullUpdateInterval;
+ }
+ public void setFullUpdateInterval(int fullUpdateInterval) {
+ this.fullUpdateInterval = fullUpdateInterval;
+ }
+ public String[] getServers() {
+ return servers;
+ }
+ public void setServers(String[] servers) {
+ this.servers = servers;
+ }
+ public int getServerMaxCompleteQueries() {
+ return serverMaxCompleteQueries;
+ }
+ public void setServerMaxCompleteQueries(int serverMaxCompleteQueries) {
+ this.serverMaxCompleteQueries = serverMaxCompleteQueries;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/QCQuery.java b/src/main/java/com/skplanet/checkmate/querycache/QCQuery.java
index 3c9aa95..8cf2a58 100644
--- a/src/main/java/com/skplanet/checkmate/querycache/QCQuery.java
+++ b/src/main/java/com/skplanet/checkmate/querycache/QCQuery.java
@@ -1,169 +1,302 @@
package com.skplanet.checkmate.querycache;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
import org.apache.commons.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import java.util.Arrays;
-import java.util.Date;
+import com.skplanet.checkmate.querycache.data.QCQueryImport;
/**
* Created by nazgul33 on 15. 1. 27.
*/
public class QCQuery {
- private static final boolean DEBUG = false;
- public static class QueryImport {
- public String queryId;
- public String connType;
- public String user;
- public String queryType;
- public String queryStr;
- public String clientIp;
- public String stmtState;
- public long rowCnt;
- public long startTime;
- public long endTime;
- // 0:exec/1:getmeta/2:fetch/3:stmtclose or
- // 1:getschemas/2:fetch
- public long[] timeHistogram = {0,0,0,0};
- public long[] execProfile = null;
- public long[] fetchProfile = {0,0,0,-1,-1,-1,-1,0,0,-1,-1};
- }
- public static class QueryExport {
- public String cuqId; // cluster unique query id
- public String server;
- public String id;
- public String backend;
- public String user;
- public String type;
- public String statement;
- public String client;
- public String state;
- public long rowCnt = -1;
- public long startTime;
- public long endTime = 0;
- // 0:exec/1:getmeta/2:fetch/3:stmtclose or
- // 1:getschemas/2:fetch
- public long[] timeHistogram;
- public long[] execProfile;
- public long[] fetchProfile;
- public String cancelUrl;
- }
-
- private QCServer server;
-
- public final String cuqId;
- public final String id;
- public final String backend;
- public final String user;
- public String type;
- public final String statement;
- public final String client;
- public String state;
- public long rowCnt = -1;
- public final long startTime;
- public long endTime = 0;
+ private static final Logger LOG = LoggerFactory.getLogger(QCQuery.class);
+
+ private String cluster;
+ private String server;
+ private String id;
+ private String backend;
+ private String user;
+ private String type;
+ private String statement;
+ private String client;
+ private String state;
+ private long rowCnt = -1;
+ private long startTime;
+ private long endTime = 0;
// 0:exec/1:getmeta/2:fetch/3:stmtclose or
// 1:getschemas/2:fetch
- public long[] timeHistogram;
- public long[] execProfile;
- public long[] fetchProfile;
-
- public long updateTime = 0;
-
- public QCQuery(QCServer server, QueryImport qObj) {
- this.server = server;
- this.id = qObj.queryId;
- this.backend = qObj.connType;
- this.user = qObj.user;
- this.type = qObj.queryType;
- this.statement = qObj.queryStr;
- this.client = qObj.clientIp;
- this.state = qObj.stmtState;
- this.rowCnt = qObj.rowCnt;
- this.startTime = qObj.startTime;
- this.endTime = qObj.endTime;
- this.timeHistogram = qObj.timeHistogram;
- this.execProfile = qObj.execProfile;
- this.fetchProfile = qObj.fetchProfile;
-
- this.updateTime = new Date().getTime();
-
- this.cuqId = getCuqId(server, qObj);
- }
+ private long[] timeHistogram;
+ private long[] execProfile;
+ private long[] fetchProfile;
+
+ private String cuqId;
+ private String cancelUrl;
+
+ private long updateTime;
+ private long updateCount;
+ private boolean anormal = false;
+
+ public QCQuery(String cluster, String server, QCQueryImport qObj) {
+
+ this.cluster = cluster;
+ this.server = server;
+ this.id = qObj.getQueryId();
+ this.backend = qObj.getConnType();
+ this.user = qObj.getUser();
+ this.type = qObj.getQueryType();
+ this.statement = qObj.getQueryStr();
+ this.client = qObj.getClientIp();
+ this.state = qObj.getStmtState();
+ this.rowCnt = qObj.getRowCnt();
+ this.startTime = qObj.getStartTime();
+ this.endTime = qObj.getEndTime();
+ this.timeHistogram = qObj.getTimeHistogram();
+ this.execProfile = qObj.getExecProfile();
+ this.fetchProfile = qObj.getFetchProfile();
+
+ this.cuqId = getCuqId(cluster, server, qObj);
+ this.cancelUrl = "/api/qc/cancelQuery?cluster="+cluster+"&cuqId="+cuqId;
+
+ this.updateCount = 0;
+ this.updateTime = System.currentTimeMillis();
+}
+
+ public String getCluster() {
+ return cluster;
+ }
+
+ public void setCluster(String cluster) {
+ this.cluster = cluster;
+ }
+
+ public String getServer() {
+ return server;
+ }
+
+ public void setServer(String server) {
+ this.server = server;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getBackend() {
+ return backend;
+ }
+
+ public void setBackend(String backend) {
+ this.backend = backend;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getStatement() {
+ return statement;
+ }
+
+ public void setStatement(String statement) {
+ this.statement = statement;
+ }
+
+ public String getClient() {
+ return client;
+ }
+
+ public void setClient(String client) {
+ this.client = client;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
- public boolean Update(QCQuery qObj) {
+ public long getRowCnt() {
+ return rowCnt;
+ }
+
+ public void setRowCnt(long rowCnt) {
+ this.rowCnt = rowCnt;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public long getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(long endTime) {
+ this.endTime = endTime;
+ }
+
+ public long[] getTimeHistogram() {
+ return timeHistogram;
+ }
+
+ public void setTimeHistogram(long[] timeHistogram) {
+ this.timeHistogram = timeHistogram;
+ }
+
+ public long[] getExecProfile() {
+ return execProfile;
+ }
+
+ public void setExecProfile(long[] execProfile) {
+ this.execProfile = execProfile;
+ }
+
+ public long[] getFetchProfile() {
+ return fetchProfile;
+ }
+
+ public void setFetchProfile(long[] fetchProfile) {
+ this.fetchProfile = fetchProfile;
+ }
+
+ public long getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(long updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public long getUpdateCount() {
+ return updateCount;
+ }
+
+ public void setUpdateCount(long updateCount) {
+ this.updateCount = updateCount;
+ }
+
+ public String getCuqId() {
+ return cuqId;
+ }
+
+ public void setCuqId(String cuqId) {
+ this.cuqId = cuqId;
+ }
+
+ public String getCancelUrl() {
+ return cancelUrl;
+ }
+
+ public void setCancelUrl(String cancelUrl) {
+ this.cancelUrl = cancelUrl;
+ }
+
+ public boolean isAnormal() {
+ return anormal;
+ }
+
+ public void setAnormal(boolean anormal) {
+ this.anormal = anormal;
+ }
+
+ public static boolean update(QCQuery oq, QCQuery nq) {
+
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
boolean updated = false;
- if ( !this.type.equals(qObj.type) ) {
- if (DEBUG) System.console().printf("query %s update type %s -> %s\n", id, type, qObj.type);
- this.type = qObj.type;
+ if (!oq.getType().equals(nq.getType())) {
+ LOG.debug("query {} update type {} -> {}", oq.getId(), oq.getType(), nq.getType());
+ oq.setType(nq.getType());
updated = true;
}
- if ( !this.state.equals(qObj.state) ) {
- if (DEBUG) System.console().printf("query %s update state %s -> %s\n", id, state, qObj.state);
- this.state = qObj.state;
+ if (!oq.getState().equals(nq.getState())) {
+ LOG.debug("query {} update state {} -> {}", oq.getId(), oq.getState(), nq.getState());
+ oq.setState(nq.getState());
updated = true;
}
- if ( this.rowCnt != qObj.rowCnt ) {
- if (DEBUG) System.console().printf("query %s update rowCnt %s -> %s\n", id, rowCnt, qObj.rowCnt);
- this.rowCnt = qObj.rowCnt;
+ if (oq.getRowCnt() != nq.getRowCnt() ) {
+ LOG.debug("query {} update rowCnt {} -> {}", oq.getId(), oq.getRowCnt(), nq.getRowCnt());
+ oq.setRowCnt(nq.getRowCnt());
updated = true;
}
- if ( this.endTime != qObj.endTime ) {
- if (DEBUG) System.console().printf("query %s update rowCnt %s -> %s\n", id, endTime, qObj.endTime);
- this.endTime = qObj.endTime;
+ if (oq.getEndTime() != nq.getEndTime()) {
+ LOG.debug("query {} update endTime {} -> %s", oq.getId(),
+ sdf.format(new Date(oq.getEndTime())),
+ sdf.format(new Date(nq.getEndTime())));
+ oq.setEndTime(nq.endTime);
updated = true;
}
-// if ( !Arrays.equals(this.timeHistogram, qObj.timeHistogram) ) {
-// this.timeHistogram = qObj.timeHistogram;
-// updated = true;
-// }
-// if ( !Arrays.equals(this.execProfile, qObj.execProfile) ) {
-// this.execProfile = qObj.execProfile;
-// updated = true;
-// }
-// if ( !Arrays.equals(this.fetchProfile, qObj.fetchProfile) ) {
-// this.fetchProfile = qObj.fetchProfile;
-// updated = true;
-// }
-
if (updated) {
- this.updateTime = new Date().getTime();
+ oq.setUpdateTime(System.currentTimeMillis());
+ oq.setUpdateCount(oq.getUpdateCount()+1);
}
return updated;
}
- public static String getCuqId(QCServer server, QCQuery.QueryImport qi) {
- String cuqid = new String(Base64.encodeBase64((server.name+qi.connType+qi.queryId).trim().toUpperCase().getBytes()));
+ public static String getCuqId(String cluster, String server, QCQueryImport qi) {
+ String key = server+qi.getConnType()+qi.getQueryId();
+ String cuqid = Base64.encodeBase64String(key.trim().getBytes());
return cuqid.replace('+',':').replace('/','.').replace('=','-');
}
- public QueryExport export() {
- QueryExport eq = new QueryExport();
- eq.cuqId = cuqId;
- // remove characters not supported by html4 standard for id field.
-
- eq.server = server.name;
- eq.id = id;
- eq.backend = backend;
- eq.user = user;
- eq.type = type;
- eq.statement = statement;
- eq.client = client;
- eq.state = state;
- eq.rowCnt = rowCnt;
- eq.startTime = startTime;
- eq.endTime = endTime;
- eq.timeHistogram = new long[timeHistogram.length];
- System.arraycopy(eq.timeHistogram, 0, timeHistogram, 0, timeHistogram.length);
- if (execProfile != null) {
- eq.execProfile = new long[execProfile.length];
- System.arraycopy(eq.execProfile, 0, execProfile, 0, execProfile.length);
- }
- eq.fetchProfile = new long[fetchProfile.length];
- System.arraycopy(eq.fetchProfile, 0, fetchProfile, 0, fetchProfile.length);
- // eq.cancelUrl = "http://" + server.name + ":" + server.cluster.getOpt().webPort + "/api/cancelQuery?id="+id+"&driver="+backend;
- eq.cancelUrl = "/api/qc/cancelQuery?cluster="+server.cluster.name+"&cuqId="+eq.cuqId;
- return eq;
- }
+ public boolean equals(Object o) {
+ return o instanceof QCQuery && cuqId.equals(((QCQuery)o).getCuqId());
+ }
+
+// public QueryExport export() {
+//
+// QueryExport qe = new QueryExport();
+// qe.setCuqId(cuqId);
+// qe.setServer(server);
+// qe.setId(id);
+// qe.setBackend(backend);
+// qe.setUser(user);
+// qe.setType(type);
+// qe.setStatement(statement);
+// qe.setClient(client);
+// qe.setState(state);
+// qe.setRowCnt(rowCnt);
+// qe.setStartTime(startTime);
+// qe.setEndTime(endTime);
+// long[] cloneHistogram = new long[timeHistogram.length];
+// System.arraycopy(timeHistogram, 0, cloneHistogram, 0, timeHistogram.length);
+// qe.setTimeHistogram(cloneHistogram);
+// if (execProfile != null) {
+// long[] cloneExec = new long[execProfile.length];
+// System.arraycopy(execProfile, 0, cloneExec, 0, execProfile.length);
+// qe.setExecProfile(cloneExec);
+// }
+// long [] cloneFetch = new long[fetchProfile.length];
+// System.arraycopy(fetchProfile, 0, cloneFetch, 0, fetchProfile.length);
+// qe.setFetchProfile(cloneFetch);
+// qe.setCancelUrl("/api/qc/cancelQuery?cluster="+cluster+"&cuqId="+cuqId);
+// return qe;
+// }
}
diff --git a/src/main/java/com/skplanet/checkmate/querycache/QCQueryMail.java b/src/main/java/com/skplanet/checkmate/querycache/QCQueryMail.java
index 6beae7f..cafeb30 100644
--- a/src/main/java/com/skplanet/checkmate/querycache/QCQueryMail.java
+++ b/src/main/java/com/skplanet/checkmate/querycache/QCQueryMail.java
@@ -1,22 +1,25 @@
package com.skplanet.checkmate.querycache;
-import com.skplanet.checkmate.utils.MailSender;
-import org.apache.commons.lang.time.DateUtils;
-
+import java.text.SimpleDateFormat;
import java.util.Date;
+import com.skplanet.checkmate.utils.MailSender;
+
/**
* Created by nazgul33 on 4/8/16.
*/
public class QCQueryMail extends MailSender.Mail {
- public QCQueryMail(QCQuery.QueryExport query, String subject, String content) {
- super(subject, content);
- setContent( content + "\n\n" + queryToMailContent(query) );
- }
+
+ public QCQueryMail(QCQuery query, String subject, String content) {
+ super(subject);
+ setContent(content + "\n\n" + queryToMailContent(query) );
+ }
+
+ public static String queryToMailContent(QCQuery query) {
- static String queryToMailContent(QCQuery.QueryExport query) {
- StringBuilder sb = new StringBuilder();
- /*
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ StringBuilder sb = new StringBuilder();
+ /*
public String cuqId; // cluster unique query id
public String server;
public String id;
@@ -35,18 +38,18 @@ static String queryToMailContent(QCQuery.QueryExport query) {
public long[] execProfile;
public long[] fetchProfile;
public String cancelUrl;
- */
- sb.append("Server : ").append(query.server).append('\n');
- sb.append("QueryId : ").append(query.id).append('\n');
- sb.append("Backend : ").append(query.backend).append('\n');
- sb.append("User : ").append(query.user).append('\n');
- sb.append("State : ").append(query.state).append('\n');
- sb.append("Fetched Rows : ").append(query.rowCnt).append('\n');
- sb.append("StartTime : ").append( new Date(query.startTime) ).append('\n');
- sb.append("Now : ").append( new Date() ).append('\n');
+ */
+ sb.append("Server : ").append(query.getServer()).append('\n');
+ sb.append("QueryId : ").append(query.getId()).append('\n');
+ sb.append("Backend : ").append(query.getBackend()).append('\n');
+ sb.append("User : ").append(query.getUser()).append('\n');
+ sb.append("State : ").append(query.getState()).append('\n');
+ sb.append("Fetched Rows : ").append(query.getRowCnt()).append('\n');
+ sb.append("StartTime : ").append( sdf.format(new Date(query.getStartTime())) ).append('\n');
+ sb.append("Now : ").append( sdf.format(new Date()) ).append('\n');
- sb.append("SQL : ").append(query.statement).append('\n');
+ sb.append("SQL : ").append(query.getStatement()).append('\n');
- return sb.toString();
- }
+ return sb.toString();
+ }
}
diff --git a/src/main/java/com/skplanet/checkmate/querycache/QCServer.java b/src/main/java/com/skplanet/checkmate/querycache/QCServer.java
index 9136a28..8a29110 100644
--- a/src/main/java/com/skplanet/checkmate/querycache/QCServer.java
+++ b/src/main/java/com/skplanet/checkmate/querycache/QCServer.java
@@ -1,436 +1,356 @@
package com.skplanet.checkmate.querycache;
-import com.codahale.metrics.Histogram;
-import com.codahale.metrics.Meter;
-import com.codahale.metrics.SlidingTimeWindowReservoir;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-import com.skplanet.checkmate.CheckMateServer;
-import com.skplanet.checkmate.utils.HttpUtil;
+import static java.lang.String.format;
import java.net.ConnectException;
-import java.net.URI;
import java.net.URISyntaxException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
-import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.SlidingTimeWindowReservoir;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.skplanet.checkmate.CheckMateServer;
+import com.skplanet.checkmate.querycache.data.QCQueryEvent;
+import com.skplanet.checkmate.querycache.data.QCQueryImport;
+import com.skplanet.checkmate.querycache.data.ServerConDesc;
+import com.skplanet.checkmate.querycache.data.ServerObjectPool;
+import com.skplanet.checkmate.querycache.data.ServerQueries;
+import com.skplanet.checkmate.querycache.data.ServerSystemStats;
+import com.skplanet.checkmate.utils.HttpUtil;
+
/**
* Created by nazgul33 on 15. 1. 27.
*/
public class QCServer {
- private static final boolean DEBUG = false;
- private static final Logger LOG = LoggerFactory.getLogger("querycache");
- private static final int MAX_COMPLETE_QUERIES = 100;
- private final Histogram histogram;
-
- // inner-classes below are for gson conversion from json object.
- // NOTICE!
- // sync between QCWebApiServlet
- public static class ConDesc {
- public String driver;
- public int free;
- public int using;
- }
-
- public static class RuntimeInfo {
- public int nProcessors;
- public long memFree;
- public long memTotal;
- public long memMax;
- }
-
- public static class ThreadInfo {
- public int webServerThreads;
- public int webServerThreadsIdle;
- public int handlerThreads;
- public int handlerThreadsIdle;
- public int totalThreads;
- }
-
- public static class SystemInfo {
- public double loadSystem;
- public double loadProcess;
- public long memPhysFree;
- public long memPhysTotal;
- public long swapFree;
- public long swapTotal;
- }
-
- public static class ObjectPool {
- // configuration
- public long sReloadCycle = 0;
- public int sMaxPoolSize = 0;
- public float sReloadingThreshold = 0;
- public int sCellCoeff = 0;
- public int[] poolSize = {0, 0, 0, 0};
- }
-
- public static class Queries {
- public List runningQueries = new ArrayList<>();
- public List completeQueries = new ArrayList<>();
- }
+
+ private static final Logger LOG = LoggerFactory.getLogger(QCServer.class);
+
+ private int MAX_COMPLETE_QUERIES = 100;
+
+ private Histogram histogram;
- public static class SysInfoCollection {
- public RuntimeInfo jvm;
- public SystemInfo system;
- public ThreadInfo threads;
- }
-
- public final String name;
- private Map queriesRunning;
- private Map queriesComplete;
- public final QCCluster cluster;
+ private String name;
+ private Map runningMap;
+ private Map completeMap;
+ private QCCluster cluster;
+ private QCClusterOptions clusterOpt;
- private List connections = null;
- private ObjectPool objectPool = null;
- private SysInfoCollection sysInfoCollection = null;
+ private String wsUrl;
+ private List conDescList;
+ private ServerObjectPool objectPool;
+ private ServerSystemStats systemStats;
- private long lastQueryUpdate = 0;
+ private long lastExceptionTime;
- private boolean online;
- private String lastException;
+ private QCWebSocketClient wsClient;
private AtomicInteger queryCount = new AtomicInteger(0);
- QCServer(String name, QCCluster cluster) {
- this.name = name;
- queriesRunning = new HashMap<>();
- queriesComplete = new LinkedHashMap() {
- protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > MAX_COMPLETE_QUERIES;
- }
- };
- online = false;
+ private String queriesUrl;
+ private String systemUrl;
+ private String connectionUrl;
+ private String objectpoolUrl;
+
+ public QCServer(QCCluster cluster, String name) throws URISyntaxException {
+
this.cluster = cluster;
+ this.clusterOpt = cluster.getOptions();
+ this.name = name;
- connectRealtimeWebSocket();
-
- StringBuffer sb = new StringBuffer();
- sb.append("queries.").append(cluster.name).append('.').append(this.name);
+ this.MAX_COMPLETE_QUERIES = cluster.getOptions().getServerMaxCompleteQueries();
+
+ this.runningMap = new HashMap<>();
+ this.completeMap = new LimitHashMap<>(MAX_COMPLETE_QUERIES);
+
+ this.wsUrl = format("ws://%s:%s%s", name, clusterOpt.getWebPort(), "/api/websocket");
+ this.wsClient = new QCWebSocketClient(this, wsUrl);
+
+ int webPort = cluster.getOptions().getWebPort();
+ this.queriesUrl = format("http://%s:%s/api/queries", name, webPort);
+ this.systemUrl = format("http://%s:%s/api/system", name, webPort);
+ this.connectionUrl = format("http://%s:%s/api/connections", name, webPort);
+ this.objectpoolUrl = format("http://%s:%s/api/objectpool", name, webPort);
+
+ String metricName = format("queries.%s.%s",cluster.getName(),name);
histogram = new Histogram( new SlidingTimeWindowReservoir(5L, TimeUnit.MINUTES) );
- CheckMateServer.getMetrics().register(sb.toString(), histogram);
+ CheckMateServer.getMetrics().register(metricName, histogram);
}
-
- public int updateQueryCount() {
- int count = queryCount.getAndSet(0);
- histogram.update(count);
- return count;
+
+ public String getName() {
+ return name;
}
-
- public boolean isOnline() {
- return online;
+
+ public QCCluster getCluster() {
+ return cluster;
}
- public void setOnline(boolean online) {
- this.online = online;
+ public void start() {
+ wsClient.start();
}
-
- public String getLastException() {
- return lastException;
+
+ public void stop() {
+ wsClient.stop();
}
-
- public void setLastException(Exception e) {
- this.lastException = e.getMessage();
- }
-
- public Collection getRunningQueries() {
- Collection ql;
- synchronized (queriesRunning) {
- ql = queriesRunning.values();
- }
- return ql;
- }
-
- public Collection getCompleteQueries() {
- Collection ql;
- synchronized (queriesComplete) {
- ql = queriesComplete.values();
- }
- return ql;
- }
-
- public void Update() {
- // update routines below will set offline when update is failed.
- this.setOnline(true);
-
- UpdateQueries();
- lastQueryUpdate = new Date().getTime();
- UpdateConnections();
- UpdateObjectPools();
- UpdateSystem();
- }
-
- protected String getUrl(String path) {
- return "http://" + this.name + ":" + cluster.getOpt().webPort + path;
+
+ public int getAndResetQueryCount() {
+ int count = queryCount.getAndSet(0);
+ histogram.update(count);
+ return count;
}
- protected void processAddQueryEvent(QCQuery q) {
- QCQuery qExisting;
- synchronized (queriesRunning) {
- qExisting = queriesRunning.get(q.cuqId);
- if (qExisting != null) {
- if( !qExisting.Update(q) ) {
- // not updated : do nothing
- return;
- }
- } else {
- this.queriesRunning.put(q.cuqId, q);
- queryCount.incrementAndGet();
- }
- }
- this.cluster.addExportedRunningQuery(q);
+ private void setLastException() {
+ this.lastExceptionTime = System.currentTimeMillis();
}
- protected void processRemoveQueryEvent(QCQuery q) {
- synchronized (queriesRunning) {
- this.queriesRunning.remove(q.cuqId);
- }
- this.cluster.removeExportedRunningQuery(q);
+ public void updateApi() {
+
+ if (lastExceptionTime > 0 && lastExceptionTime + 60*1000 > System.currentTimeMillis()) {
+ return;
+ }
+ LOG.debug("updateApi {}.{}", cluster.getName(), name);
+ updateApiQueries();
+ updateApiConnections();
+ updateApiObjectPools();
+ updateApiSystem();
}
- protected void UpdateQueries() {
- HttpUtil httpUtil = new HttpUtil();
- StringBuffer buf = new StringBuffer();
- int res = 0;
-
+ private void updateApiQueries() {
+
+ long t0 = System.currentTimeMillis();
try {
- res = httpUtil.get( getUrl("/api/queries"), buf);
- if (res == 200) {
- Gson gSon = new Gson();
- Queries queries = gSon.fromJson(buf.toString(), Queries.class);
- synchronized (queriesRunning) {
- int added = 0;
- int removed = 0;
- int updated = 0;
- List rqList = new ArrayList<>();
- Map rqMap = new HashMap<>();
- // process "current" running query list
- for (QCQuery.QueryImport qi : queries.runningQueries) {
- // add to map for reverse existence check below.
- QCQuery q = new QCQuery(this, qi);
- rqList.add(q);
- rqMap.put(q.cuqId, q);
- }
-
- // cross check queries in my list to remove "disappeared" queries.
- Iterator> it = queriesRunning.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry entry = it.next();
- if (!rqMap.containsKey(entry.getKey())) {
- this.cluster.removeExportedRunningQuery(entry.getValue());
- it.remove();
- removed++;
- }
- }
-
- for (QCQuery q : rqList) {
- QCQuery qExisting = queriesRunning.get(q.cuqId);
- if (qExisting != null) {
- if ( qExisting.Update(q) ) {
- updated++;
- this.cluster.addExportedRunningQuery(qExisting);
- }
- } else {
- this.queriesRunning.put(q.cuqId, q);
- added++;
- this.cluster.addExportedRunningQuery(q);
- queryCount.incrementAndGet();
- }
- }
-
- if (DEBUG) {
- LOG.debug(this.name + ": running queries +" + added + " #" + updated + " -" + removed);
- }
- }
-
- synchronized (queriesComplete) {
- int added = 0;
-
- // process "current" complete query list
- // sort key endTime, ascending
- Collections.sort(queries.completeQueries, new Comparator() {
- @Override
- public int compare(QCQuery.QueryImport o1, QCQuery.QueryImport o2) {
- return (o2.endTime > o1.endTime) ? 1 : (o2.endTime == o1.endTime) ? 0 : -1;
- }
- });
-
- for (QCQuery.QueryImport qi : queries.completeQueries) {
- String cuqId = QCQuery.getCuqId(this, qi);
- // complete query has no changes. process new complete queries only.
- if (!this.queriesComplete.containsKey(cuqId)) {
- QCQuery q = new QCQuery(this, qi);
- this.queriesComplete.put(cuqId, q);
- cluster.queueCompleteQuery(q);
- added++;
- }
- }
-
- if (DEBUG) {
- LOG.debug("{} : cq size = {}(+{})",
- this.name, this.queriesComplete.size(), added);
+ String content = HttpUtil.get(queriesUrl);
+ Gson gSon = new Gson();
+ ServerQueries queries = gSon.fromJson(content, ServerQueries.class);
+
+ List runningList = new ArrayList<>(queries.getRunningQueries().size());
+ for (QCQueryImport qi:queries.getRunningQueries()) {
+ QCQuery query = new QCQuery(cluster.getName(), name, qi);
+ runningList.add(query);
+ }
+ List completeList = new ArrayList<>(queries.getCompleteQueries().size());
+ for (QCQueryImport qi:queries.getCompleteQueries()) {
+ QCQuery query = new QCQuery(cluster.getName(), name, qi);
+ completeList.add((query));
+ }
+
+ synchronized(runningMap) {
+
+ Iterator> iter = runningMap.entrySet().iterator();
+ while (iter.hasNext()) {
+ Entry entry = iter.next();
+ QCQuery value = entry.getValue();
+ if (!runningList.contains(value)) {
+ int compIdx = completeList.indexOf(value);
+ if (compIdx > -1) {
+ cluster.addQueryEvent(QCQueryEvent.RUN_QUERY_REMOVED, completeList.get(compIdx));
+ } else {
+ cluster.addQueryEvent(QCQueryEvent.RUN_QUERY_REMOVED, value);
+ }
+ iter.remove();
+ }
+ }
+
+ for (QCQuery query:runningList) {
+ QCQuery rquery = runningMap.get(query.getCuqId());
+ if (rquery != null) {
+ if (QCQuery.update(rquery, query)) {
+ cluster.addQueryEvent(QCQueryEvent.RUN_QUERY_UPDATED, rquery);
+ }
+ } else {
+ runningMap.put(query.getCuqId(), query);
+ cluster.addQueryEvent(QCQueryEvent.RUN_QUERY_ADDED, query);
+ queryCount.incrementAndGet();
+ }
+ }
+ }
+
+ synchronized (completeMap) {
+ int added = 0;
+ for (QCQuery query : completeList) {
+ // complete query has no changes. process new complete queries only.
+ if (!completeMap.containsKey(query.getCuqId())) {
+ completeMap.put(query.getCuqId(), query);
+ cluster.addQueryEvent(QCQueryEvent.RUN_QUERY_REMOVED, query);
+ added++;
}
}
+ LOG.debug("{}.{} : complete query. add={}, total={}",
+ cluster.getName(), name, added, completeMap.size());
}
+
+ long t1 = System.currentTimeMillis();
+ LOG.debug("update queries {} {} : took={}, run={}, complete={}",
+ cluster.getName(), name, (t1-t0), runningList.size(), completeList.size());
+ } catch (ConnectException e) {
+ LOG.error("{}.{}: updating queries : {} {}",
+ cluster.getName(), name, queriesUrl, e.getMessage());
} catch (Exception e) {
- if (e instanceof ConnectException) {
- LOG.error(this.name + ": updating queries: connection refused.");
- this.setOnline(false);
- this.setLastException(e);
- }
- else {
- LOG.error(this.name + ": updating queries: ", e);
- this.setLastException(e);
- }
+ LOG.error("{}.{}: updating queries : {} {}",
+ cluster.getName(), name, queriesUrl, e.getMessage(), e);
+ setLastException();
}
}
-
- protected void UpdateConnections() {
- HttpUtil httpUtil = new HttpUtil();
- StringBuffer buf = new StringBuffer();
- int res = 0;
+
+ private void updateApiConnections() {
+ conDescList = null;
try {
- res = httpUtil.get( getUrl("/api/connections"), buf);
- if (res == 200) {
- Gson gSon = new Gson();
- connections = gSon.fromJson(buf.toString(), new TypeToken>() {}.getType());
- if (DEBUG) {
- for (ConDesc con: connections) {
- LOG.debug(this.name + " con " + con.driver + " free " + con.free + " using " + con.using);
- }
+ String content = HttpUtil.get(connectionUrl);
+ Gson gSon = new Gson();
+ conDescList = gSon.fromJson(content, new TypeToken>(){}.getType());
+ if (LOG.isDebugEnabled()) {
+ for (ServerConDesc con: conDescList) {
+ LOG.debug("{}.{} con={} free={} using={}",
+ cluster.getName(), name,
+ con.getDriver(), con.getFree(), con.getUsing());
}
}
+ } catch (ConnectException e) {
+ LOG.error("{}.{}: updating connections : {} {}",
+ cluster.getName(), name, connectionUrl, e.getMessage());
} catch (Exception e) {
- if (e instanceof ConnectException) {
- LOG.error(this.name + ": updating connections: connection refused.");
- this.setOnline(false);
- this.setLastException(e);
- }
- else {
- LOG.error(this.name + ": updating connections,", e);
- this.setLastException(e);
- }
+ LOG.error("{}.{}: updating connections : {} {}",
+ cluster.getName(), name, connectionUrl, e.getMessage(), e);
+ setLastException();
}
}
- protected void UpdateObjectPools() {
- HttpUtil httpUtil = new HttpUtil();
- StringBuffer buf = new StringBuffer();
- int res = 0;
+ private void updateApiObjectPools() {
+ objectPool = null;
try {
- res = httpUtil.get( getUrl("/api/objectpool"), buf);
- if (res == 200) {
- Gson gSon = new Gson();
- objectPool = gSon.fromJson(buf.toString(), ObjectPool.class);
- if (DEBUG) {
- LOG.debug(this.name + " pool " + objectPool.poolSize[0] + "," +
- objectPool.poolSize[1] + "," +
- objectPool.poolSize[2] + "," +
- objectPool.poolSize[3]);
- }
- }
+ String content = HttpUtil.get(objectpoolUrl);
+ Gson gSon = new Gson();
+ objectPool = gSon.fromJson(content, ServerObjectPool.class);
+ LOG.debug("{}.{} pool {} {} {} {} {}",
+ cluster.getName(),
+ name,
+ objectPool.getPoolSize()[0],
+ objectPool.getPoolSize()[1],
+ objectPool.getPoolSize()[2],
+ objectPool.getPoolSize()[3]);
+ } catch (ConnectException e) {
+ LOG.error("{}.{}: updating object pools : {} {}",
+ cluster.getName(), name, objectpoolUrl, e.getMessage());
+ setLastException();
} catch (Exception e) {
- if (e instanceof ConnectException) {
- LOG.error(this.name + ": updating pools: connection refused.");
- this.setOnline(false);
- this.setLastException(e);
- }
- else {
- LOG.error(this.name + ": updating pools,", e);
- this.setLastException(e);
- }
+ LOG.error("{}.{}: updating object pools : {} {}",
+ cluster.getName(), name, objectpoolUrl, e.getMessage(), e);
+ setLastException();
}
}
- protected void UpdateSystem() {
- HttpUtil httpUtil = new HttpUtil();
- StringBuffer buf = new StringBuffer();
- int res = 0;
+ private void updateApiSystem() {
+ systemStats = null;
try {
- res = httpUtil.get( getUrl("/api/system"), buf);
- if (res == 200) {
- Gson gSon = new Gson();
- sysInfoCollection = gSon.fromJson(buf.toString(), SysInfoCollection.class);
- if (DEBUG) {
- LOG.debug(this.name + " total threads " + sysInfoCollection.threads.totalThreads);
- LOG.debug(this.name + " runtime mem used " + (sysInfoCollection.jvm.memTotal - sysInfoCollection.jvm.memFree));
- }
- }
+ String content = HttpUtil.get(systemUrl);
+ Gson gSon = new Gson();
+ systemStats = gSon.fromJson(content, ServerSystemStats.class);
+
+ LOG.debug("{}.{} total threads={}, runtime memused={}",
+ cluster.getName(), name,
+ systemStats.getThreads().getTotalThreads(),
+ (systemStats.getJvm().getMemTotal() - systemStats.getJvm().getMemFree())
+ );
+ } catch (ConnectException e) {
+ LOG.error("{}.{}: updating system stats : {} {}",
+ cluster.getName(), name, systemUrl, e.getMessage());
+ setLastException();
} catch (Exception e) {
- if (e instanceof ConnectException) {
- LOG.error(this.name + ": updating system stats: connection refused.");
- this.setOnline(false);
- this.setLastException(e);
- }
- else {
- LOG.error(this.name + ": updating system stats,", e);
- this.setLastException(e);
- }
+ LOG.error("{}.{}: updating system stats : {} {}",
+ cluster.getName(), name, systemUrl, e.getMessage(), e);
+ setLastException();
}
}
- public Collection exportRunningQueries() {
- List ql;
- synchronized (queriesRunning) {
- ql = new ArrayList<>(queriesRunning.size());
- for(QCQuery q: queriesRunning.values()) {
- ql.add( q.export() );
- }
- }
- return ql;
+ public ServerSystemStats getSystemStats() {
+ return systemStats;
}
- public Collection exportCompleteQueries() {
- List ql;
- synchronized (queriesComplete) {
- ql = new ArrayList<>(queriesComplete.size());
- for(QCQuery q: queriesComplete.values()) {
- ql.add( q.export() );
- }
- }
- return ql;
+ public ServerObjectPool getObjectPool() {
+ return objectPool;
}
- public SysInfoCollection getSysInfoCollection() {
- return sysInfoCollection;
+ public List getConnDescList() {
+ return conDescList;
}
-
- public ObjectPool getObjectPool() {
- return objectPool;
+
+ public List getRunningQueryList() {
+ synchronized(runningMap) {
+ return new ArrayList<>(runningMap.values());
+ }
}
-
- public List getConnections() {
- return connections;
+
+ public QCQuery getRunningQueryByCuqId(String cuqId) {
+ synchronized(runningMap) {
+ return runningMap.get(cuqId);
+ }
}
-
- private QCClientWebSocket rtWebSocket = null;
- public QCClientWebSocket getRtWebSocket() {
- return rtWebSocket;
+
+ public List getCompleteQueryList() {
+ synchronized(completeMap) {
+ return new ArrayList<>(completeMap.values());
+ }
}
- public void removeRtWebSocket() {
- rtWebSocket = null;
+
+ public void processWebSocketAddEvent(QCQueryImport queryImport) {
+
+ QCQuery query = new QCQuery(cluster.getName(), name, queryImport);
+ synchronized(runningMap) {
+ QCQuery rquery = runningMap.get(query.getCuqId());
+ if (rquery != null) {
+ boolean updated = QCQuery.update(rquery, query);
+ if (updated) {
+ cluster.addQueryEvent(QCQueryEvent.RUN_QUERY_UPDATED, rquery);
+ }
+ } else {
+ runningMap.put(query.getCuqId(), query);
+ queryCount.incrementAndGet();
+ cluster.addQueryEvent(QCQueryEvent.RUN_QUERY_ADDED, query);
+ }
+ }
}
- public void connectRealtimeWebSocket() {
- String uri = "ws://" + this.name + ":" + cluster.getOpt().webPort + "/api/websocket";
- WebSocketClient c = new WebSocketClient();
- QCClientWebSocket s = new QCClientWebSocket(this);
- rtWebSocket = null;
- try {
- c.start();
- URI rtUri = new URI(uri);
- ClientUpgradeRequest req = new ClientUpgradeRequest();
- c.connect(s, rtUri, req);
- rtWebSocket = s;
- } catch (URISyntaxException e) {
- LOG.error("invalid uri " + uri, e);
- } catch (Exception e) {
- LOG.error("websocket client error", e);
- }
+
+ public void processWebSocketRemoveEvent(QCQueryImport queryImport) {
+
+ QCQuery query = new QCQuery(cluster.getName(), name, queryImport);
+ synchronized(runningMap) {
+ if (runningMap.containsKey(query.getCuqId())) {
+ runningMap.remove(query.getCuqId());
+ }
+ }
+ synchronized(completeMap) {
+ if (!completeMap.containsKey(query.getCuqId())) {
+ completeMap.put(query.getCuqId(), query);
+ cluster.addQueryEvent(QCQueryEvent.RUN_QUERY_REMOVED, query);
+ }
+ }
}
+
+ private class LimitHashMap extends LinkedHashMap {
+
+ private static final long serialVersionUID = -3768283519827515112L;
+
+ private int MAX_SIZE = 0;
+
+ public LimitHashMap(int maxSize) {
+ super();
+ this.MAX_SIZE = maxSize;
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > MAX_SIZE;
+ }
+ };
}
diff --git a/src/main/java/com/skplanet/checkmate/querycache/QCWebSocketClient.java b/src/main/java/com/skplanet/checkmate/querycache/QCWebSocketClient.java
new file mode 100644
index 0000000..57f3914
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/QCWebSocketClient.java
@@ -0,0 +1,224 @@
+package com.skplanet.checkmate.querycache;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketListener;
+import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
+import org.eclipse.jetty.websocket.client.WebSocketClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.skplanet.checkmate.querycache.data.QCQueryImport;
+
+/**
+ * Created by nazgul33 on 15. 2. 23.
+ */
+public class QCWebSocketClient implements WebSocketListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(QCWebSocketClient.class);
+
+ public static final String EVENT_RUN_QUERY_ADDED = "runningQueryAdded";
+ public static final String EVENT_RUN_QUERY_UPDATED = "runningQueryUpdated";
+ public static final String EVENT_RUN_QUERY_REMOVED = "runningQueryRemoved";
+ public static final String EVENT_RESULT = "result";
+ public static final String EVENT_PONG = "pong";
+
+ private WebSocketClient client;
+ private Session session;
+ private long errorCount = 0;
+ private static final long MAX_ERROR_COUNT = 10;
+
+ private Timer timer = new Timer(true);
+
+ private QCServer listener;
+ private String cluster;
+ private String url;
+ private URI uri;
+
+ public QCWebSocketClient(final QCServer server, final String url) throws URISyntaxException {
+
+ this.cluster = server.getCluster().getName();
+ this.listener = server;
+ this.url = url;
+ this.uri = new URI(url);
+
+ client = new WebSocketClient();
+ client.setDaemon(true);
+ }
+
+ public void start() {
+ timer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ if (session == null || !session.isOpen()) {
+ connect();
+ }
+ } catch (Exception e) {
+ errorCount++;
+ LOG.error("websocket error {} {} {}",
+ listener.getCluster().getName(),
+ url,
+ e.getMessage());
+ }
+ if (errorCount > MAX_ERROR_COUNT) {
+ try {
+ TimeUnit.MINUTES.sleep(1);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }, 0, 5*1000);
+ timer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ ping();
+ }
+ }, 0, 5*1000);
+ }
+
+ public void stop() {
+ timer.cancel();
+ if (session != null) {
+ session.close();
+ }
+ if (client != null) {
+ try {
+ client.stop();
+ } catch (Exception e) {
+ LOG.error("webclient stop failed. {} {}", cluster, url, e);
+ }
+ }
+ }
+
+ private void connect() throws Exception {
+ try {
+ if (!client.isStarted()) {
+ client.start();
+ }
+ ClientUpgradeRequest req = new ClientUpgradeRequest();
+ client.connect(this, uri, req);
+ errorCount = 0;
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+
+ @Override
+ public void onWebSocketBinary(byte[] payload, int offset, int len) {
+ /* not interested */
+ }
+
+ @Override
+ public void onWebSocketClose(int statusCode, String reason) {
+ LOG.info("websocket closed {} {} statusCode={}, reason={}",
+ cluster, url, statusCode, reason);
+ try {
+ session.disconnect();
+ } catch (IOException e) {
+ LOG.error("websocket session error {} {} {}", cluster, url, e.getMessage());
+ }
+ }
+
+ @Override
+ public void onWebSocketConnect(Session session) {
+
+ this.session = session;
+ LOG.info("websocket connected {} {}", cluster, url);
+
+ RequestMsg req = new RequestMsg();
+ req.request = "subscribe";
+ req.channel = "runningQueries";
+
+ Gson gson = new Gson();
+ String msg = gson.toJson(req);
+
+ sendMessage(msg);
+ }
+
+ @Override
+ public void onWebSocketError(Throwable cause) {
+ if (cause instanceof ConnectException) {
+ LOG.error("websocket error {} {} {}", cluster, url, cause.getMessage());
+ } else {
+ LOG.error("websocket error {} {}", cluster, url, cause);
+ }
+ session = null;
+ }
+
+ @Override
+ public void onWebSocketText(String message) {
+ Gson gson = new Gson();
+ RunningQueryEvent evt = null;
+ try {
+ evt = gson.fromJson(message, RunningQueryEvent.class);
+ } catch (Exception e) {
+ LOG.error("Gson exception :", message);
+ }
+
+ if (evt == null || evt.msgType == null) {
+ LOG.error("invalid event object received.", message);
+ return;
+ }
+
+ switch (evt.msgType) {
+ case EVENT_RUN_QUERY_ADDED:
+ case EVENT_RUN_QUERY_UPDATED:
+ LOG.debug("new RT query {} {}", cluster, url);
+ if (evt.query != null) {
+ listener.processWebSocketAddEvent(evt.query);
+ }
+ break;
+ case EVENT_RUN_QUERY_REMOVED:
+ LOG.debug("removing RT query {} {}", cluster, url);
+ if (evt.query != null) {
+ listener.processWebSocketRemoveEvent(evt.query);
+ }
+ break;
+ case EVENT_RESULT:
+ LOG.debug("result {} {} {} ",cluster, url, evt.result);
+ break;
+ case EVENT_PONG:
+ LOG.debug("pong {} {}", cluster, url);
+ break;
+ default:
+ LOG.warn("ignoring message", message);
+ break;
+ }
+ }
+
+ private void sendMessage(String message) {
+ if (session != null && session.isOpen()) {
+ session.getRemote().sendString(message, null);
+ }
+ }
+
+ private void ping() {
+ LOG.debug("ping {} {}", cluster, url);
+ Gson gson = new Gson();
+ RequestMsg msg = new RequestMsg();
+ msg.request = "ping";
+ sendMessage(gson.toJson(msg));
+ }
+
+ private static class RequestMsg {
+ public String request;
+ public String channel;
+ public String data;
+ }
+
+ private static class RunningQueryEvent {
+ public String msgType = null;
+ public String result = null;
+ public QCQueryImport query = null;
+ public String queryId = null;
+ }
+}
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ClusterServerPoolInfo.java b/src/main/java/com/skplanet/checkmate/querycache/data/ClusterServerPoolInfo.java
new file mode 100644
index 0000000..c256a0f
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ClusterServerPoolInfo.java
@@ -0,0 +1,37 @@
+package com.skplanet.checkmate.querycache.data;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ClusterServerPoolInfo {
+ private String server;
+ private ServerObjectPool objPool;
+ private List connPoolList;
+
+ public ClusterServerPoolInfo(){}
+
+ public ClusterServerPoolInfo(String server, ServerObjectPool objPool, List connPoolList) {
+ this.server = server;
+ this.objPool = (objPool!=null?objPool:new ServerObjectPool());
+ this.connPoolList = (connPoolList!=null?connPoolList:Collections.EMPTY_LIST);
+ }
+
+ public String getServer() {
+ return server;
+ }
+ public void setServer(String server) {
+ this.server = server;
+ }
+ public ServerObjectPool getObjPool() {
+ return objPool;
+ }
+ public void setObjPool(ServerObjectPool objPool) {
+ this.objPool = objPool;
+ }
+ public List getConnPoolList() {
+ return connPoolList;
+ }
+ public void setConnPoolList(List connPoolList) {
+ this.connPoolList = connPoolList;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ClusterServerSysStats.java b/src/main/java/com/skplanet/checkmate/querycache/data/ClusterServerSysStats.java
new file mode 100644
index 0000000..3b9fec8
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ClusterServerSysStats.java
@@ -0,0 +1,42 @@
+package com.skplanet.checkmate.querycache.data;
+
+public class ClusterServerSysStats {
+ private String server;
+ private ServerRuntimeInfo jvm;
+ private ServerSystemInfo system;
+ private ServerThreadInfo threads;
+
+ public ClusterServerSysStats(){}
+
+ public ClusterServerSysStats(String server, ServerSystemStats svrStats) {
+ this.server = server;
+ this.jvm = (svrStats!=null?svrStats.getJvm():new ServerRuntimeInfo());
+ this.system = (svrStats!=null?svrStats.getSystem():new ServerSystemInfo());
+ this.threads = (svrStats!=null?svrStats.getThreads():new ServerThreadInfo());
+ }
+
+ public String getServer() {
+ return server;
+ }
+ public void setServer(String server) {
+ this.server = server;
+ }
+ public ServerRuntimeInfo getJvm() {
+ return jvm;
+ }
+ public void setJvm(ServerRuntimeInfo jvm) {
+ this.jvm = jvm;
+ }
+ public ServerSystemInfo getSystem() {
+ return system;
+ }
+ public void setSystem(ServerSystemInfo system) {
+ this.system = system;
+ }
+ public ServerThreadInfo getThreads() {
+ return threads;
+ }
+ public void setThreads(ServerThreadInfo threads) {
+ this.threads = threads;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/QCQueryEvent.java b/src/main/java/com/skplanet/checkmate/querycache/data/QCQueryEvent.java
new file mode 100644
index 0000000..0fc7af3
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/QCQueryEvent.java
@@ -0,0 +1,54 @@
+package com.skplanet.checkmate.querycache.data;
+
+import com.skplanet.checkmate.querycache.QCQuery;
+
+public class QCQueryEvent {
+
+ public static final String RUN_QUERY_ADDED = "runningQueryAdded";
+ public static final String RUN_QUERY_UPDATED = "runningQueryUpdated";
+ public static final String RUN_QUERY_REMOVED = "runningQueryRemoved";
+
+ private long timestamp;
+ private String msgType;
+ private QCQuery query;
+ private String cuqId;
+
+ public QCQueryEvent(String msgType, QCQuery query) {
+ this.timestamp = System.currentTimeMillis();
+ this.msgType = msgType;
+ this.query = query;
+ this.cuqId = query.getCuqId();
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public String getMsgType() {
+ return msgType;
+ }
+
+ public void setMsgType(String msgType) {
+ this.msgType = msgType;
+ }
+
+ public QCQuery getQuery() {
+ return query;
+ }
+
+ public void setQuery(QCQuery query) {
+ this.query = query;
+ }
+
+ public String getCuqId() {
+ return cuqId;
+ }
+
+ public void setCuqId(String cuqId) {
+ this.cuqId = cuqId;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/QCQueryImport.java b/src/main/java/com/skplanet/checkmate/querycache/data/QCQueryImport.java
new file mode 100644
index 0000000..0c2fc9b
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/QCQueryImport.java
@@ -0,0 +1,98 @@
+package com.skplanet.checkmate.querycache.data;
+
+public class QCQueryImport {
+
+ private String queryId;
+ private String connType;
+ private String user;
+ private String queryType;
+ private String queryStr;
+ private String clientIp;
+ private String stmtState;
+ private long rowCnt;
+ private long startTime;
+ private long endTime;
+ // 0:exec/1:getmeta/2:fetch/3:stmtclose or
+ // 1:getschemas/2:fetch
+ private long[] timeHistogram = {0,0,0,0};
+ private long[] execProfile = null;
+ private long[] fetchProfile = {0,0,0,-1,-1,-1,-1,0,0,-1,-1};
+ public String getQueryId() {
+ return queryId;
+ }
+ public void setQueryId(String queryId) {
+ this.queryId = queryId;
+ }
+ public String getConnType() {
+ return connType;
+ }
+ public void setConnType(String connType) {
+ this.connType = connType;
+ }
+ public String getUser() {
+ return user;
+ }
+ public void setUser(String user) {
+ this.user = user;
+ }
+ public String getQueryType() {
+ return queryType;
+ }
+ public void setQueryType(String queryType) {
+ this.queryType = queryType;
+ }
+ public String getQueryStr() {
+ return queryStr;
+ }
+ public void setQueryStr(String queryStr) {
+ this.queryStr = queryStr;
+ }
+ public String getClientIp() {
+ return clientIp;
+ }
+ public void setClientIp(String clientIp) {
+ this.clientIp = clientIp;
+ }
+ public String getStmtState() {
+ return stmtState;
+ }
+ public void setStmtState(String stmtState) {
+ this.stmtState = stmtState;
+ }
+ public long getRowCnt() {
+ return rowCnt;
+ }
+ public void setRowCnt(long rowCnt) {
+ this.rowCnt = rowCnt;
+ }
+ public long getStartTime() {
+ return startTime;
+ }
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+ public long getEndTime() {
+ return endTime;
+ }
+ public void setEndTime(long endTime) {
+ this.endTime = endTime;
+ }
+ public long[] getTimeHistogram() {
+ return timeHistogram;
+ }
+ public void setTimeHistogram(long[] timeHistogram) {
+ this.timeHistogram = timeHistogram;
+ }
+ public long[] getExecProfile() {
+ return execProfile;
+ }
+ public void setExecProfile(long[] execProfile) {
+ this.execProfile = execProfile;
+ }
+ public long[] getFetchProfile() {
+ return fetchProfile;
+ }
+ public void setFetchProfile(long[] fetchProfile) {
+ this.fetchProfile = fetchProfile;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ServerConDesc.java b/src/main/java/com/skplanet/checkmate/querycache/data/ServerConDesc.java
new file mode 100644
index 0000000..2e475ec
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ServerConDesc.java
@@ -0,0 +1,27 @@
+package com.skplanet.checkmate.querycache.data;
+
+public class ServerConDesc {
+ private String driver;
+ private int free;
+ private int using;
+
+ public String getDriver() {
+ return driver;
+ }
+ public void setDriver(String driver) {
+ this.driver = driver;
+ }
+ public int getFree() {
+ return free;
+ }
+ public void setFree(int free) {
+ this.free = free;
+ }
+ public int getUsing() {
+ return using;
+ }
+ public void setUsing(int using) {
+ this.using = using;
+ }
+}
+
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ServerObjectPool.java b/src/main/java/com/skplanet/checkmate/querycache/data/ServerObjectPool.java
new file mode 100644
index 0000000..c4f81ef
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ServerObjectPool.java
@@ -0,0 +1,41 @@
+package com.skplanet.checkmate.querycache.data;
+
+public class ServerObjectPool {
+ // configuration
+ private long sReloadCycle = 0;
+ private int sMaxPoolSize = 0;
+ private float sReloadingThreshold = 0;
+ private int sCellCoeff = 0;
+ private int[] poolSize = {0, 0, 0, 0};
+
+ public long getsReloadCycle() {
+ return sReloadCycle;
+ }
+ public void setsReloadCycle(long sReloadCycle) {
+ this.sReloadCycle = sReloadCycle;
+ }
+ public int getsMaxPoolSize() {
+ return sMaxPoolSize;
+ }
+ public void setsMaxPoolSize(int sMaxPoolSize) {
+ this.sMaxPoolSize = sMaxPoolSize;
+ }
+ public float getsReloadingThreshold() {
+ return sReloadingThreshold;
+ }
+ public void setsReloadingThreshold(float sReloadingThreshold) {
+ this.sReloadingThreshold = sReloadingThreshold;
+ }
+ public int getsCellCoeff() {
+ return sCellCoeff;
+ }
+ public void setsCellCoeff(int sCellCoeff) {
+ this.sCellCoeff = sCellCoeff;
+ }
+ public int[] getPoolSize() {
+ return poolSize;
+ }
+ public void setPoolSize(int[] poolSize) {
+ this.poolSize = poolSize;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ServerQueries.java b/src/main/java/com/skplanet/checkmate/querycache/data/ServerQueries.java
new file mode 100644
index 0000000..9ce3767
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ServerQueries.java
@@ -0,0 +1,22 @@
+package com.skplanet.checkmate.querycache.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ServerQueries {
+ private List runningQueries = new ArrayList<>();
+ private List completeQueries = new ArrayList<>();
+
+ public List getRunningQueries() {
+ return runningQueries;
+ }
+ public void setRunningQueries(List runningQueries) {
+ this.runningQueries = runningQueries;
+ }
+ public List getCompleteQueries() {
+ return completeQueries;
+ }
+ public void setCompleteQueries(List completeQueries) {
+ this.completeQueries = completeQueries;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ServerRuntimeInfo.java b/src/main/java/com/skplanet/checkmate/querycache/data/ServerRuntimeInfo.java
new file mode 100644
index 0000000..89c382f
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ServerRuntimeInfo.java
@@ -0,0 +1,33 @@
+package com.skplanet.checkmate.querycache.data;
+
+public class ServerRuntimeInfo {
+ private int nProcessors;
+ private long memFree;
+ private long memTotal;
+ private long memMax;
+
+ public int getnProcessors() {
+ return nProcessors;
+ }
+ public void setnProcessors(int nProcessors) {
+ this.nProcessors = nProcessors;
+ }
+ public long getMemFree() {
+ return memFree;
+ }
+ public void setMemFree(long memFree) {
+ this.memFree = memFree;
+ }
+ public long getMemTotal() {
+ return memTotal;
+ }
+ public void setMemTotal(long memTotal) {
+ this.memTotal = memTotal;
+ }
+ public long getMemMax() {
+ return memMax;
+ }
+ public void setMemMax(long memMax) {
+ this.memMax = memMax;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ServerSystemInfo.java b/src/main/java/com/skplanet/checkmate/querycache/data/ServerSystemInfo.java
new file mode 100644
index 0000000..03ecdd5
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ServerSystemInfo.java
@@ -0,0 +1,47 @@
+package com.skplanet.checkmate.querycache.data;
+
+public class ServerSystemInfo {
+ private double loadSystem;
+ private double loadProcess;
+ private long memPhysFree;
+ private long memPhysTotal;
+ private long swapFree;
+ private long swapTotal;
+
+ public double getLoadSystem() {
+ return loadSystem;
+ }
+ public void setLoadSystem(double loadSystem) {
+ this.loadSystem = loadSystem;
+ }
+ public double getLoadProcess() {
+ return loadProcess;
+ }
+ public void setLoadProcess(double loadProcess) {
+ this.loadProcess = loadProcess;
+ }
+ public long getMemPhysFree() {
+ return memPhysFree;
+ }
+ public void setMemPhysFree(long memPhysFree) {
+ this.memPhysFree = memPhysFree;
+ }
+ public long getMemPhysTotal() {
+ return memPhysTotal;
+ }
+ public void setMemPhysTotal(long memPhysTotal) {
+ this.memPhysTotal = memPhysTotal;
+ }
+ public long getSwapFree() {
+ return swapFree;
+ }
+ public void setSwapFree(long swapFree) {
+ this.swapFree = swapFree;
+ }
+ public long getSwapTotal() {
+ return swapTotal;
+ }
+ public void setSwapTotal(long swapTotal) {
+ this.swapTotal = swapTotal;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ServerSystemStats.java b/src/main/java/com/skplanet/checkmate/querycache/data/ServerSystemStats.java
new file mode 100644
index 0000000..0c87ba5
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ServerSystemStats.java
@@ -0,0 +1,27 @@
+package com.skplanet.checkmate.querycache.data;
+
+public class ServerSystemStats {
+
+ private ServerRuntimeInfo jvm;
+ private ServerSystemInfo system;
+ private ServerThreadInfo threads;
+
+ public ServerRuntimeInfo getJvm() {
+ return jvm;
+ }
+ public void setJvm(ServerRuntimeInfo jvm) {
+ this.jvm = jvm;
+ }
+ public ServerSystemInfo getSystem() {
+ return system;
+ }
+ public void setSystem(ServerSystemInfo system) {
+ this.system = system;
+ }
+ public ServerThreadInfo getThreads() {
+ return threads;
+ }
+ public void setThreads(ServerThreadInfo threads) {
+ this.threads = threads;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/skplanet/checkmate/querycache/data/ServerThreadInfo.java b/src/main/java/com/skplanet/checkmate/querycache/data/ServerThreadInfo.java
new file mode 100644
index 0000000..08983dc
--- /dev/null
+++ b/src/main/java/com/skplanet/checkmate/querycache/data/ServerThreadInfo.java
@@ -0,0 +1,41 @@
+package com.skplanet.checkmate.querycache.data;
+
+public class ServerThreadInfo {
+ private int webServerThreads;
+ private int webServerThreadsIdle;
+ private int handlerThreads;
+ private int handlerThreadsIdle;
+ private int totalThreads;
+
+ public int getWebServerThreads() {
+ return webServerThreads;
+ }
+ public void setWebServerThreads(int webServerThreads) {
+ this.webServerThreads = webServerThreads;
+ }
+ public int getWebServerThreadsIdle() {
+ return webServerThreadsIdle;
+ }
+ public void setWebServerThreadsIdle(int webServerThreadsIdle) {
+ this.webServerThreadsIdle = webServerThreadsIdle;
+ }
+ public int getHandlerThreads() {
+ return handlerThreads;
+ }
+ public void setHandlerThreads(int handlerThreads) {
+ this.handlerThreads = handlerThreads;
+ }
+ public int getHandlerThreadsIdle() {
+ return handlerThreadsIdle;
+ }
+ public void setHandlerThreadsIdle(int handlerThreadsIdle) {
+ this.handlerThreadsIdle = handlerThreadsIdle;
+ }
+ public int getTotalThreads() {
+ return totalThreads;
+ }
+ public void setTotalThreads(int totalThreads) {
+ this.totalThreads = totalThreads;
+ }
+}
+
diff --git a/src/main/java/com/skplanet/checkmate/servlet/CMApiServletQC.java b/src/main/java/com/skplanet/checkmate/servlet/CMApiServletQC.java
index 2c6e546..331611f 100644
--- a/src/main/java/com/skplanet/checkmate/servlet/CMApiServletQC.java
+++ b/src/main/java/com/skplanet/checkmate/servlet/CMApiServletQC.java
@@ -1,40 +1,50 @@
package com.skplanet.checkmate.servlet;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-import com.skplanet.checkmate.querycache.QCCluster;
-import com.skplanet.checkmate.querycache.QCClusterManager;
-import com.skplanet.checkmate.querycache.QCQuery;
-import com.skplanet.checkmate.utils.HttpUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.List;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.lang.reflect.Type;
-import java.util.Collection;
-import java.util.Date;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+import com.skplanet.checkmate.CheckMateServer;
+import com.skplanet.checkmate.querycache.QCCluster;
+import com.skplanet.checkmate.querycache.QCClusterManager;
+import com.skplanet.checkmate.querycache.QCQuery;
+import com.skplanet.checkmate.querycache.data.ClusterServerPoolInfo;
+import com.skplanet.checkmate.querycache.data.ClusterServerSysStats;
+import com.skplanet.checkmate.utils.HttpUtil;
/**
* Created by nazgul33 on 15. 1. 29.
*/
public class CMApiServletQC extends HttpServlet {
- private static final boolean DEBUG = false;
- private static final Logger LOG = LoggerFactory.getLogger("api");
+
+ private static final long serialVersionUID = 2564648276343514634L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(CMApiServletQC.class);
private static final String ASYNC_REQ_ATTR = CMApiServletQC.class.getName() + ".async";
private static final String ASYNC_RETURN_ATTR = CMApiServletQC.class.getName() + ".async.return";
+
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/json; charset=utf-8");
- if (DEBUG) {
- LOG.debug(request.getRequestURI() + "?" + request.getQueryString());
- }
+ LOG.info("{}?{}",request.getRequestURI(),request.getQueryString());
PrintWriter writer = response.getWriter();
String path = request.getRequestURI().substring(request.getContextPath().length());
@@ -43,12 +53,12 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
urlWithParameter += "?" + request.getQueryString();
}
- QCClusterManager qcMgr = QCClusterManager.getInstance();
+ QCClusterManager qcMgr = CheckMateServer.getClusterManager();
Gson gson = new Gson();
switch (path) {
case "/clusterList": {
- Collection cl = qcMgr.getClusterList();
- Type qListType = new TypeToken>() {}.getType();
+ List cl = qcMgr.getClusterNameList();
+ Type qListType = new TypeToken>() {}.getType();
String jsonObj = gson.toJson(cl, qListType);
writer.printf("{\"result\":\"ok\", \"msg\":\"ok\", \"data\":%s}", jsonObj);
response.setStatus(HttpServletResponse.SC_OK);
@@ -57,8 +67,8 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
case "/runningQueries": {
QCCluster c = qcMgr.getCluster(request.getParameter("cluster"));
if (c!=null) {
- Collection ql = c.getExportedRunningQueries();
- Type qListType = new TypeToken>() {
+ List ql = c.getRunningQueries();
+ Type qListType = new TypeToken>() {
}.getType();
String jsonObj = gson.toJson(ql, qListType);
writer.printf("{\"result\":\"ok\", \"msg\":\"ok\", \"data\":%s}", jsonObj);
@@ -75,7 +85,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
case "/completeQueries": {
QCCluster c = qcMgr.getCluster(request.getParameter("cluster"));
if (c!=null) {
- Collection ql = c.getExportedCompleteQueries();
+ Collection ql = c.getCompleteQueries();
/*
// TODO: paging, filtering
@@ -91,7 +101,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
return ql.subList(page_number*page_size, (page_number + 1)*page_size);
*/
- Type qListType = new TypeToken>() {}.getType();
+ Type qListType = new TypeToken>() {}.getType();
String jsonObj = gson.toJson(ql, qListType);
writer.printf("{\"result\":\"ok\", \"msg\":\"ok\", \"data\":%s}", jsonObj);
response.setStatus(HttpServletResponse.SC_OK);
@@ -106,16 +116,22 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
case "/sysInfoList": {
QCCluster c = qcMgr.getCluster(request.getParameter("cluster"));
if (c!=null) {
- Collection l = c.getSystemInfo();
- Type lType = new TypeToken>() {
- }.getType();
- String jsonObj = gson.toJson(l, lType);
- writer.printf("{\"result\":\"ok\", \"msg\":\"ok\", \"data\":%s}", jsonObj);
+ List list = c.getServerInfo();
+ Type lType = new TypeToken>() {}.getType();
+ JsonArray jarr = gson.toJsonTree(list , lType).getAsJsonArray();
+
+ JsonObject json = new JsonObject();
+ json.addProperty("result", "ok");
+ json.addProperty("msg", "ok");
+ json.add("data", jarr);
+ writer.print(json.toString());
response.setStatus(HttpServletResponse.SC_OK);
- }
- else {
+ } else {
LOG.error(urlWithParameter + " : invalid parameter");
- writer.print("{\"result\":\"error\", \"msg\":\"invalid parameter\"}");
+ JsonObject json = new JsonObject();
+ json.addProperty("result", "error");
+ json.addProperty("msg", "invalid parameter");
+ writer.print(json.toString());
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
break;
@@ -123,15 +139,22 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
case "/poolInfoList": {
QCCluster c = qcMgr.getCluster(request.getParameter("cluster"));
if (c != null) {
- Collection l = c.getPoolInfo();
- Type lType = new TypeToken>() {}.getType();
- String jsonObj = gson.toJson(l, lType);
- writer.printf("{\"result\":\"ok\", \"msg\":\"ok\", \"data\":%s}", jsonObj);
+ List list = c.getPoolInfo();
+ Type lType = new TypeToken>() {}.getType();
+ JsonArray jarr = gson.toJsonTree(list , lType).getAsJsonArray();
+
+ JsonObject json = new JsonObject();
+ json.addProperty("result", "ok");
+ json.addProperty("msg", "ok");
+ json.add("data", jarr);
+ writer.print(json.toString());
response.setStatus(HttpServletResponse.SC_OK);
- }
- else {
+ } else {
LOG.error(urlWithParameter + " : invalid parameter");
- writer.print("{\"result\":\"error\", \"msg\":\"invalid parameter\"}");
+ JsonObject json = new JsonObject();
+ json.addProperty("result", "error");
+ json.addProperty("msg", "invalid parameter");
+ writer.print(json.toString());
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
break;
@@ -146,7 +169,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
break;
}
- final QCQuery.QueryExport eq = c.getExportedRunningQueryByCuqId(cuqId);
+ final QCQuery eq = c.getRunningQueryByCuqId(cuqId);
if ( eq == null ) {
response.setContentType("application/json; charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
@@ -155,7 +178,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
break;
}
- LOG.info("Starting cancel async job. " + eq.server + " " + eq.backend + " " + eq.id);
+ LOG.info("Starting cancel async job. " + eq.getServer() + " " + eq.getBackend() + " " + eq.getId());
final AsyncContext async = request.startAsync();
request.setAttribute(ASYNC_REQ_ATTR, new Boolean(true));
async.setTimeout(30000);
@@ -163,10 +186,12 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
@Override
public void run() {
HttpUtil httpUtil = new HttpUtil();
- StringBuffer buf = new StringBuffer();
- int res = 0;
+ StringBuilder buf = new StringBuilder();
try {
- String url = "http://" + eq.server + ":" + c.getOpt().webPort + "/api/cancelQuery?id="+eq.id+"&driver="+eq.backend;
+ String url = format("http://%s:%s%s",
+ eq.getServer(),
+ c.getOptions().getWebPort(),
+ "/api/cancelQuery?id="+eq.getId()+"&driver="+eq.getBackend());
httpUtil.get( url, buf );
async.getRequest().setAttribute(ASYNC_RETURN_ATTR, buf.toString());
diff --git a/src/main/java/com/skplanet/checkmate/servlet/CMQCServerWebSocket.java b/src/main/java/com/skplanet/checkmate/servlet/CMQCServerWebSocket.java
index b45d1cb..966711b 100644
--- a/src/main/java/com/skplanet/checkmate/servlet/CMQCServerWebSocket.java
+++ b/src/main/java/com/skplanet/checkmate/servlet/CMQCServerWebSocket.java
@@ -2,6 +2,7 @@
import com.google.gson.Gson;
+import com.skplanet.checkmate.CheckMateServer;
import com.skplanet.checkmate.querycache.QCCluster;
import com.skplanet.checkmate.querycache.QCClusterManager;
import org.eclipse.jetty.websocket.api.Session;
@@ -13,40 +14,32 @@
* Created by nazgul33 on 15. 2. 13.
*/
public class CMQCServerWebSocket implements WebSocketListener {
- private static final boolean DEBUG = false;
+
private static final Logger LOG = LoggerFactory.getLogger("websocket-server-qc");
- private Session outbound;
+ private Session session;
private int id = -1;
- private QCClusterManager qcMgr = QCClusterManager.getInstance();
+ private QCClusterManager qcMgr = CheckMateServer.getClusterManager();
private QCCluster cluster = null;
- private static class RequestMsg {
- public String request;
- public String channel;
- public String data;
- }
-
@Override
- public void onWebSocketBinary(byte[] payload, int offset, int len)
- {
+ public void onWebSocketBinary(byte[] payload, int offset, int len) {
/* only interested in test messages */
}
@Override
- public void onWebSocketClose(int statusCode, String reason)
- {
- this.outbound = null;
- if ( this.id >= 0 && this.cluster != null) {
- cluster.unSubscribe(id);
+ public void onWebSocketClose(int statusCode, String reason) {
+ session.close();
+ if ( id >= 0 && cluster != null) {
+ cluster.unsubscribe(id);
}
- this.id = -1;
- this.cluster = null;
+ id = -1;
+ cluster = null;
}
@Override
public void onWebSocketConnect(Session session) {
- this.outbound = session;
+ this.session = session;
}
@Override
@@ -56,7 +49,7 @@ public void onWebSocketError(Throwable cause) {
@Override
public void onWebSocketText(String message) {
- if (outbound == null || !outbound.isOpen())
+ if (session == null || !session.isOpen())
return;
Gson gson = new Gson();
@@ -64,15 +57,15 @@ public void onWebSocketText(String message) {
switch (msg.request) {
case "subscribe": {
if ("cluster".equals(msg.channel)) {
- this.cluster = qcMgr.getCluster(msg.data);
- if (this.cluster != null) {
- this.id = this.cluster.subscribe(this);
+ cluster = qcMgr.getCluster(msg.data);
+ if (cluster != null) {
+ id = cluster.subscribe(this);
}
}
return;
}
case "ping": {
- outbound.getRemote().sendString("{\"msgType\":\"pong\"}", null);
+ sendMessage("{\"msgType\":\"pong\"}");
return;
}
}
@@ -81,8 +74,14 @@ public void onWebSocketText(String message) {
}
public void sendMessage(String message) {
- if (outbound == null || !outbound.isOpen())
+ if (session == null || !session.isOpen())
return;
- outbound.getRemote().sendString(message, null);
+ session.getRemote().sendString(message, null);
+ }
+
+ private static class RequestMsg {
+ public String request;
+ public String channel;
+ public String data;
}
}
diff --git a/src/main/java/com/skplanet/checkmate/servlet/CMWebSocketServletQC.java b/src/main/java/com/skplanet/checkmate/servlet/CMWebSocketServletQC.java
index 97ff6ec..0340b01 100644
--- a/src/main/java/com/skplanet/checkmate/servlet/CMWebSocketServletQC.java
+++ b/src/main/java/com/skplanet/checkmate/servlet/CMWebSocketServletQC.java
@@ -11,9 +11,15 @@
@WebServlet(name = "CheckMate WebSocket for QueryCache", urlPatterns = { "/api/qc/websocket" })
public class CMWebSocketServletQC extends WebSocketServlet {
- @Override
+
+ private static final long serialVersionUID = -1985362762429496022L;
+
+ private static final int MAX_TEXT_MESSAGE_SIZE = 1*1024*1024;
+
+ @Override
public void configure(WebSocketServletFactory factory) {
factory.getPolicy().setIdleTimeout(120*1000); // 2min
+ factory.getPolicy().setMaxTextMessageSize(MAX_TEXT_MESSAGE_SIZE);
factory.register(CMQCServerWebSocket.class);
}
}
diff --git a/src/main/java/com/skplanet/checkmate/utils/HttpUtil.java b/src/main/java/com/skplanet/checkmate/utils/HttpUtil.java
index f246657..8113622 100644
--- a/src/main/java/com/skplanet/checkmate/utils/HttpUtil.java
+++ b/src/main/java/com/skplanet/checkmate/utils/HttpUtil.java
@@ -5,64 +5,92 @@
import java.net.HttpURLConnection;
import java.net.URL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Created by nazgul33 on 15. 1. 27.
*/
public class HttpUtil {
- private static boolean DEBUG = false;
+
+ private static final Logger LOG = LoggerFactory.getLogger(HttpUtil.class);
+
private static int CONNECTION_TIMEOUT = 5000;
private static int READ_TIMEOUT = 3000;
public final String userAgent;
+
+ public HttpUtil() {
+ this("CheckMate 1.0");
+ }
+
public HttpUtil(String userAgent) {
this.userAgent = userAgent;
}
- public HttpUtil() {
- this.userAgent = "CheckMate 1.0";
- }
// HTTP GET request
// returns response code
// if response code is 200, parameter "response" should have the result
- public int get(String url, StringBuffer response) throws Exception {
+ public int get(String url, StringBuilder response) throws Exception {
return get(url, response, null);
}
- public int getJson(String url, StringBuffer response) throws Exception {
+ public int getJson(String url, StringBuilder response) throws Exception {
return get(url, response, "application/json");
}
- public int get(String url, StringBuffer response, String accept) throws Exception {
+ public int get(String url, StringBuilder response, String accept) throws Exception {
URL obj = new URL(url);
- HttpURLConnection con = (HttpURLConnection) obj.openConnection();
- con.setConnectTimeout(CONNECTION_TIMEOUT);
- con.setReadTimeout(READ_TIMEOUT);
+ HttpURLConnection con = null;
+ try {
+ con = (HttpURLConnection) obj.openConnection();
+ con.setConnectTimeout(CONNECTION_TIMEOUT);
+ con.setReadTimeout(READ_TIMEOUT);
+ // optional default is GET
+ con.setRequestMethod("GET");
- // optional default is GET
- con.setRequestMethod("GET");
+ //add request header
+ con.setRequestProperty("User-Agent", userAgent);
- //add request header
- con.setRequestProperty("User-Agent", userAgent);
+ if (accept != null) {
+ con.setRequestProperty("Accept", accept);
+ }
- if (accept != null) {
- con.setRequestProperty("Accept", accept);
- }
+ int responseCode = con.getResponseCode();
+ LOG.debug("sending 'GET' request to URL : {}", url);
+ LOG.debug("Response Code : {}", responseCode);
- int responseCode = con.getResponseCode();
- if (DEBUG) {
- System.out.println("\nSending 'GET' request to URL : " + url);
- System.out.println("Response Code : " + responseCode);
- }
+ if (responseCode == 200) {
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(
+ new InputStreamReader(con.getInputStream()));
+ String inputLine;
- if (responseCode == 200) {
- BufferedReader in = new BufferedReader(
- new InputStreamReader(con.getInputStream()));
- String inputLine;
-
- while ((inputLine = in.readLine()) != null) {
- response.append(inputLine);
+ while ((inputLine = in.readLine()) != null) {
+ response.append(inputLine).append("\n");
+ }
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
}
- in.close();
+ return responseCode;
+ } finally {
+ if (con != null) {
+ con.disconnect();
+ }
}
- return responseCode;
+ }
+
+ public static String get(String url) throws Exception {
+ HttpUtil http = new HttpUtil();
+ StringBuilder sb = new StringBuilder();
+ int code = http.get(url, sb);
+ if (code == 200) {
+ return sb.toString();
+ } else {
+ throw new RuntimeException("response code "+ code);
+ }
}
}
diff --git a/src/main/java/com/skplanet/checkmate/utils/MailSender.java b/src/main/java/com/skplanet/checkmate/utils/MailSender.java
index 692edb4..9980ee8 100644
--- a/src/main/java/com/skplanet/checkmate/utils/MailSender.java
+++ b/src/main/java/com/skplanet/checkmate/utils/MailSender.java
@@ -1,200 +1,181 @@
package com.skplanet.checkmate.utils;
-/**
- * Created by nazgul33 on 4/7/16.
- */
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
import javax.mail.Message;
-import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.*;
+
+/**
+ * Created by nazgul33 on 4/7/16.
+ */
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Created by nazgul33 on 10/26/15.
*/
-public class MailSender implements Runnable {
- protected static final Logger LOG = LoggerFactory.getLogger(MailSender.class);
-
- static public class Mail {
- public final String subject;
- private String content;
-
- public Mail(String subject, String content) {
- this.subject = subject;
- this.content = content;
- }
-
- public Mail(String subject, Exception e) {
- this.subject = subject;
-
- StringWriter errors = new StringWriter();
- errors.append("Exception : ").append(e.getClass().getCanonicalName()).append("\n");
- errors.append(e.getMessage()).append("\n");
- errors.flush();
- e.printStackTrace(new PrintWriter(errors));
- this.content = errors.toString();
- }
-
- public String getContent() {
- return content;
- }
-
- public void setContent(String content) {
- this.content = content;
- }
- }
-
- private final String smtpServer, smtpFrom;
- private final int smtpPort;
- private final InternetAddress[] recipientAddresses;
-
- public MailSender(String smtpServer, String smtpFrom, int smtpPort, List recipients) throws Exception {
- this.smtpServer = smtpServer;
- this.smtpFrom = smtpFrom;
- this.smtpPort = smtpPort;
-
- recipientAddresses = new InternetAddress[recipients.size()];
- for (int i=0; i mailQueue = new ArrayList<>();
- public void addMail(Mail mail) {
- synchronized (mailQueue) {
- mailQueue.add(mail);
- }
- LOG.info("mail queued. {}", mail.subject);
- }
-
- public void run() {
- try {
- Properties properties = System.getProperties();
- properties.setProperty("mail.smtp.host", smtpServer);
- properties.setProperty("mail.smtp.port", String.valueOf(smtpPort));
-
- Session session = Session.getDefaultInstance(properties);
-
- InternetAddress iFrom = new InternetAddress(smtpFrom);
- Collection mq = new ArrayList<>();
-
- LOG.info("MailSender started.");
-
- while (!Thread.interrupted()) {
- synchronized (mailQueue) {
- if (mailQueue.size() > 0) {
- for (Mail mail : mailQueue) {
- mq.add(mail);
- }
- mailQueue.clear();
- }
- }
- if (mq.size() == 0) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- // ignore
- }
- continue;
- }
-
- for (Mail mail : mq) {
- LOG.info("sending mail '{}'", mail.subject);
-
- try {
- MimeMessage message = new MimeMessage(session);
- message.setFrom(iFrom);
- message.addRecipients(Message.RecipientType.TO, recipientAddresses);
- message.setSubject(mail.subject);
- message.setText(mail.content);
-
- Transport.send(message);
- LOG.info("Mail sent to {}", recipientAddresses);
- } catch (MessagingException e) {
- LOG.error("Exception sending mail", e);
- }
- }
- mq.clear();
- }
- } catch (Exception e) {
- LOG.error("Unexpected exception", e);
- }
- }
-
- public static void main(String args[]) {
- String server = null;
- int port = 25;
- String from = null;
- List recipients = null;
- String title = null;
- String msg = null;
- try {
- for (int i = 0; i < args.length; i++) {
- switch (args[i]) {
- case "-s":
- server = args[++i];
- System.out.println("Server : " + server);
- break;
- case "-p":
- port = Integer.valueOf(args[++i]);
- System.out.println("Port : " + port);
- break;
- case "-f":
- from = args[++i];
- System.out.println("From : " + from);
- break;
- case "-r":
- recipients = Arrays.asList(args[++i].split(","));
- System.out.println("Recipients : " + recipients);
- break;
- case "-t":
- title = args[++i];
- System.out.println("Title : " + title);
- break;
- case "-m":
- msg = args[++i];
- System.out.println("Message : " + msg);
- break;
- default:
- System.out.println("unknown option");
- break;
- }
- }
- } catch (Exception e) {
- System.err.println("error parsing arguments.");
- e.printStackTrace();
- System.exit(1);
- }
-
- MailSender mailSender = null;
- try {
- mailSender = new MailSender(server, from, port, recipients);
- } catch (Exception e) {
- System.err.println("error instantiating MailSender");
- e.printStackTrace();
- System.exit(1);
- }
-
- Thread t = new Thread(mailSender);
- t.setDaemon(false);
- t.start();
-
- Mail mail = new Mail(title, msg);
- mailSender.addMail(mail);
-
- try {
- Thread.sleep(10);
- t.interrupt();
- t.join();
- } catch (Exception e) {
- // ignore
- }
- }
+public class MailSender {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MailSender.class);
+
+ private static MailSender _this;
+
+ private List mailQueue = new ArrayList<>();
+
+ private String server;
+ private String from;
+ private int port;
+ private InternetAddress[] tos;
+ private MailSenderThread thread;
+
+ private MailSender(String server, int port, String from, String[] toList) throws Exception {
+ this.server = server;
+ this.port = port;
+ this.from = from;
+
+ tos = new InternetAddress[toList.length];
+ for (int i=0;i mq = new ArrayList<>();
+
+ while (running) {
+ synchronized (mailQueue) {
+ if (mailQueue.size() > 0) {
+ mq.addAll(mailQueue);
+ mailQueue.clear();
+ }
+ }
+ for (Mail mail : mq) {
+ LOG.info("sending mail '{}'", mail.getSubject());
+
+ try {
+ MimeMessage message = new MimeMessage(session);
+ message.setFrom(iFrom);
+ message.addRecipients(Message.RecipientType.TO, tos);
+ message.setSubject(mail.getSubject());
+ message.setText(mail.getContent());
+
+ Transport.send(message);
+ LOG.info("Mail sent to {}", Arrays.toString(tos));
+ } catch (Exception e) {
+ LOG.error("Exception sending mail", e);
+ }
+ }
+ mq.clear();
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Unexpected exception", e);
+ }
+
+ LOG.info("MailSender thread started.");
+ }
+
+ public void close() {
+ running = false;
+ interrupt();
+ }
+ }
+
+ public static class Mail {
+ private String subject;
+ private String content;
+
+ public Mail(String subject) {
+ this(subject, (String)null);
+ }
+
+ public Mail(String subject, String content) {
+ this.subject = subject;
+ this.content = content;
+ }
+
+ public Mail(String subject, Exception e) {
+ this.subject = subject;
+
+ StringWriter errors = new StringWriter();
+ errors.append("Exception : ").append(e.getClass().getCanonicalName()).append("\n");
+ errors.append(e.getMessage()).append("\n");
+ errors.flush();
+ e.printStackTrace(new PrintWriter(errors));
+ this.content = errors.toString();
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+ }
}
diff --git a/src/main/java/com/skplanet/checkmate/yarn/YarnResourceManager.java b/src/main/java/com/skplanet/checkmate/yarn/YarnResourceManager.java
index 8554ab1..6e07f2d 100644
--- a/src/main/java/com/skplanet/checkmate/yarn/YarnResourceManager.java
+++ b/src/main/java/com/skplanet/checkmate/yarn/YarnResourceManager.java
@@ -30,7 +30,7 @@ void GetUnfinishedApplications() {
HttpUtil httpUtil = new HttpUtil();
int responseCode = 0;
try {
- StringBuffer buf = new StringBuffer(2048);
+ StringBuilder buf = new StringBuilder(2048);
responseCode = httpUtil.getJson(url, buf);
LOG.info("http response {}", responseCode);
if (responseCode == 200) {
diff --git a/www/css/querycache.css b/www/css/querycache.css
index 681985c..dfa000a 100644
--- a/www/css/querycache.css
+++ b/www/css/querycache.css
@@ -94,10 +94,11 @@ table.fixed
{
table-layout: fixed;
}
+
td.qServer,
th.qServer
{
- width: 50px;
+ width: 100px;
padding-left: 1px;
padding-right: 1px;
}
@@ -105,7 +106,7 @@ th.qServer
td.qId,
th.qId
{
- width: 52px;
+ width: 102px;
padding-left: 1px;
padding-right: 1px;
}
@@ -113,7 +114,7 @@ th.qId
td.qBackend,
th.qBackend
{
- width: 72px;
+ width: 102px;
padding-left: 1px;
padding-right: 1px;
}
@@ -121,7 +122,7 @@ th.qBackend
td.qUser,
th.qUser
{
- width: 72px;
+ width: 102px;
padding-left: 1px;
padding-right: 1px;
}
@@ -137,7 +138,7 @@ th.qStatement
td.qState,
th.qState
{
- width: 48px;
+ width: 102px;
padding-left: 1px;
padding-right: 1px;
}
@@ -145,7 +146,7 @@ th.qState
td.qClient,
th.qClient
{
- width: 90px;
+ width: 122px;
padding-left: 1px;
padding-right: 1px;
}
@@ -156,12 +157,13 @@ th.qRows
width: 72px;
padding-left: 1px;
padding-right: 1px;
+ text-align:right;
}
td.qStartTime,
th.qStartTime
{
- width: 80px;
+ width: 120px;
padding-left: 1px;
padding-right: 1px;
}
@@ -169,7 +171,7 @@ th.qStartTime
td.qElapsedTime,
th.qElapsedTime
{
- width: 90px;
+ width: 150px;
padding-left: 1px;
padding-right: 1px;
}
diff --git a/www/qc/queries.funcs.html b/www/qc/queries.funcs.html
index 9007c4d..12524b1 100644
--- a/www/qc/queries.funcs.html
+++ b/www/qc/queries.funcs.html
@@ -1,7 +1,6 @@
-
<%@include file="queries.funcs.html"%>
-
-
-
Connection Pool Stats
-
-
- | server | backend | pool free | pool used | direct | created |
-
-
-
-
-
+
+
Connection Pool Stats
+
+
+ | server | backend | pool free | pool used | direct | created |
+
+
+
+
+
-
-
Object Pool Stats
-
-
- | server | TROWSET | TROW | TCOLUMNVALUE | TSTRINGVALUE |
-
-
-
-
-
+
+
Object Pool Stats
+
+
+ | server | TROWSET | TROW | TCOLUMNVALUE | TSTRINGVALUE |
+
+
+
+
+
-
-<%@include file="header.jsp"%>
-
-
-
-<%@include file="queries.funcs.html"%>
-
-
-
In-Flight Queries
-
-
- | server |
- id |
- type |
- user |
- statement |
- state |
- client ip |
- rows |
- startTime |
- elapsedTime |
- Cancel |
-
-
-
-
+
+
In-Flight Queries
+
+
+
+ | server |
+ id |
+ user |
+ query |
+ state |
+ client |
+ rows |
+ start |
+ elapsed |
+ Cancel |
+
+
+
+
+
-
-
-
- | server |
- id |
- type |
- user |
- statement |
- state |
- client ip |
- rows |
- startTime |
- elapsedTime |
-
-
-
-
-
+
+
+
+
+ | server |
+ id |
+ user |
+ query |
+ state |
+ client |
+ rows |
+ start |
+ end |
+ elapsed |
+
+
+
+
+
+
diff --git a/www/qc/queries.funcs.html b/www/qc/queries.funcs.html
index 12524b1..b8ad8f1 100644
--- a/www/qc/queries.funcs.html
+++ b/www/qc/queries.funcs.html
@@ -1,210 +1,203 @@
diff --git a/www/qc/queries.jsp b/www/qc/queries.jsp
index 87d35f4..901dc39 100644
--- a/www/qc/queries.jsp
+++ b/www/qc/queries.jsp
@@ -1,37 +1,43 @@
-<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
-<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
-
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
+
+<%
+boolean useWebSocket = clusters.getQcOption(request.getParameter("cluster")).isUseWebSocket();
+%>