You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2013/10/10 14:40:45 UTC
[6/6] git commit: TAJO-239: Improving web UI. (Keuntae Park via
hyunsik)
TAJO-239: Improving web UI. (Keuntae Park via hyunsik)
Project: http://git-wip-us.apache.org/repos/asf/incubator-tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tajo/commit/85b83940
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/85b83940
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/85b83940
Branch: refs/heads/master
Commit: 85b839403fc5b3ccde944b650b23d2977321b852
Parents: 5a257e2
Author: Hyunsik Choi <hy...@apache.org>
Authored: Thu Oct 10 19:48:27 2013 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Thu Oct 10 21:39:33 2013 +0900
----------------------------------------------------------------------
CHANGES.txt | 2 +
pom.xml | 1 +
.../org/apache/tajo/catalog/CatalogServer.java | 4 +
.../java/org/apache/tajo/master/TajoMaster.java | 95 +-
.../main/java/org/apache/tajo/util/JSPUtil.java | 167 +
.../tajo/webapp/QueryExecutorServlet.java | 360 +
.../java/org/apache/tajo/worker/TajoWorker.java | 52 +-
.../org/apache/tajo/worker/WorkerJSPUtil.java | 114 -
.../resources/webapps/admin/catalogview.jsp | 211 +-
.../main/resources/webapps/admin/cluster.jsp | 122 +
.../src/main/resources/webapps/admin/conf.jsp | 37 +
.../src/main/resources/webapps/admin/env.jsp | 48 +
.../src/main/resources/webapps/admin/header.jsp | 13 +
.../src/main/resources/webapps/admin/index.jsp | 187 +-
.../src/main/resources/webapps/admin/query.jsp | 108 +-
.../resources/webapps/admin/query_executor.jsp | 183 +
.../src/main/resources/webapps/admin/thread.jsp | 26 +
.../resources/webapps/static/img/logo_tajo.gif | Bin 0 -> 3025 bytes
.../webapps/static/js/jquery-ui.min.js | 5 +
.../main/resources/webapps/static/js/jquery.js | 2 +
.../static/js/jquery.jsPlumb-1.3.16-all-min.js | 1 +
.../static/js/jquery.jsPlumb-1.3.16-all.js | 10561 +++++++++++++++++
.../main/resources/webapps/static/queryplan.css | 55 +
.../src/main/resources/webapps/static/style.css | 321 +-
.../src/main/resources/webapps/worker/conf.jsp | 36 +
.../src/main/resources/webapps/worker/env.jsp | 50 +
.../main/resources/webapps/worker/header.jsp | 18 +
.../src/main/resources/webapps/worker/index.jsp | 184 +-
.../resources/webapps/worker/querydetail.jsp | 98 +-
.../main/resources/webapps/worker/queryplan.jsp | 220 +
.../resources/webapps/worker/querytasks.jsp | 96 +
.../src/main/resources/webapps/worker/tasks.jsp | 68 +
.../main/resources/webapps/worker/thread.jsp | 28 +
33 files changed, 12707 insertions(+), 766 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 3f01f04..e191aed 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -50,6 +50,8 @@ Release 0.2.0 - unreleased
IMPROVEMENTS
+ TAJO-239: Improving web UI. (Keuntae Park via hyunsik)
+
TAJO-232: Rename join operators and add other join operators to
PhysicalPlanner. (hyunsik)
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 1288547..fa247b8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -312,6 +312,7 @@
<exclude>**/*.schema</exclude>
<exclude>**/*.tbl</exclude>
<exclude>**/*.jsp</exclude>
+ <exclude>**/*.js</exclude>
<exclude>**/web.xml</exclude>
<exclude>**/*.result</exclude>
<!-- generated content -->
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java
index f810431..f15d962 100644
--- a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java
+++ b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java
@@ -122,6 +122,10 @@ public class CatalogServer extends AbstractService {
super.init(conf);
}
+ public String getCatalogServerName() {
+ return bindAddressStr + ", class=" + this.store.getClass().getSimpleName() + ", jdbc=" + conf.get(CatalogConstants.JDBC_URI);
+ }
+
private void initBuiltinFunctions(List<FunctionDesc> functions)
throws ServiceException {
for (FunctionDesc desc : functions) {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
index 2c09dd2..b303ad6 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
@@ -51,9 +51,13 @@ import org.apache.tajo.master.rm.YarnTajoResourceManager;
import org.apache.tajo.storage.AbstractStorageManager;
import org.apache.tajo.storage.StorageManagerFactory;
import org.apache.tajo.util.NetUtils;
+import org.apache.tajo.webapp.QueryExecutorServlet;
import org.apache.tajo.webapp.StaticHttpServer;
-import java.io.IOException;
+import java.io.*;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
@@ -106,10 +110,24 @@ public class TajoMaster extends CompositeService {
private QueryJobManager queryJobManager;
+ private ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
+
public TajoMaster() throws Exception {
super(TajoMaster.class.getName());
}
+ public String getMasterName() {
+ return tajoMasterService.getBindAddress().getHostName() + ":" + tajoMasterService.getBindAddress().getPort();
+ }
+
+ public String getVersion() {
+ return "0.2.0";
+ }
+
+ public TajoMasterClientService getTajoMasterClientService() {
+ return tajoMasterClientService;
+ }
+
@Override
public void init(Configuration _conf) {
this.systemConf = (TajoConf) _conf;
@@ -167,6 +185,7 @@ public class TajoMaster extends CompositeService {
int httpPort = systemConf.getInt("tajo.master.http.port", 8080);
webServer = StaticHttpServer.getInstance(this ,"admin", null, httpPort ,
true, null, context.getConf(), null);
+ webServer.addServlet("queryServlet", "/query_exec", QueryExecutorServlet.class);
webServer.start();
}
@@ -429,6 +448,10 @@ public class TajoMaster extends CompositeService {
return this.catalog;
}
+ public CatalogServer getCatalogServer() {
+ return this.catalogServer;
+ }
+
public AbstractStorageManager getStorageManager() {
return this.storeManager;
}
@@ -477,6 +500,76 @@ public class TajoMaster extends CompositeService {
}
}
+ String getThreadTaskName(long id, String name) {
+ if (name == null) {
+ return Long.toString(id);
+ }
+ return id + " (" + name + ")";
+ }
+
+ public void dumpThread(Writer writer) {
+ PrintWriter stream = new PrintWriter(writer);
+ int STACK_DEPTH = 20;
+ boolean contention = threadBean.isThreadContentionMonitoringEnabled();
+ long[] threadIds = threadBean.getAllThreadIds();
+ stream.println("Process Thread Dump: Tajo Worker");
+ stream.println(threadIds.length + " active threads");
+ for (long tid : threadIds) {
+ ThreadInfo info = threadBean.getThreadInfo(tid, STACK_DEPTH);
+ if (info == null) {
+ stream.println(" Inactive");
+ continue;
+ }
+ stream.println("Thread " + getThreadTaskName(info.getThreadId(), info.getThreadName()) + ":");
+ Thread.State state = info.getThreadState();
+ stream.println(" State: " + state + ", Blocked count: " + info.getBlockedCount() +
+ ", Waited count: " + info.getWaitedCount());
+ if (contention) {
+ stream.println(" Blocked time: " + info.getBlockedTime() + ", Waited time: " + info.getWaitedTime());
+ }
+ if (state == Thread.State.WAITING) {
+ stream.println(" Waiting on " + info.getLockName());
+ } else if (state == Thread.State.BLOCKED) {
+ stream.println(" Blocked on " + info.getLockName() +
+ ", Blocked by " + getThreadTaskName(info.getLockOwnerId(), info.getLockOwnerName()));
+ }
+ stream.println(" Stack:");
+ for (StackTraceElement frame : info.getStackTrace()) {
+ stream.println(" " + frame.toString());
+ }
+ stream.println("");
+ }
+ }
+
+ public static List<File> getMountPath() throws Exception {
+ BufferedReader mountOutput = null;
+ try {
+ Process mountProcess = Runtime.getRuntime ().exec("mount");
+ mountOutput = new BufferedReader(new InputStreamReader(mountProcess.getInputStream()));
+ List<File> mountPaths = new ArrayList<File>();
+ while (true) {
+ String line = mountOutput.readLine();
+ if (line == null) {
+ break;
+ }
+
+ System.out.println(line);
+
+ int indexStart = line.indexOf(" on /");
+ int indexEnd = line.indexOf(" ", indexStart + 4);
+
+ mountPaths.add(new File(line.substring (indexStart + 4, indexEnd)));
+ }
+ return mountPaths;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ } finally {
+ if(mountOutput != null) {
+ mountOutput.close();
+ }
+ }
+ }
public static void main(String[] args) throws Exception {
StringUtils.startupShutdownMessage(TajoMaster.class, args, LOG);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/util/JSPUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/util/JSPUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/util/JSPUtil.java
new file mode 100644
index 0000000..8b2a234
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/util/JSPUtil.java
@@ -0,0 +1,167 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.util;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.tajo.master.querymaster.QueryInProgress;
+import org.apache.tajo.master.querymaster.QueryMasterTask;
+import org.apache.tajo.master.querymaster.QueryUnit;
+import org.apache.tajo.master.querymaster.SubQuery;
+import org.apache.tajo.worker.TaskRunner;
+
+import java.text.DecimalFormat;
+import java.util.*;
+
+public class JSPUtil {
+ static DecimalFormat decimalF = new DecimalFormat("###.0");
+
+ public static void sortQueryUnit(QueryUnit[] queryUnits, String sortField, String sortOrder) {
+ if(sortField == null || sortField.isEmpty()) {
+ sortField = "id";
+ }
+
+ Arrays.sort(queryUnits, new QueryUnitComparator(sortField, "asc".equals(sortOrder)));
+ }
+
+ public static void sortTaskRunner(List<TaskRunner> taskRunners) {
+ Collections.sort(taskRunners, new Comparator<TaskRunner>() {
+ @Override
+ public int compare(TaskRunner taskRunner, TaskRunner taskRunner2) {
+ return taskRunner.getId().compareTo(taskRunner2.getId());
+ }
+ });
+ }
+
+ public static String getElapsedTime(long startTime, long finishTime) {
+ return finishTime == 0 ? decimalF.format((System.currentTimeMillis() - startTime) / 1000) + " sec"
+ : decimalF.format((finishTime - startTime) / 1000) + " sec";
+ }
+
+ public static String getTajoMasterHttpAddr(Configuration config) {
+ try {
+ String[] masterAddr = config.get("tajo.master.manager.addr").split(":");
+
+ return masterAddr[0] + ":" + config.getInt("tajo.master.http.port", 8080);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return e.getMessage();
+ }
+ }
+
+ public static List<QueryMasterTask> sortQueryMasterTask(Collection<QueryMasterTask> queryMasterTasks,
+ final boolean desc) {
+ List<QueryMasterTask> queryMasterTaskList = new ArrayList<QueryMasterTask>(queryMasterTasks);
+
+ Collections.sort(queryMasterTaskList, new Comparator<QueryMasterTask>() {
+
+ @Override
+ public int compare(QueryMasterTask task1, QueryMasterTask task2) {
+ if(desc) {
+ return task2.getQueryId().toString().compareTo(task1.getQueryId().toString());
+ } else {
+ return task1.getQueryId().toString().compareTo(task2.getQueryId().toString());
+ }
+ }
+ });
+
+ return queryMasterTaskList;
+ }
+
+ public static List<QueryInProgress> sortQueryInProgress(Collection<QueryInProgress> queryInProgresses,
+ final boolean desc) {
+ List<QueryInProgress> queryProgressList = new ArrayList<QueryInProgress>(queryInProgresses);
+
+ Collections.sort(queryProgressList, new Comparator<QueryInProgress>() {
+ @Override
+ public int compare(QueryInProgress query1, QueryInProgress query2) {
+ if(desc) {
+ return query2.getQueryId().toString().compareTo(query1.getQueryId().toString());
+ } else {
+ return query1.getQueryId().toString().compareTo(query2.getQueryId().toString());
+ }
+ }
+ });
+
+ return queryProgressList;
+ }
+
+ public static List<SubQuery> sortSubQuery(Collection<SubQuery> subQueries) {
+ List<SubQuery> subQueryList = new ArrayList<SubQuery>(subQueries);
+ Collections.sort(subQueryList, new Comparator<SubQuery>() {
+ @Override
+ public int compare(SubQuery subQuery1, SubQuery subQuery2) {
+ return subQuery1.getId().toString().compareTo(subQuery2.getId().toString());
+ }
+ });
+
+ return subQueryList;
+ }
+
+ static class QueryUnitComparator implements Comparator<QueryUnit> {
+ private String sortField;
+ private boolean asc;
+ public QueryUnitComparator(String sortField, boolean asc) {
+ this.sortField = sortField;
+ this.asc = asc;
+ }
+
+ @Override
+ public int compare(QueryUnit queryUnit, QueryUnit queryUnit2) {
+ if(asc) {
+ if("id".equals(sortField)) {
+ return queryUnit.getId().compareTo(queryUnit2.getId());
+ } else if("host".equals(sortField)) {
+ String host1 = queryUnit.getSucceededHost() == null ? "-" : queryUnit.getSucceededHost();
+ String host2 = queryUnit2.getSucceededHost() == null ? "-" : queryUnit2.getSucceededHost();
+ return host1.compareTo(host2);
+ } else if("runTime".equals(sortField)) {
+ return compareLong(queryUnit.getRunningTime(), queryUnit2.getRunningTime());
+ } else if("startTime".equals(sortField)) {
+ return compareLong(queryUnit.getLaunchTime(), queryUnit2.getLaunchTime());
+ } else {
+ return queryUnit.getId().compareTo(queryUnit2.getId());
+ }
+ } else {
+ if("id".equals(sortField)) {
+ return queryUnit2.getId().compareTo(queryUnit.getId());
+ } else if("host".equals(sortField)) {
+ String host1 = queryUnit.getSucceededHost() == null ? "-" : queryUnit.getSucceededHost();
+ String host2 = queryUnit2.getSucceededHost() == null ? "-" : queryUnit2.getSucceededHost();
+ return host2.compareTo(host1);
+ } else if("runTime".equals(sortField)) {
+ return compareLong(queryUnit2.getRunningTime(), queryUnit.getRunningTime());
+ } else if("startTime".equals(sortField)) {
+ return compareLong(queryUnit2.getLaunchTime(), queryUnit.getLaunchTime());
+ } else {
+ return queryUnit2.getId().compareTo(queryUnit.getId());
+ }
+ }
+ }
+ }
+
+ static int compareLong(long a, long b) {
+ if(a > b) {
+ return 1;
+ } else if(a < b) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
new file mode 100644
index 0000000..2ba563c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
@@ -0,0 +1,360 @@
+package org.apache.tajo.webapp;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.util.StringUtils;
+import org.apache.tajo.QueryId;
+import org.apache.tajo.TajoProtos;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.client.QueryStatus;
+import org.apache.tajo.client.TajoClient;
+import org.apache.tajo.conf.TajoConf;
+import org.apache.tajo.ipc.ClientProtos;
+import org.apache.tajo.util.JSPUtil;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.glassfish.grizzly.threadpool.FixedThreadPool;
+
+import javax.servlet.ServletConfig;
+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.OutputStream;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class QueryExecutorServlet extends HttpServlet {
+ private static final Log LOG = LogFactory.getLog(QueryExecutorServlet.class);
+
+ ObjectMapper om = new ObjectMapper();
+
+ //queryRunnerId -> QueryRunner
+ private Map<String, QueryRunner> queryRunners = new HashMap<String, QueryRunner>();
+
+ private TajoClient tajoClient;
+
+ private ExecutorService queryRunnerExecutor = Executors.newFixedThreadPool(5);
+
+ private QueryRunnerCleaner queryRunnerCleaner;
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ om.getDeserializationConfig().disable(
+ DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
+
+ try {
+ tajoClient = new TajoClient(new TajoConf());
+
+ queryRunnerCleaner = new QueryRunnerCleaner();
+ queryRunnerCleaner.start();
+ } catch (IOException e) {
+ LOG.error(e.getMessage());
+ }
+ }
+
+ @Override
+ public void service(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ String action = request.getParameter("action");
+ Map<String, Object> returnValue = new HashMap<String, Object>();
+ try {
+ if(tajoClient == null) {
+ errorResponse(response, "TajoClient not initialized");
+ return;
+ }
+ if(action == null || action.trim().isEmpty()) {
+ errorResponse(response, "no action parameter.");
+ return;
+ }
+
+ if("runQuery".equals(action)) {
+ String query = request.getParameter("query");
+ if(query == null || query.trim().isEmpty()) {
+ errorResponse(response, "No query parameter");
+ return;
+ }
+ String queryRunnerId = null;
+ while(true) {
+ synchronized(queryRunners) {
+ queryRunnerId = "" + System.currentTimeMillis();
+ if(!queryRunners.containsKey(queryRunnerId)) {
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ QueryRunner queryRunner = new QueryRunner(queryRunnerId, query);
+ synchronized(queryRunners) {
+ queryRunners.put(queryRunnerId, queryRunner);
+ }
+ queryRunnerExecutor.submit(queryRunner);
+ returnValue.put("queryRunnerId", queryRunnerId);
+ } else if("getQueryProgress".equals(action)) {
+ synchronized(queryRunners) {
+ String queryRunnerId = request.getParameter("queryRunnerId");
+ QueryRunner queryRunner = queryRunners.get(queryRunnerId);
+ if(queryRunner == null) {
+ errorResponse(response, "No query info:" + queryRunnerId);
+ return;
+ }
+ if(queryRunner.error != null) {
+ errorResponse(response, queryRunner.error);
+ return;
+ }
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ returnValue.put("progress", queryRunner.progress);
+ returnValue.put("startTime", df.format(queryRunner.startTime));
+ returnValue.put("finishTime", queryRunner.finishTime == 0 ? "-" : df.format(queryRunner.startTime));
+ returnValue.put("runningTime", JSPUtil.getElapsedTime(queryRunner.startTime, queryRunner.finishTime));
+ }
+ } else if("getQueryResult".equals(action)) {
+ synchronized(queryRunners) {
+ String queryRunnerId = request.getParameter("queryRunnerId");
+ QueryRunner queryRunner = queryRunners.get(queryRunnerId);
+ if(queryRunner == null) {
+ errorResponse(response, "No query info:" + queryRunnerId);
+ return;
+ }
+ if(queryRunner.error != null) {
+ errorResponse(response, queryRunner.error);
+ return;
+ }
+ returnValue.put("resultData", queryRunner.queryResult);
+ returnValue.put("resultColumns", queryRunner.columnNames);
+ returnValue.put("runningTime", JSPUtil.getElapsedTime(queryRunner.startTime, queryRunner.finishTime));
+ }
+ } else if("clearAllQueryRunner".equals(action)) {
+ synchronized(queryRunners) {
+ for(QueryRunner eachQueryRunner: queryRunners.values()) {
+ eachQueryRunner.setStop();
+ }
+ queryRunners.clear();
+ }
+ }
+ returnValue.put("success", "true");
+ writeHttpResponse(response, returnValue);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ errorResponse(response, e);
+ }
+ }
+
+ private void errorResponse(HttpServletResponse response, Exception e) throws IOException {
+ errorResponse(response, e.getMessage() + "\n" + StringUtils.stringifyException(e));
+ }
+
+ private void errorResponse(HttpServletResponse response, String message) throws IOException {
+ Map<String, Object> errorMessage = new HashMap<String, Object>();
+ errorMessage.put("success", "false");
+ errorMessage.put("errorMessage", message);
+ writeHttpResponse(response, errorMessage);
+ }
+
+ private void writeHttpResponse(HttpServletResponse response, Map<String, Object> outputMessage) throws IOException {
+ response.setContentType("text/html");
+
+ OutputStream out = response.getOutputStream();
+ out.write(om.writeValueAsBytes(outputMessage));
+
+ out.flush();
+ out.close();
+ }
+
+ class QueryRunnerCleaner extends Thread {
+ public void run() {
+ List<QueryRunner> queryRunnerList;
+ synchronized(queryRunners) {
+ queryRunnerList = new ArrayList<QueryRunner>(queryRunners.values());
+ for(QueryRunner eachQueryRunner: queryRunnerList) {
+ if(!eachQueryRunner.running.get() &&
+ (System.currentTimeMillis() - eachQueryRunner.finishTime > 180 * 1000)) {
+ queryRunners.remove(eachQueryRunner.queryRunnerId);
+ }
+ }
+ }
+ }
+ }
+
+ class QueryRunner extends Thread {
+ long startTime;
+ long finishTime;
+
+ String queryRunnerId;
+
+ ClientProtos.GetQueryStatusResponse queryRespons;
+ AtomicBoolean running = new AtomicBoolean(true);
+ AtomicBoolean stop = new AtomicBoolean(false);
+ QueryId queryId;
+ String query;
+ Exception error;
+
+ AtomicInteger progress = new AtomicInteger(0);
+
+ List<String> columnNames = new ArrayList<String>();
+
+ List<List<Object>> queryResult;
+
+ public QueryRunner(String queryRunnerId, String query) {
+ this.queryRunnerId = queryRunnerId;
+ this.query = query;
+ }
+
+ public void setStop() {
+ this.stop.set(true);
+ this.interrupt();
+ }
+
+ public void run() {
+ startTime = System.currentTimeMillis();
+ try {
+ queryRespons = tajoClient.executeQuery(query);
+ if (queryRespons.getResultCode() == ClientProtos.ResultCode.OK) {
+ QueryId queryId = null;
+ try {
+ queryId = new QueryId(queryRespons.getQueryId());
+ getQueryResult(queryId);
+ } finally {
+ if (queryId != null) {
+ tajoClient.closeQuery(queryId);
+ }
+ }
+ } else {
+ LOG.error("queryRespons.getResultCode() not OK:" + queryRespons.getResultCode());
+ error = new Exception("queryRespons.getResultCode() not OK:" + queryRespons.getResultCode());
+ }
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ error = e;
+ } finally {
+ running.set(false);
+ finishTime = System.currentTimeMillis();
+ }
+ }
+
+ private void getQueryResult(QueryId tajoQueryId) {
+ // query execute
+ try {
+ QueryStatus status = null;
+
+ while (!stop.get()) {
+ try {
+ Thread.sleep(1000);
+ } catch(InterruptedException e) {
+ break;
+ }
+ status = tajoClient.getQueryStatus(tajoQueryId);
+ if (status.getState() == TajoProtos.QueryState.QUERY_MASTER_INIT
+ || status.getState() == TajoProtos.QueryState.QUERY_MASTER_LAUNCHED) {
+ continue;
+ }
+
+ if (status.getState() == TajoProtos.QueryState.QUERY_RUNNING
+ || status.getState() == TajoProtos.QueryState.QUERY_SUCCEEDED) {
+ int progressValue = (int) (status.getProgress() * 100.0f);
+ if(progressValue == 100) {
+ progressValue = 99;
+ }
+ progress.set(progressValue);
+ }
+ if (status.getState() != TajoProtos.QueryState.QUERY_RUNNING
+ && status.getState() != TajoProtos.QueryState.QUERY_NOT_ASSIGNED) {
+ break;
+ }
+ }
+
+ if(status == null) {
+ LOG.error("Query Status is null");
+ error = new Exception("Query Status is null");
+ return;
+ }
+ if (status.getState() == TajoProtos.QueryState.QUERY_ERROR ||
+ status.getState() == TajoProtos.QueryState.QUERY_FAILED) {
+ error = new Exception(status.getErrorMessage());
+ } else if (status.getState() == TajoProtos.QueryState.QUERY_KILLED) {
+ LOG.info(queryId + " is killed.");
+ error = new Exception(queryId + " is killed.");
+ } else {
+ if (status.getState() == TajoProtos.QueryState.QUERY_SUCCEEDED) {
+ if (status.hasResult()) {
+ ResultSet res = tajoClient.getQueryResult(tajoQueryId);
+ try {
+ ResultSetMetaData rsmd = res.getMetaData();
+ TableDesc desc = tajoClient.getResultDesc(tajoQueryId);
+ LOG.info("Tajo Query Result: " + desc.getPath() + "\n");
+
+ int numOfColumns = rsmd.getColumnCount();
+ for(int i = 0; i < numOfColumns; i++) {
+ columnNames.add(rsmd.getColumnName(i + 1));
+ }
+ queryResult = new ArrayList<List<Object>>();
+
+ int rowCount = 0;
+ boolean hasMoreData = false;
+ while (res.next()) {
+ if(rowCount > 1000) {
+ hasMoreData = true;
+ break;
+ }
+ List<Object> row = new ArrayList<Object>();
+ for(int i = 0; i < numOfColumns; i++) {
+ row.add(res.getObject(i + 1).toString());
+ }
+ queryResult.add(row);
+ rowCount++;
+
+ }
+ } finally {
+ if (res != null) {
+ res.close();
+ }
+ progress.set(100);
+ }
+ } else {
+ error = new Exception(queryId + " no result");
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ error = e;
+ }
+ }
+ }
+
+ static class QueryResult {
+ String queryId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java
index 8b115b1..d9984b8 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/TajoWorker.java
@@ -42,10 +42,10 @@ import org.apache.tajo.util.NetUtils;
import org.apache.tajo.util.TajoIdUtils;
import org.apache.tajo.webapp.StaticHttpServer;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.*;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
@@ -95,6 +95,8 @@ public class TajoWorker extends CompositeService {
private int httpPort;
+ private ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
+
public TajoWorker(String daemonMode) throws Exception {
super(TajoWorker.class.getName());
this.daemonMode = daemonMode;
@@ -468,6 +470,47 @@ public class TajoWorker extends CompositeService {
setWorkerMode(args);
}
+ String getThreadTaskName(long id, String name) {
+ if (name == null) {
+ return Long.toString(id);
+ }
+ return id + " (" + name + ")";
+ }
+
+ public void dumpThread(Writer writer) {
+ PrintWriter stream = new PrintWriter(writer);
+ int STACK_DEPTH = 20;
+ boolean contention = threadBean.isThreadContentionMonitoringEnabled();
+ long[] threadIds = threadBean.getAllThreadIds();
+ stream.println("Process Thread Dump: Tajo Worker");
+ stream.println(threadIds.length + " active threads");
+ for (long tid : threadIds) {
+ ThreadInfo info = threadBean.getThreadInfo(tid, STACK_DEPTH);
+ if (info == null) {
+ stream.println(" Inactive");
+ continue;
+ }
+ stream.println("Thread " + getThreadTaskName(info.getThreadId(), info.getThreadName()) + ":");
+ Thread.State state = info.getThreadState();
+ stream.println(" State: " + state + ", Blocked count: " + info.getBlockedCount() +
+ ", Waited count: " + info.getWaitedCount());
+ if (contention) {
+ stream.println(" Blocked time: " + info.getBlockedTime() + ", Waited time: " + info.getWaitedTime());
+ }
+ if (state == Thread.State.WAITING) {
+ stream.println(" Waiting on " + info.getLockName());
+ } else if (state == Thread.State.BLOCKED) {
+ stream.println(" Blocked on " + info.getLockName() +
+ ", Blocked by " + getThreadTaskName(info.getLockOwnerId(), info.getLockOwnerName()));
+ }
+ stream.println(" Stack:");
+ for (StackTraceElement frame : info.getStackTrace()) {
+ stream.println(" " + frame.toString());
+ }
+ stream.println("");
+ }
+ }
+
public static List<File> getMountPath() throws Exception {
BufferedReader mountOutput = null;
try {
@@ -507,6 +550,7 @@ public class TajoWorker extends CompositeService {
}
public static void main(String[] args) throws Exception {
+ args = new String[]{"standby"};
StringUtils.startupShutdownMessage(TajoWorker.class, args, LOG);
if(args.length < 1) {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/WorkerJSPUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/WorkerJSPUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/WorkerJSPUtil.java
deleted file mode 100644
index ba49ff6..0000000
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/worker/WorkerJSPUtil.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.worker;
-
-import org.apache.hadoop.conf.Configuration;
-import org.apache.tajo.master.querymaster.QueryUnit;
-
-import java.text.DecimalFormat;
-import java.util.*;
-
-public class WorkerJSPUtil {
- public static void sortQueryUnit(QueryUnit[] queryUnits, String sortField, String sortOrder) {
- if(sortField == null || sortField.isEmpty()) {
- sortField = "id";
- }
-
- Arrays.sort(queryUnits, new QueryUnitComparator(sortField, "asc".equals(sortOrder)));
- }
-
- public static void sortTaskRunner(List<TaskRunner> taskRunners) {
- Collections.sort(taskRunners, new Comparator<TaskRunner>() {
- @Override
- public int compare(TaskRunner taskRunner, TaskRunner taskRunner2) {
- return taskRunner.getId().compareTo(taskRunner2.getId());
- }
- });
- }
-
- static DecimalFormat decimalF = new DecimalFormat("###.0");
-
- public static String getElapsedTime(long startTime, long finishTime) {
- return finishTime == 0 ? decimalF.format((System.currentTimeMillis() - startTime) / 1000) + " sec"
- : decimalF.format((finishTime - startTime) / 1000) + " sec";
- }
-
- public static String getTajoMasterHttpAddr(Configuration config) {
- try {
- String[] masterAddr = config.get("tajo.master.manager.addr").split(":");
-
- return masterAddr[0] + ":" + config.getInt("tajo.master.http.port", 8080);
- } catch (Exception e) {
- e.printStackTrace();
- return e.getMessage();
- }
- }
-
- static class QueryUnitComparator implements Comparator<QueryUnit> {
- private String sortField;
- private boolean asc;
- public QueryUnitComparator(String sortField, boolean asc) {
- this.sortField = sortField;
- this.asc = asc;
- }
-
- @Override
- public int compare(QueryUnit queryUnit, QueryUnit queryUnit2) {
- if(asc) {
- if("id".equals(sortField)) {
- return queryUnit.getId().compareTo(queryUnit2.getId());
- } else if("host".equals(sortField)) {
- String host1 = queryUnit.getSucceededHost() == null ? "-" : queryUnit.getSucceededHost();
- String host2 = queryUnit2.getSucceededHost() == null ? "-" : queryUnit2.getSucceededHost();
- return host1.compareTo(host2);
- } else if("runTime".equals(sortField)) {
- return compareLong(queryUnit.getRunningTime(), queryUnit2.getRunningTime());
- } else if("startTime".equals(sortField)) {
- return compareLong(queryUnit.getLaunchTime(), queryUnit2.getLaunchTime());
- } else {
- return queryUnit.getId().compareTo(queryUnit2.getId());
- }
- } else {
- if("id".equals(sortField)) {
- return queryUnit2.getId().compareTo(queryUnit.getId());
- } else if("host".equals(sortField)) {
- String host1 = queryUnit.getSucceededHost() == null ? "-" : queryUnit.getSucceededHost();
- String host2 = queryUnit2.getSucceededHost() == null ? "-" : queryUnit2.getSucceededHost();
- return host2.compareTo(host1);
- } else if("runTime".equals(sortField)) {
- return compareLong(queryUnit2.getRunningTime(), queryUnit.getRunningTime());
- } else if("startTime".equals(sortField)) {
- return compareLong(queryUnit2.getLaunchTime(), queryUnit.getLaunchTime());
- } else {
- return queryUnit2.getId().compareTo(queryUnit.getId());
- }
- }
- }
- }
-
- static int compareLong(long a, long b) {
- if(a > b) {
- return 1;
- } else if(a < b) {
- return -1;
- } else {
- return 0;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp
index 44c43b3..4b3265b 100644
--- a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/catalogview.jsp
@@ -1,118 +1,121 @@
-<%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
-<%--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- http://www.apache.org/licenses/LICENSE-2.0
+<%@ page import="java.util.*" %>
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="org.apache.tajo.catalog.*" %>
+<%@ page import="org.apache.tajo.util.FileUtil" %>
+<%
+ TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+ CatalogService catalog = master.getCatalog();
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--- %>
+ String selectedDatabase = request.getParameter("database");
+ if(selectedDatabase == null || selectedDatabase.trim().isEmpty()) {
+ selectedDatabase = "default";
+ }
-<%@ page import="java.util.*" %>
-<%@ page import="nta.engine.cluster.ClusterManager" %>
-<%@ page import="com.google.gson.Gson" %>
-<%@ page import="nta.engine.json.*" %>
-<%@ page import="nta.catalog.*" %>
-<%@ page import="nta.engine.*" %>
+ TableDesc tableDesc = null;
+ String selectedTable = request.getParameter("table");
+ if(selectedTable != null && !selectedTable.trim().isEmpty()) {
+ tableDesc = catalog.getTableDesc(selectedTable);
+ } else {
+ selectedTable = "";
+ }
+
+ //TODO filter with database
+ Collection<String> tableNames = catalog.getAllTableNames();
+%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
- <link rel="stylesheet" type = "text/css" href = "./style.css" />
+ <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Tajo Catalog</title>
- <%
- String masterAddr = (String)application.getAttribute("tajo.master.addr");
- NtaEngineMaster master = (NtaEngineMaster)application.getAttribute("tajo.master");
- CatalogService catalog = master.getCatalog();
- String tableName = request.getParameter("tablename");
- if(tableName == null) {
- if(master.getCatalog().getAllTableNames().iterator().hasNext())
- tableName = catalog.getAllTableNames().iterator().next();
- else
- tableName = null;
- }
- TableDesc desc = null;
- TableMeta meta = null;
- Collection<String> tableList = null;
- if(tableName != null) {
- desc = catalog.getTableDesc(tableName);
- meta = desc.getMeta();
- tableList = master.getCatalog().getAllTableNames();
- }
- %>
+ <title>Tajo</title>
</head>
<body>
- <div class = "container" >
- <img src="./img/tajochar_catalog_small.jpg" />
- </div>
- <br />
- <div class = "headline_2">
- <div class = "container">
- <a href="./index.jsp" class="headline">Tajo Main</a>
-
- <a href="./nodeview.jsp" class="headline">Workers</a>
-
- <a href="./queryview.jsp" class="headline">Queries</a>
- </div>
- </div>
- <div class = "container">
-
- <%
- if(tableName != null) {
- out.write("<h2 class = \"line\" >Table Info</h2>");
- TableDesc table = catalog.getTableDesc(tableName);
- out.write("<ul>");
- out.write("<li> Table Name : " + table.getId() + "</li>");
- out.write("<li> Table Path : " + table.getPath() + "</li>");
- out.write("<li> Store Type : " + table.getMeta().getStoreType() + "</li>");
- out.write("<li> Schema<ul>");
- Schema schema = table.getMeta().getSchema();
- for(int i = 0 ; i < table.getMeta().getSchema().size() ; i ++) {
- out.write("<li>" + schema.getColumn(i).toString() + "</li>");
- }
- out.write("</ul>");
- out.write("</li>");
- out.write("</ul>");
- }
- %>
- <h2 class = "line">Table List</h2>
- <table align = "center" class = "new">
- <tr>
- <th>TableName</th>
- <th>TablePath</th>
- <th>StoreType</th>
- </tr>
- <%
- String[] tableArr = catalog.getAllTableNames().toArray(new String[0]);
- for(int i = 0 ; i < tableArr.length ; i ++ ) {
- TableDesc table = catalog.getTableDesc(tableArr[i]);
- %>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+ <h2>Tajo Master: <%=master.getMasterName()%></h2>
+ <hr/>
+ <h3>Catalog</h3>
+ <p/>
+ <table width="100%" border='0'>
<tr>
- <td><a href = "./catalogview.jsp?tablename=<%=table.getId()%>" class = "tablelink"><%=table.getId()%></a></td>
- <td><%=table.getPath()%></td>
- <td><%=table.getMeta().getStoreType()%></td>
- </tr>
- <%
+ <!-- left -->
+ <td width="20%" valign="top">
+ <div>
+ <b>Database:</b>
+ <select width="190" style="width: 190px">
+ <option value="default" selected>default</option>
+ </select>
+ </div>
+ <!-- table list -->
+ <div style='margin-top:5px'>
+<%
+ if(tableNames == null || tableNames.isEmpty()) {
+ out.write("No tables");
+ } else {
+%>
+ <table width="100%" border="1" class="border_table">
+ <tr><th>Table Name</th></tr>
+<%
+ for(String eachTableName: tableNames) {
+ String bold = "";
+ if(eachTableName.equals(selectedTable)) {
+ bold = "font-weight:bold";
+ }
+ String detailLink = "catalogview.jsp?database=" + selectedDatabase + "&table=" + eachTableName;
+ out.write("<tr><td><span style='" + bold + "'><a href='" + detailLink + "'>" + eachTableName + "</a></span></td></tr>");
}
- %>
- </table>
-
- <h2 class = "line">Function List</h2>
- <h2 class = "line">Others</h2>
-
-
- </div>
+%>
+ </table>
+<%
+ }
+%>
+ </div>
+ </td>
+ <!-- right -->
+ <td width="80%" valign="top">
+ <div style='margin-left: 15px'>
+ <div style='font-weight:bold'>Table name: <%=selectedTable%></div>
+ <div style='margin-top:5px'>
+<%
+ if(tableDesc != null) {
+ List<Column> columns = tableDesc.getSchema().getColumns();
+ out.write("<table border='1' class='border_table'><tr><th>No</th><th>Column name</th><th>Type</th></tr>");
+ int columnIndex = 1;
+ for(Column eachColumn: columns) {
+ out.write("<tr><td width='30' align='right'>" + columnIndex + "</td><td width='320'>" + eachColumn.getColumnName() + "</td><td width='150'>" + eachColumn.getDataType().getType() + "</td></tr>");
+ columnIndex++;
+ }
+
+ String optionStr = "";
+ String prefix = "";
+ for(Map.Entry<String, String> entry: tableDesc.getMeta().toMap().entrySet()) {
+ optionStr += prefix + "'" + entry.getKey() + "'='" + entry.getValue() + "'";
+ prefix = "<br/>";
+ }
+ out.write("</table>");
+%>
+ </div>
+ <div style='margin-top:10px'>
+ <div style=''>Detail</div>
+ <table border="1" class='border_table'>
+ <tr><td width='100'>Table path</td><td width='410'><%=tableDesc.getPath()%></td></tr>
+ <tr><td>Store type</td><td><%=tableDesc.getMeta().getStoreType()%></td></tr>
+ <tr><td># rows</td><td><%=tableDesc.getMeta().getStat().getNumRows()%></td></tr>
+ <tr><td>Volume</td><td><%=FileUtil.humanReadableByteCount(tableDesc.getMeta().getStat().getNumBytes(),true)%></td></tr>
+ <tr><td>Options</td><td><%=optionStr%></td></tr>
+ </table>
+ </div>
+ </div>
+<%
+ }
+%>
+ </td>
+ </tr>
+ </table>
+</div>
</body>
</html>
-
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/cluster.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/cluster.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/cluster.jsp
new file mode 100644
index 0000000..20dbc7c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/cluster.jsp
@@ -0,0 +1,122 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="java.util.*" %>
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="org.apache.tajo.master.rm.*" %>
+
+<%
+ TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+ Map<String, WorkerResource> workers = master.getContext().getResourceManager().getWorkers();
+ List<String> wokerKeys = new ArrayList<String>(workers.keySet());
+ Collections.sort(wokerKeys);
+
+ int totalSlot = 0;
+ int runningSlot = 0;
+ int idleSlot = 0;
+
+ List<WorkerResource> liveWorkers = new ArrayList<WorkerResource>();
+ List<WorkerResource> deadWorkers = new ArrayList<WorkerResource>();
+ List<WorkerResource> decommissionWorkers = new ArrayList<WorkerResource>();
+
+ for(WorkerResource eachWorker: workers.values()) {
+ if(eachWorker.getWorkerStatus() == WorkerStatus.LIVE) {
+ liveWorkers.add(eachWorker);
+ idleSlot += eachWorker.getAvaliableSlots();
+ totalSlot += eachWorker.getSlots();
+ runningSlot += eachWorker.getUsedSlots();
+ } else if(eachWorker.getWorkerStatus() == WorkerStatus.DEAD) {
+ deadWorkers.add(eachWorker);
+ } else if(eachWorker.getWorkerStatus() == WorkerStatus.DECOMMISSION) {
+ decommissionWorkers.add(eachWorker);
+ }
+ }
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+ <h2>Tajo Master: <%=master.getMasterName()%></h2>
+ <hr/>
+ <div>Live:<%=liveWorkers.size()%>, Dead: <%=deadWorkers.size()%>, Decommission: <%=decommissionWorkers.size()%></div>
+ <hr/>
+ <h3>Live Workers</h3>
+<%
+ if(liveWorkers.isEmpty()) {
+%>
+ No Live Workers
+<%
+ } else {
+%>
+ <table width="100%" class="border_table" border="1">
+ <tr><th>No</th><th>Worker</th><th>Ports</th><th>Running Tasks</th><th>Slot</th></th><th>Heap(free/max)</th><th>Disk</th><th>Cpu</th><th>Status</th></tr>
+<%
+ int no = 1;
+ for(WorkerResource worker: liveWorkers) {
+ String workerHttp = "http://" + worker.getAllocatedHost() + ":" + worker.getHttpPort();
+%>
+ <tr>
+ <td width='30' align='right'><%=no++%></td>
+ <td><a href='<%=workerHttp%>'><%=worker.getAllocatedHost() + ":" + worker.getManagerPort()%></a></td>
+ <td width='100'><%=worker.portsToStr()%></td>
+ <td width='100' align='right'><%=worker.getNumRunningTasks()%></td>
+ <td width='100' align='right'><%=worker.getUsedSlots()%>/<%=worker.getSlots()%></td>
+ <td width='100' align='left'><%=worker.getFreeHeap()/1024/1024%>/<%=worker.getMaxHeap()/1024/1024%> MB</td>
+ <td width='100' align='right'><%=worker.getUsedDiskSlots()%>/<%=worker.getDiskSlots()%></td>
+ <td width='100' align='right'><%=worker.getUsedCpuCoreSlots()%>/<%=worker.getCpuCoreSlots()%></td>
+ <td width='100' align='center'><%=worker.getWorkerStatus()%></td>
+ </tr>
+<%
+ } //end fo for
+%>
+ </table>
+<%
+ } //end of if
+%>
+
+ <p/>
+ <hr/>
+ <p/>
+ <h3>Dead Workers</h3>
+
+<%
+ if(deadWorkers.isEmpty()) {
+%>
+ No Dead Workers
+<%
+ } else {
+%>
+ <table width="100%" class="border_table" border="1">
+ <tr><th>No</th><th>Worker</th><th>Ports</th><th>Running Tasks</th><th>Slot</th></th><th>Heap(free/max)</th><th>Disk</th><th>Cpu</th><th>Status</th></tr>
+<%
+ int no = 1;
+ for(WorkerResource worker: deadWorkers) {
+%>
+ <tr>
+ <td width='30' align='right'><%=no++%></td>
+ <td><%=worker.getAllocatedHost() + ":" + worker.getManagerPort()%></td>
+ <td><%=worker.portsToStr()%></td>
+ <td><%=worker.getNumRunningTasks()%></td>
+ <td><%=worker.getUsedSlots()%>/<%=worker.getSlots()%></td>
+ <td><%=worker.getFreeHeap()/1024/1024%>/<%=worker.getMaxHeap()/1024/1024%> MB</td>
+ <td><%=worker.getUsedDiskSlots()%>/<%=worker.getDiskSlots()%></td>
+ <td><%=worker.getUsedCpuCoreSlots()%>/<%=worker.getCpuCoreSlots()%></td>
+ <td><%=worker.getWorkerStatus()%></td>
+ </tr>
+<%
+ } //end fo for
+%>
+ </table>
+<%
+ } //end of if
+%>
+</div>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/conf.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/conf.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/conf.jsp
new file mode 100644
index 0000000..323d6d8
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/conf.jsp
@@ -0,0 +1,37 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="org.apache.tajo.conf.*" %>
+<%@ page import="java.util.Map" %>
+
+<%
+ TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+ TajoMaster.MasterContext context = master.getContext();
+ TajoConf tajoConf = context.getConf();
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+ <h2>Tajo Master: <%=master.getMasterName()%></h2>
+ <hr/>
+ <table width="100%" border="1" class="border_table">
+<%
+ for(Map.Entry<String,String> entry: tajoConf) {
+%>
+ <tr><td width="200"><%=entry.getKey()%></td><td><%=entry.getValue()%></td>
+<%
+ }
+%>
+ </table>
+</div>
+</body>
+</html>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/env.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/env.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/env.jsp
new file mode 100644
index 0000000..122917b
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/env.jsp
@@ -0,0 +1,48 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="java.util.Map" %>
+
+<%
+ TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+ <h2>Tajo Master: <%=master.getMasterName()%></h2>
+ <hr/>
+ <h3>System Environment</h3>
+ <table width="100%" class="border_table">
+<%
+ for(Map.Entry<String, String> entry: System.getenv().entrySet()) {
+%>
+ <tr><td width="200"><%=entry.getKey()%></td><td><%=entry.getValue()%></td>
+<%
+ }
+%>
+ </table>
+
+ <h3>Properties</h3>
+ <hr/>
+
+ <table width="100%" class="border_table">
+<%
+ for(Map.Entry<Object, Object> entry: System.getProperties().entrySet()) {
+%>
+ <tr><td width="200"><%=entry.getKey()%></td><td><%=entry.getValue()%></td>
+<%
+ }
+%>
+ </table>
+</div>
+</body>
+</html>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/header.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/header.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/header.jsp
new file mode 100644
index 0000000..3f26e20
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/header.jsp
@@ -0,0 +1,13 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<div class="menu">
+ <div style='float:left; margin-left:12px; margin-top:6px;'><a href='index.jsp'><img src='/static/img/logo_tajo.gif' border='0'/></a></div>
+ <ul>
+ <li><a class='top_menu_item' style='margin-left:10px;' href='index.jsp'>Home</a></li>
+ <li><a class='top_menu_item' href='cluster.jsp'>Cluster</a></li>
+ <li><a class='top_menu_item' href='query.jsp'>Query</a></li>
+ <li><a class='top_menu_item' href='catalogview.jsp'>Catalog</a></li>
+ <li><a class='top_menu_item' href='query_executor.jsp'>Execute Query</a></li>
+ </ul>
+ <br style='clear:left'/>
+</div>
+
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp
index cc262dd..f592c7d 100644
--- a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/index.jsp
@@ -1,114 +1,117 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
-<%@ page import="java.net.InetSocketAddress" %>
-<%@ page import="java.net.InetAddress" %>
-<%@ page import="org.apache.hadoop.conf.Configuration" %>
<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
<%@ page import="org.apache.tajo.master.*" %>
<%@ page import="org.apache.tajo.master.rm.*" %>
<%@ page import="org.apache.tajo.catalog.*" %>
<%@ page import="org.apache.tajo.master.querymaster.QueryInProgress" %>
-<%@ page import="java.text.SimpleDateFormat" %>
+<%@ page import="org.apache.tajo.util.NetUtils" %>
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
- <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>tajo main</title>
- <%
- TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
- CatalogService catalog = master.getCatalog();
- Map<String, WorkerResource> workers = master.getContext().getResourceManager().getWorkers();
- List<String> wokerKeys = new ArrayList<String>(workers.keySet());
- Collections.sort(wokerKeys);
- %>
-</head>
-<body>
-<img src='/static/img/tajo_logo.png'/>
-<hr/>
+<%
+ TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+ Map<String, WorkerResource> workers = master.getContext().getResourceManager().getWorkers();
-<h3>Works</h3>
-<div>Live:<%=wokerKeys.size()%></div>
-<table>
- <tr><th>Worker</th><th>Ports</th><th>Running Tasks</th><th>Slot</th></th><th>Heap(free/max)</th><th>Disk</th><th>Cpu</th><th>Status</th></tr>
- <%
- for(String eachWorker: wokerKeys) {
- WorkerResource worker = workers.get(eachWorker);
- String workerHttp = "http://" + worker.getAllocatedHost() + ":" + worker.getHttpPort();
- %>
+ int numLiveWorkers = 0;
+ int numDeadWorkers = 0;
+ int numDecommissionWorkers = 0;
- <tr>
- <td><a href='<%=workerHttp%>'><%=eachWorker%></a></td>
- <td><%=worker.portsToStr()%></td>
- <td><%=worker.getNumRunningTasks()%></td>
- <td><%=worker.getUsedSlots()%>/<%=worker.getSlots()%></td>
- <td><%=worker.getFreeHeap()/1024/1024%>/<%=worker.getMaxHeap()/1024/1024%> MB</td>
- <td><%=worker.getUsedDiskSlots()%>/<%=worker.getDiskSlots()%></td>
- <td><%=worker.getUsedCpuCoreSlots()%>/<%=worker.getCpuCoreSlots()%></td>
- <td><%=worker.getWorkerStatus()%></td>
- </tr>
- <%
- }
+ int totalSlot = 0;
+ int runningSlot = 0;
+ int idleSlot = 0;
- if(workers.isEmpty()) {
- %>
- <tr>
- <td colspan='7'>No Workers</td>
- </tr>
- <%
+ for(WorkerResource eachWorker: workers.values()) {
+ if(eachWorker.getWorkerStatus() == WorkerStatus.LIVE) {
+ numLiveWorkers++;
+ idleSlot += eachWorker.getAvaliableSlots();
+ totalSlot += eachWorker.getSlots();
+ runningSlot += eachWorker.getUsedSlots();
+ } else if(eachWorker.getWorkerStatus() == WorkerStatus.DEAD) {
+ numDeadWorkers++;
+ } else if(eachWorker.getWorkerStatus() == WorkerStatus.DECOMMISSION) {
+ numDecommissionWorkers++;
}
- %>
-</table>
+ }
-<%
Collection<QueryInProgress> runningQueries = master.getContext().getQueryJobManager().getRunningQueries();
Collection<QueryInProgress> finishedQueries = master.getContext().getQueryJobManager().getFinishedQueries();
+
+ int avgQueryTime = 0;
+ int minQueryTime = Integer.MAX_VALUE;
+ int maxQueryTime = 0;
+
+ long totalTime = 0;
+ for(QueryInProgress eachQuery: finishedQueries) {
+ int runTime = (int)(eachQuery.getQueryInfo().getFinishTime() == 0 ? -1 :
+ eachQuery.getQueryInfo().getFinishTime() - eachQuery.getQueryInfo().getStartTime());
+ if(runTime > 0) {
+ totalTime += runTime;
+
+ if(runTime < minQueryTime) {
+ minQueryTime = runTime;
+ }
+
+ if(runTime > maxQueryTime) {
+ maxQueryTime = runTime;
+ }
+ }
+ }
+
+ if(minQueryTime == Integer.MAX_VALUE) {
+ minQueryTime = 0;
+ }
+ if(finishedQueries.size() > 0) {
+ avgQueryTime = (int)(totalTime / (long)finishedQueries.size());
+ }
%>
-<hr/>
-<h3>Running Queries</h3>
-<table>
- <tr></tr><th>QueryId</th><th>Query Master</th><th>Started</th><th>Progress</th><th>Time</th><th>sql</th></tr>
-<%
- SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- for(QueryInProgress eachQuery: runningQueries) {
- long time = System.currentTimeMillis() - eachQuery.getQueryInfo().getStartTime();
-%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+ <h2>Tajo Master: <%=master.getMasterName()%></h2>
+ <hr/>
+ <h3>Master Status</h3>
+ <table border='0'>
+ <tr><td width="100">Version:</td><td><%=master.getVersion()%></td></tr>
+ <tr><td width="100">Started:</td><td><%=new Date(master.getStartTime())%></td></tr>
+ <tr><td width="100">Meta Store:</td><td><%=master.getCatalogServer().getCatalogServerName()%></td></tr>
+ <tr><td width="100">Client Service:</td><td><%=NetUtils.normalizeInetSocketAddress(master.getTajoMasterClientService().getBindAddress())%></td></tr>
+ <tr><td width='100'>MaxHeap: </td><td><%=Runtime.getRuntime().maxMemory()/1024/1024%> MB</td>
+ <tr><td width='100'>TotalHeap: </td><td><%=Runtime.getRuntime().totalMemory()/1024/1024%> MB</td>
+ <tr><td width='100'>FreeHeap: </td><td><%=Runtime.getRuntime().freeMemory()/1024/1024%> MB</td>
+ <tr><td width="100">Configuration:</td><td><a href='conf.jsp'>detail...</a></td></tr>
+ <tr><td width="100">Environment:</td><td><a href='env.jsp'>detail...</a></td></tr>
+ <tr><td width="100">Threads:</td><td><a href='thread.jsp'>thread dump...</a></tr>
+ </table>
+ <hr/>
+
+ <h3>Cluster Summary</h3>
+ <table border='0' width="100%">
<tr>
- <td><%=eachQuery.getQueryId()%></td>
- <td><%=eachQuery.getQueryInfo().getQueryMasterHost()%></td>
- <td><%=df.format(eachQuery.getQueryInfo().getStartTime())%></td>
- <td><%=(int)(eachQuery.getQueryInfo().getProgress() * 100.0f)%>%</td>
- <td><%=(int)(time/1000)%> sec</td>
- <td><%=eachQuery.getQueryInfo().getSql()%></td>
+ <td width="100"><a href='cluster.jsp'>Workers:</a></td><td>Total: <%=workers.size()%> Live: <%=numLiveWorkers%> Dead: <%=numDeadWorkers%></td>
</tr>
-<%
- }
-%>
-</table>
+ <tr>
+ <td width="100">Task Slots</td><td>Total: <%=totalSlot%> Occupied:<%=runningSlot%> Idle: <%=idleSlot%></td>
+ </tr>
+ </table>
+ <hr/>
-<hr/>
-<h3>Finished Queries</h3>
-<table>
- <tr></tr><th>QueryId</th><th>Query Master</th><th>Started</th><th>Finished</th><th>Time</th><th>Status</th><th>sql</th></tr>
- <%
- for(QueryInProgress eachQuery: finishedQueries) {
- long runTime = eachQuery.getQueryInfo().getFinishTime() == 0 ? -1 :
- eachQuery.getQueryInfo().getFinishTime() - eachQuery.getQueryInfo().getStartTime();
- %>
- <tr>
- <td><%=eachQuery.getQueryId()%></td>
- <td><%=eachQuery.getQueryInfo().getQueryMasterHost()%></td>
- <td><%=df.format(eachQuery.getQueryInfo().getStartTime())%></td>
- <td><%=df.format(eachQuery.getQueryInfo().getFinishTime())%></td>
- <td><%=runTime%> ms</td>
- <td><%=eachQuery.getQueryInfo().getQueryState()%></td>
- <td><%=eachQuery.getQueryInfo().getSql()%></td>
- </tr>
- <%
- }
- %>
-</table>
+ <h3>Query Summary</h3>
+ <table border='0'>
+ <tr>
+ <td width="100">Queries:</td><td>Running: <%=runningQueries.size()%> Finished: <%=finishedQueries.size()%></td>
+ </tr>
+ <tr>
+ <td width="100">Running time:</td><td>Average: <%=avgQueryTime/1000%> Min: <%=minQueryTime/1000%> Max: <%=maxQueryTime/1000%> ms</td>
+ </tr>
+ </table>
+</div>
</body>
</html>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp
index 10d8e13..7ca6055 100644
--- a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query.jsp
@@ -1,38 +1,100 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
-<%@ page import="java.net.InetSocketAddress" %>
-<%@ page import="java.net.InetAddress" %>
-<%@ page import="org.apache.hadoop.conf.Configuration" %>
<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
<%@ page import="org.apache.tajo.master.*" %>
-<%@ page import="org.apache.tajo.master.rm.*" %>
-<%@ page import="org.apache.tajo.catalog.*" %>
+<%@ page import="org.apache.tajo.util.*" %>
<%@ page import="org.apache.tajo.master.querymaster.QueryInProgress" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+
+<%
+ TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+
+ List<QueryInProgress> runningQueries =
+ JSPUtil.sortQueryInProgress(master.getContext().getQueryJobManager().getRunningQueries(), true);
+
+ List<QueryInProgress> finishedQueries =
+ JSPUtil.sortQueryInProgress(master.getContext().getQueryJobManager().getFinishedQueries(), true);
+
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ int workerHttpPort = master.getConfig().getInt("tajo.worker.http.port", 28080);
+
+%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
- <link rel="stylesheet" type = "text/css" href = "./style.css" />
+ <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>tajo main</title>
- <%
- TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
- CatalogService catalog = master.getCatalog();
- Map<String, WorkerResource> workers = master.getContext().getResourceManager().getWorkers();
- %>
+ <title>Tajo</title>
</head>
<body>
-<img src='img/tajo_logo.png'/>
-<hr/>
-
-<a href="index.jsp">Main</a>
-<a href="query.jsp">Query</a>
-
-<div><h3>Query</h3></div>
-<div>
- <textarea></textarea>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+ <h2>Tajo Master: <%=master.getMasterName()%></h2>
+ <hr/>
+ <h3>Running Queries</h3>
+<%
+ if(runningQueries.isEmpty()) {
+ out.write("No running queries");
+ } else {
+%>
+ <table width="100%" border="1" class='border_table'>
+ <tr></tr><th>QueryId</th><th>Query Master</th><th>Started</th><th>Progress</th><th>Time</th><th>sql</th></tr>
+ <%
+ for(QueryInProgress eachQuery: runningQueries) {
+ long time = System.currentTimeMillis() - eachQuery.getQueryInfo().getStartTime();
+ String detailView = "http://" + eachQuery.getQueryInfo().getQueryMasterHost() + ":" + workerHttpPort +
+ "/querydetail.jsp?queryId=" + eachQuery.getQueryId();
+ %>
+ <tr>
+ <td><a href='<%=detailView%>'><%=eachQuery.getQueryId()%></a></td>
+ <td><%=eachQuery.getQueryInfo().getQueryMasterHost()%></td>
+ <td><%=df.format(eachQuery.getQueryInfo().getStartTime())%></td>
+ <td><%=(int)(eachQuery.getQueryInfo().getProgress() * 100.0f)%>%</td>
+ <td><%=(int)(time/1000)%> sec</td>
+ <td><%=eachQuery.getQueryInfo().getSql()%></td>
+ </tr>
+ <%
+ }
+ %>
+ </table>
+<%
+ }
+%>
+ <p/>
+ <hr/>
+ <h3>Finished Queries</h3>
+ <%
+ if(finishedQueries.isEmpty()) {
+ out.write("No finished queries");
+ } else {
+ %>
+ <table width="100%" border="1" class='border_table'>
+ <tr></tr><th>QueryId</th><th>Query Master</th><th>Started</th><th>Finished</th><th>Time</th><th>Status</th><th>sql</th></tr>
+ <%
+ for(QueryInProgress eachQuery: finishedQueries) {
+ long runTime = eachQuery.getQueryInfo().getFinishTime() == 0 ? -1 :
+ eachQuery.getQueryInfo().getFinishTime() - eachQuery.getQueryInfo().getStartTime();
+ String detailView = "http://" + eachQuery.getQueryInfo().getQueryMasterHost() + ":" + workerHttpPort +
+ "/querydetail.jsp?queryId=" + eachQuery.getQueryId();
+ %>
+ <tr>
+ <td><a href='<%=detailView%>'><%=eachQuery.getQueryId()%></a></td>
+ <td><%=eachQuery.getQueryInfo().getQueryMasterHost()%></td>
+ <td><%=df.format(eachQuery.getQueryInfo().getStartTime())%></td>
+ <td><%=df.format(eachQuery.getQueryInfo().getFinishTime())%></td>
+ <td><%=runTime%> ms</td>
+ <td><%=eachQuery.getQueryInfo().getQueryState()%></td>
+ <td><%=eachQuery.getQueryInfo().getSql()%></td>
+ </tr>
+ <%
+ }
+ %>
+ </table>
+<%
+ }
+%>
</div>
-<div>Run Query</div>
</body>
-</html>
\ No newline at end of file
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
new file mode 100644
index 0000000..abe955d
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
@@ -0,0 +1,183 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="java.util.*" %>
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+<%@ page import="org.apache.tajo.catalog.*" %>
+<%@ page import="org.apache.tajo.util.FileUtil" %>
+
+<%
+ TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Tajo</title>
+
+<style type="text/css">
+ #progress_bar {
+ border:1px solid #000000;
+ background:#ffffff;
+ width:400px;
+ height:16px;
+ border-radius: 16px;
+ }
+ #progress_status {background:#fbcb46; width:0%; height:16px; border-radius: 10px; }
+
+</style>
+<script src="/static/js/jquery.js" type="text/javascript"></script>
+<script type="text/javascript">
+var progressInterval = 1000;
+var progressTimer = null;
+var queryRunnerId = null;
+
+$(document).ready(function() {
+ $('#btnSubmit').click(function() {
+ runQuery();
+ });
+});
+
+function init() {
+ $("#progress_status").css("width", "0%");
+ $("#progress_text").text("0%");
+ $("#queryStatus").html("");
+ $("#queryResult").html("");
+ queryRunnerId = null;
+}
+function runQuery() {
+ if(progressTimer != null) {
+ alert("Already query running.");
+ return;
+ }
+ init();
+ var query = $("#query").val();
+
+ $.ajax({
+ type: "POST",
+ url: "query_exec",
+ data: { action: "runQuery", query: query}
+ })
+ .done(function(msg) {
+ var resultJson = $.parseJSON(msg);
+ if(resultJson.success == "false") {
+ clearTimer();
+ alert(resultJson.errorMessage);
+ return;
+ }
+ queryRunnerId = resultJson.queryRunnerId;
+ progressTimer = setInterval(function () {
+ $.ajax({
+ type: "GET",
+ url: "query_exec",
+ data: { action: "getQueryProgress", queryRunnerId: queryRunnerId }
+ })
+ .done(function( msg ) {
+ var resultJson = $.parseJSON(msg);
+ if(resultJson.success == "false") {
+ clearTimer();
+ alert(resultJson.errorMessage);
+ $("#queryStatus").html(getQueryStatusHtml(resultJson));
+ return;
+ }
+ var progress = parseInt(resultJson.progress, 0);
+ $("#progress_status").css("width", progress + "%");
+ $("#progress_text").text(progress + "%");
+ $("#queryStatus").html(getQueryStatusHtml(resultJson));
+ if(progress >= 100) {
+ clearTimer();
+ getResult();
+ }
+ });
+ }, progressInterval);
+ });
+}
+
+function clearTimer() {
+ if(progressTimer != null) {
+ clearInterval(progressTimer);
+ }
+ progressTimer = null;
+}
+
+function getQueryStatusHtml(status) {
+ if(status.success == "false") {
+ return "<div style='color:#ff0000; margin-top: 5px'>" + status.errorMessage + "</div>";
+ } else {
+ var statusHtml = "<div style='margin-top: 5px'>Start: " + status.startTime + "</div>";
+ statusHtml += "<div style='margin-top: 5px'>Finish: " + status.finishTime + "</div>";
+ statusHtml += "<div style='margin-top: 5px'> Running time: " + status.runningTime + "</div>";
+ return statusHtml;
+ }
+}
+
+function getResult() {
+ $.ajax({
+ type: "POST",
+ url: "query_exec",
+ data: { action: "getQueryResult", queryRunnerId: queryRunnerId }
+ })
+ .done(function(msg) {
+ var resultJson = $.parseJSON(msg);
+ if(resultJson.success == "false") {
+ alert(resultJson.errorMessage);
+ $("#queryStatus").html(getQueryStatusHtml(resultJson));
+ return;
+ }
+ console.log(resultJson);
+ $("#queryResult").html("");
+ var resultColumns = resultJson.resultColumns;
+ var resultData = resultJson.resultData;
+
+ var resultTable = "<table width='100%' class='border_table'><tr>";
+ for(var i = 0; i < resultColumns.length; i++) {
+ resultTable += "<th>" + resultColumns[i] + "</th>";
+ }
+ resultTable += "</tr>";
+ for(var i = 0; i < resultData.length; i++) {
+ resultTable += "<tr>";
+ for(var j = 0; j < resultData[i].length; j++) {
+ resultTable += "<td>" + resultData[i][j] + "</td>";
+ }
+ resultTable += "</tr>";
+ }
+ resultTable += "</table>";
+ $("#queryResult").html(resultTable);
+ });
+}
+
+</script>
+</head>
+
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+ <h2>Tajo Master: <%=master.getMasterName()%></h2>
+ <hr/>
+ <h3>Query</h3>
+ <textarea id="query" style="width:800px; height:250px; font-family:Tahoma; font-size:12px;"></textarea>
+ <p/>
+ <input id="btnSubmit" type="submit" value="Submit">
+ <hr/>
+ <div>
+ <div style="float:left; width:60px">Progress:</div>
+ <div style='float:left; margin-left:10px'>
+ <div id='progress_bar'>
+ <div id='progress_status'></div>
+ </div>
+ </div>
+ <div style='float:left; margin-left:10px;'>
+ <div id="progress_text" style='font-family:Tahoma; font-size:14px; color:#000000; font-weight:bold'>0%</div>
+ </div>
+ <div style='clear:both'></div>
+ </div>
+ <div id="queryStatus">
+ </div>
+ <hr/>
+ <h3>Query Result</h3>
+ <div id="queryResult"></div>
+</div>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/thread.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/thread.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/thread.jsp
new file mode 100644
index 0000000..7c7fe5a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/thread.jsp
@@ -0,0 +1,26 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+
+<%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
+<%@ page import="org.apache.tajo.master.*" %>
+
+<%
+ TajoMaster master = (TajoMaster) StaticHttpServer.getInstance().getAttribute("tajo.info.server.object");
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Tajo</title>
+</head>
+<body>
+<%@ include file="header.jsp"%>
+<div class='contents'>
+ <h2>Tajo Master: <%=master.getMasterName()%></h2>
+ <hr/>
+ <h3>Thread Dump</h3>
+ <pre><%master.dumpThread(out);%></pre>
+</div>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/85b83940/tajo-core/tajo-core-backend/src/main/resources/webapps/static/img/logo_tajo.gif
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/static/img/logo_tajo.gif b/tajo-core/tajo-core-backend/src/main/resources/webapps/static/img/logo_tajo.gif
new file mode 100644
index 0000000..13674e3
Binary files /dev/null and b/tajo-core/tajo-core-backend/src/main/resources/webapps/static/img/logo_tajo.gif differ