diff --git a/omniadvisor/pom.xml b/omniadvisor/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c2c31b7c59ac0513dfe93fe421bb9afc1f7ad322
--- /dev/null
+++ b/omniadvisor/pom.xml
@@ -0,0 +1,989 @@
+
+
+ 4.0.0
+
+ com.huawei.boostkit
+ omniadvisor-log-analyzer
+ 1.0.0
+
+
+ Kunpeng BoostKit
+
+
+
+ aarch64
+
+ 3.2.0
+ 3.1.1
+ 0.10.0
+
+ 12.16.0
+ 2.2.5
+ 7.5
+ 7.6
+
+ 8.0.11
+
+ 4.1.1
+ 1.3.4
+ 1.19
+ 1.2.83
+ 2.1.6
+ 1.9.2
+ 2.10.0
+ 2.10.5.1
+ 2.10.0
+ 1.1.1
+ 2.4.7
+
+ 1.9.4
+
+ 2.0.7
+ 1.7.30
+ 2.20.0
+
+ 27.0-jre
+ 4.0
+ 1.3.4
+ 9.8.1
+ 4.2.1
+ 3.4.14
+
+ 1.1.3
+ 3.10
+ 3.4.1
+ 3.6
+ 2.6
+ 1.10.0
+ 2.8.0
+
+ 4.11
+ 1.10.19
+
+ 2.12.15
+ 2.12
+ 2.0
+ incremental
+
+ 8
+ 8
+ 3.1.2
+ 3.8.1
+
+
+
+
+
+ org.scala-lang
+ scala-library
+ ${scala.version}
+
+
+ org.scala-lang
+ scala-compiler
+ ${scala.version}
+
+
+ com.jsuereth
+ scala-arm_${scala.compat.version}
+ ${scala.arm.version}
+
+
+ org.scala-lang
+ scala-library
+
+
+
+
+
+
+ org.apache.tez
+ tez-api
+ ${tez.version}
+
+
+ log4j
+ log4j
+
+
+ commons-io
+ commons-io
+
+
+ org.apache.hadoop
+ hadoop-annotations
+
+
+ org.apache.commons
+ commons-compress
+
+
+ com.google.guava
+ guava
+
+
+ com.google.inject
+ guice
+
+
+ com.google.inject.extensions
+ guice-servlet
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ javax.xml.bind
+ jaxb-api
+
+
+ org.codehaus.jettison
+ jettison
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.apache.hadoop
+ hadoop-auth
+
+
+ org.apache.hadoop
+ hadoop-common
+
+
+ org.apache.hadoop
+ hadoop-hdfs-client
+
+
+ org.apache.hadoop
+ hadoop-yarn-api
+
+
+ org.apache.hadoop
+ hadoop-yarn-common
+
+
+ org.apache.hadoop
+ hadoop-yarn-client
+
+
+
+
+ org.apache.tez
+ tez-common
+ ${tez.version}
+
+
+ *
+ *
+
+
+
+
+ org.apache.tez
+ tez-dag
+ ${tez.version}
+
+
+ *
+ *
+
+
+
+
+
+
+ org.apache.hadoop
+ hadoop-auth
+ ${hadoop.version}
+
+
+ log4j
+ log4j
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ org.slf4j
+ slf4j-reload4j
+
+
+ ch.qos.reload4j
+ reload4j
+
+
+ commons-io
+ commons-io
+
+
+ commons-logging
+ commons-logging
+
+
+ com.nimbusds
+ nimbus-jose-jwt
+
+
+ com.google.guava
+ guava
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+ commons-codec
+ commons-codec
+
+
+ net.minidev
+ json-smart
+
+
+
+
+ org.apache.hadoop
+ hadoop-common
+ ${hadoop.version}
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ log4j
+ log4j
+
+
+ org.slf4j
+ slf4j-reload4j
+
+
+ ch.qos.reload4j
+ reload4j
+
+
+ org.apache.avro
+ *
+
+
+ org.apache.commons
+ commons-configuration2
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ org.apache.commons
+ commons-math3
+
+
+ org.apache.commons
+ commons-text
+
+
+ com.google.guava
+ guava
+
+
+ com.google.guava
+ guava
+
+
+ org.codehaus.woodstox
+ stax2-api
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+ commons-logging
+ commons-logging
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ javax.activation
+ activation
+
+
+ javax.ws.rs
+ jsr311-api
+
+
+
+
+ org.apache.hadoop
+ hadoop-hdfs-client
+ ${hadoop.version}
+ runtime
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ log4j
+ log4j
+
+
+
+
+ org.apache.hadoop
+ hadoop-yarn-server-resourcemanager
+ ${hadoop.version}
+
+
+ *
+ *
+
+
+
+
+ org.apache.hadoop
+ hadoop-yarn-api
+ ${hadoop.version}
+
+
+ *
+ *
+
+
+
+
+
+ org.apache.zookeeper
+ zookeeper
+ ${zookeeper.version}
+ runtime
+
+
+ org.slf4j
+ slf4j-api
+
+
+ log4j
+ log4j
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+
+
+
+
+ org.apache.spark
+ spark-core_${scala.compat.version}
+ ${spark.version}
+
+
+ com.typesage.akka
+ *
+
+
+ org.apache.avro
+ *
+
+
+ org.apache.hadoop
+ *
+
+
+ net.razorvine
+ *
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ log4j
+ log4j
+
+
+ org.slf4j
+ slf4j-reload4j
+
+
+ ch.qos.reload4j
+ reload4j
+
+
+ org.apache.commons
+ commons-text
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ commons-net
+ commons-net
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ org.slf4j
+ jcl-over-slf4j
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+ org.slf4j
+ jul-to-slf4j
+
+
+ io.netty
+ netty-all
+
+
+ org.scala-lang
+ scala-library
+
+
+ org.scala-lang
+ scala-reflect
+
+
+ org.scala-lang
+ scala-compiler
+
+
+ org.scala-lang.modules
+ scala-xml_2.12
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+ org.apache.curator
+ curator-recipes
+
+
+
+
+ org.apache.spark
+ spark-kvstore_${scala.compat.version}
+ ${spark.version}
+
+
+
+
+ io.ebean
+ ebean
+ ${ebean.version}
+ runtime
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+ io.ebean
+ ebean-api
+ ${ebean.version}
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+ io.ebean
+ ebean-querybean
+ ${ebean.version}
+
+
+ io.ebean
+ ebean-annotation
+ ${ebean-annotation.version}
+
+
+ io.ebean
+ ebean-ddl-generator
+ ${ebean.version}
+ runtime
+
+
+ io.ebean
+ ebean-migration
+
+
+
+
+ io.ebean
+ ebean-migration
+ ${ebean.version}
+ runtime
+
+
+ io.ebean
+ querybean-generator
+ ${ebean.version}
+ provided
+
+
+ org.codehaus.woodstox
+ stax2-api
+ ${stax2-api.version}
+ runtime
+
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+
+
+
+ com.nimbusds
+ nimbus-jose-jwt
+ ${nimbus-jose-jwt.version}
+
+
+
+
+ com.sun.jersey
+ jersey-client
+ ${jersey-client.version}
+
+
+ org.codehaus.jettison
+ jettison
+ ${jettison.version}
+
+
+ commons-logging
+ commons-logging
+ ${commons-logging.version}
+ runtime
+
+
+ org.apache.commons
+ commons-text
+ ${commons-text.version}
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+ commons-lang
+ commons-lang
+ ${commons-lang.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+ runtime
+
+
+ org.apache.commons
+ commons-configuration2
+ ${commons-configuration2.version}
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ commons-logging
+ commons-logging
+
+
+ org.apache.commons
+ commons-text
+
+
+
+
+
+
+ mysql
+ mysql-connector-java
+ ${mysql.jdbc.version}
+
+
+ com.sun.jersey
+ jersey-core
+
+
+ com.sun.jersey
+ jersey-server
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ com.google.protobuf
+ protobuf-java
+
+
+
+
+
+
+ com.alibaba
+ fastjson
+ ${fastjon.version}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.10.0
+
+
+ org.codehaus.jackson
+ jackson-mapper-asl
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.module
+ jackson-module-scala_${scala.compat.version}
+ ${jackson-module-scala.version}
+
+
+ org.scala-lang
+ scala-library
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson-core.version}
+
+
+
+ net.minidev
+ json-smart
+ ${json-smart.version}
+
+
+ jakarta.ws.rs
+ jakarta.ws.rs-api
+ ${jakarta.version}
+
+
+ io.ebean
+ persistence-api
+ ${ebean-persistence.version}
+
+
+ io.ebean
+ ebean-datasource-api
+ ${ebean-datasource.version}
+
+
+ org.codehaus.jackson
+ jackson-core-asl
+ ${jackson.version}
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ org.slf4j
+ jul-to-slf4j
+ ${slf4j.version}
+ runtime
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${slf4j.version}
+ runtime
+
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ ${log4j.version}
+ runtime
+
+
+ org.apache.logging.log4j
+ log4j-api
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-log4j12.version}
+ runtime
+
+
+ log4j
+ log4j
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+ org.apache.logging.log4j
+ log4j-api
+ ${log4j.version}
+ runtime
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+ runtime
+
+
+
+ org.apache.logging.log4j
+ log4j-1.2-api
+ ${log4j.version}
+ runtime
+
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+ org.mockito
+ mockito-all
+ ${mockito-all.version}
+ test
+
+
+ org.apache.hadoop
+ hadoop-minikdc
+ ${hadoop.version}
+ test
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+
+
+
+
+ boostkit-${project.artifactId}-${project.version}-${dep.os.arch}
+
+
+ src/main/resources
+
+ *
+ */*
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.3.1
+
+
+ copy-resources
+ validate
+
+ copy-resources
+
+
+ ${project.build.directory}/resources
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+
+ net.alchim31.maven
+ scala-maven-plugin
+ 4.7.2
+
+ ${scala.recompile.mode}
+
+
+
+ scala-compile-first
+ process-resources
+
+ add-source
+ compile
+
+
+
+ scala-test-compile
+ process-test-resources
+
+ testCompile
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven.compiler.plugin.version}
+
+ ${maven.compiler.source}
+ ${maven.compiler.target}
+
+
+
+ compile
+
+ compile
+
+
+
+
+
+ io.repaint.maven
+ tiles-maven-plugin
+ 2.24
+ true
+
+
+ io.ebean.tile:enhancement:${ebean.version}
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ ${maven.jar.plugin.version}
+
+
+ false
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.10
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ runtime
+ ${project.build.directory}/lib
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.2.0
+
+ false
+ ${project.build.directory}
+ boostkit-${project.artifactId}-${project.version}-${dep.os.arch}
+
+ src/main/assembly/assembly.xml
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/omniadvisor/src/main/assembly/assembly.xml b/omniadvisor/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d7c6ccb8df39e30417e8b92e1c7daf5fbec61213
--- /dev/null
+++ b/omniadvisor/src/main/assembly/assembly.xml
@@ -0,0 +1,23 @@
+
+ bin
+
+ zip
+
+
+
+ ${basedir}/target
+
+ *.jar
+
+ ./
+
+
+ ${basedir}/target/resources/conf
+ ./conf
+
+
+ ${basedir}/target/lib
+ ./lib
+
+
+
\ No newline at end of file
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/OmniAdvisor.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/OmniAdvisor.java
new file mode 100644
index 0000000000000000000000000000000000000000..315e0208aa561752566f01e5aef1976a5635b77a
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/OmniAdvisor.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor;
+
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.executor.OmniAdvisorRunner;
+import org.apache.commons.lang.time.DateUtils;
+
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public final class OmniAdvisor {
+ private static final int REQUIRED_PARAMS_LENGTH = 4;
+ private static final String[] TIME_PARSE_PATTERNS = {"yyyy-MM-dd HH:mm:ss"};
+
+ private OmniAdvisor() {}
+
+ public static void main(String[] args) {
+ List params = removeEmptyArgs(args);
+
+ if (params.size() != REQUIRED_PARAMS_LENGTH) {
+ throw new OmniAdvisorException("The number of parameters is abnormal. Only four parameters are supported.");
+ }
+
+ Date startDate;
+ Date finishDate;
+ try {
+ startDate = DateUtils.parseDate(params.get(0), TIME_PARSE_PATTERNS);
+ finishDate = DateUtils.parseDate(params.get(1), TIME_PARSE_PATTERNS);
+ } catch (ParseException e) {
+ throw new OmniAdvisorException("Unsupported date format. Only the 'yyyy-MM-dd HH:mm:ss' is supported", e);
+ }
+
+ long startTimeMills = startDate.getTime();
+ long finishedTimeMills = finishDate.getTime();
+
+ if (startTimeMills > finishedTimeMills) {
+ throw new OmniAdvisorException("start time cannot be greater than finish time");
+ }
+
+ OmniAdvisorContext.initContext(params.get(2), params.get(3));
+ OmniAdvisorRunner runner = new OmniAdvisorRunner(startTimeMills, finishedTimeMills);
+ runner.run();
+ }
+
+ private static List removeEmptyArgs(String[] args) {
+ return Arrays.stream(args).filter(arg -> !arg.isEmpty()).collect(Collectors.toList());
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/OmniAdvisorContext.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/OmniAdvisorContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3e52441e4b809a7732ba806f1be107aade20c19
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/OmniAdvisorContext.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor;
+
+import com.google.common.collect.ImmutableList;
+import com.huawei.boostkit.omniadvisor.configuration.DBConfigure;
+import com.huawei.boostkit.omniadvisor.configuration.OmniAdvisorConfigure;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherFactory;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+import io.ebean.Finder;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.apache.hadoop.conf.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Locale;
+
+import static java.lang.String.format;
+
+public final class OmniAdvisorContext {
+ private static final Logger LOG = LoggerFactory.getLogger(OmniAdvisorContext.class);
+ private static final String CONFIG_FILE_NAME = "omniAdvisorLogAnalyzer.properties";
+ private static final List DEFAULT_HADOOP_CONFIG_FILES = ImmutableList.of("hdfs-site.xml", "core-site.xml");
+ private static final String ENCODING = StandardCharsets.UTF_8.displayName(Locale.ENGLISH);
+ private static final Configuration HADOOP_CONF;
+
+ private static OmniAdvisorContext instance = null;
+
+ private final OmniAdvisorConfigure omniAdvisorConfigure;
+ private final FetcherFactory fetcherFactory;
+
+ static {
+ HADOOP_CONF = new Configuration();
+ for (String configFileName : DEFAULT_HADOOP_CONFIG_FILES) {
+ URL configFile = Thread.currentThread().getContextClassLoader().getResource(configFileName);
+ if (configFile != null) {
+ LOG.info("Add resource {} to hadoop config", configFile);
+ HADOOP_CONF.addResource(configFile);
+ }
+ }
+ }
+
+ private Finder finder = new Finder<>(AppResult.class);
+
+ private OmniAdvisorContext() {
+ this(false, null, null);
+ }
+
+ private OmniAdvisorContext(String user, String passwd) {
+ this(true, user, passwd);
+ }
+
+ private OmniAdvisorContext(boolean initDatabase, String user, String passwd) {
+ PropertiesConfiguration configuration = loadConfigure();
+ if (initDatabase) {
+ initDataSource(configuration, user, passwd);
+ }
+ this.omniAdvisorConfigure = loadOmniTuningConfig(configuration);
+ this.fetcherFactory = loadFetcherFactory(configuration);
+ }
+
+ public static void initContext(String user, String passwd) {
+ if (instance == null) {
+ instance = new OmniAdvisorContext(user, passwd);
+ } else {
+ LOG.warn("OmniTuningContext has been instantiated");
+ }
+ }
+
+ // only use for unit test
+ public static void initContext() {
+ if (instance == null) {
+ instance = new OmniAdvisorContext();
+ } else {
+ LOG.warn("OmniTuningContext has been instantiated");
+ }
+ }
+
+ public static OmniAdvisorContext getInstance() {
+ if (instance == null) {
+ throw new OmniAdvisorException("OmniTuningContext has not been instantiated");
+ }
+ return instance;
+ }
+
+ public static Configuration getHadoopConfig() {
+ return HADOOP_CONF;
+ }
+
+ public OmniAdvisorConfigure getOmniAdvisorConfigure() {
+ return omniAdvisorConfigure;
+ }
+
+ public FetcherFactory getFetcherFactory() {
+ return fetcherFactory;
+ }
+
+ public Finder getFinder() {
+ return finder;
+ }
+
+ public void setFinder(Finder finder) {
+ this.finder = finder;
+ }
+
+ private PropertiesConfiguration loadConfigure() {
+ try {
+ Configurations configurations = new Configurations();
+ URL configFileUrl = Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE_NAME);
+ if (configFileUrl == null) {
+ throw new OmniAdvisorException("Config file is missing");
+ }
+ FileBasedConfigurationBuilder.setDefaultEncoding(OmniAdvisorConfigure.class, ENCODING);
+ return configurations.properties(configFileUrl);
+ } catch (ConfigurationException e) {
+ throw new OmniAdvisorException(format("Failed to read config file, %s", e));
+ }
+ }
+
+ private void initDataSource(PropertiesConfiguration configuration, String user, String passwd) {
+ DBConfigure.initDatabase(configuration, user, passwd);
+ }
+
+ private OmniAdvisorConfigure loadOmniTuningConfig(PropertiesConfiguration configuration) {
+ return new OmniAdvisorConfigure(configuration);
+ }
+
+ private FetcherFactory loadFetcherFactory(PropertiesConfiguration configuration) {
+ return new FetcherFactory(configuration);
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/analysis/AnalyticJob.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/analysis/AnalyticJob.java
new file mode 100644
index 0000000000000000000000000000000000000000..95e58e0237aa5345ed5d41e2e469d7124f747581
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/analysis/AnalyticJob.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.analysis;
+
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType;
+
+public interface AnalyticJob {
+ String getApplicationId();
+
+ FetcherType getType();
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/configuration/DBConfigure.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/configuration/DBConfigure.java
new file mode 100644
index 0000000000000000000000000000000000000000..6164c896ca2af66d2294e31059f8109829ed487d
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/configuration/DBConfigure.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.configuration;
+
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+import io.ebean.DatabaseFactory;
+import io.ebean.config.DatabaseConfig;
+import io.ebean.datasource.DataSourceFactory;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import static java.lang.String.format;
+
+public final class DBConfigure {
+ private static final Logger LOG = LoggerFactory.getLogger(DBConfigure.class);
+
+ private static final String DB_DEFAULT_DRIVER = "com.mysql.cj.jdbc.Driver";
+ private static final String DB_DRIVER_KEY = "datasource.db.driver";
+ private static final String DB_URL_KEY = "datasource.db.url";
+ private static final String DB_USERNAME_KEY = "datasource.db.username";
+ private static final String DB_PASSWORD_KEY = "datasource.db.password";
+
+ private DBConfigure() {}
+
+ public static void initDatabase(PropertiesConfiguration configuration, String userName, String passWord) {
+ Properties databaseProperties = new Properties();
+ databaseProperties.put(DB_DRIVER_KEY, configuration.getString(DB_DRIVER_KEY, DB_DEFAULT_DRIVER));
+ databaseProperties.put(DB_URL_KEY, configuration.getString(DB_URL_KEY));
+ databaseProperties.put(DB_USERNAME_KEY, userName);
+ databaseProperties.put(DB_PASSWORD_KEY, passWord);
+
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.loadFromProperties(databaseProperties);
+
+ dbConfig.setDataSource(DataSourceFactory.create(dbConfig.getName(), dbConfig.getDataSourceConfig()));
+
+ checkInit(dbConfig);
+
+ DatabaseFactory.create(dbConfig);
+ }
+
+ public static void checkInit(DatabaseConfig dbConfig) {
+ boolean isInit;
+ try (Connection conn = dbConfig.getDataSource().getConnection();
+ ResultSet rs = conn.getMetaData().getTables(conn.getCatalog(), null, AppResult.RESULT_TABLE_NAME, null)) {
+ isInit = rs.next();
+ } catch (SQLException e) {
+ throw new OmniAdvisorException(format("Failed to connect to dataSource, %s", e));
+ }
+
+ if (!isInit) {
+ LOG.info("Analyze result table is not exist, creating it");
+ dbConfig.setDdlGenerate(true);
+ dbConfig.setDdlRun(true);
+ }
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/configuration/OmniAdvisorConfigure.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/configuration/OmniAdvisorConfigure.java
new file mode 100644
index 0000000000000000000000000000000000000000..cac34518aab3f23d1a2c1798aedfea720fcdee86
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/configuration/OmniAdvisorConfigure.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.configuration;
+
+import org.apache.commons.configuration2.PropertiesConfiguration;
+
+public class OmniAdvisorConfigure {
+ private static final int DEFAULT_THREAD_COUNT = 3;
+ private static final String THREAD_COUNT_CONF_KEY = "log.analyzer.thread.count";
+ private static final String KERBEROS_PRINCIPAL_KEY = "kerberos.principal";
+ private static final String KERBEROS_KEYTAB_FILE_KEY = "kerberos.keytab.file";
+
+ private final int threadCount;
+ private String kerberosPrincipal;
+ private String kerberosKeytabFile;
+
+ public OmniAdvisorConfigure(PropertiesConfiguration configuration) {
+ this.threadCount = configuration.getInt(THREAD_COUNT_CONF_KEY, DEFAULT_THREAD_COUNT);
+ this.kerberosPrincipal = configuration.getString(KERBEROS_PRINCIPAL_KEY, null);
+ this.kerberosKeytabFile = configuration.getString(KERBEROS_KEYTAB_FILE_KEY, null);
+ }
+
+ public int getThreadCount() {
+ return threadCount;
+ }
+
+ public String getKerberosPrincipal() {
+ return kerberosPrincipal;
+ }
+
+ public String getKerberosKeytabFile() {
+ return kerberosKeytabFile;
+ }
+
+ public void setKerberosPrincipal(String kerberosPrincipal) {
+ this.kerberosPrincipal = kerberosPrincipal;
+ }
+
+ public void setKerberosKeytabFile(String kerberosKeytabFile) {
+ this.kerberosKeytabFile = kerberosKeytabFile;
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/exception/OmniAdvisorException.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/exception/OmniAdvisorException.java
new file mode 100644
index 0000000000000000000000000000000000000000..fffa3c10a25df77a89a13b38a68750dbe8c081b7
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/exception/OmniAdvisorException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.exception;
+
+public class OmniAdvisorException extends RuntimeException {
+ public OmniAdvisorException(String message) {
+ super(message);
+ }
+
+ public OmniAdvisorException(Throwable throwable) {
+ super(throwable);
+ }
+
+ public OmniAdvisorException(String message, Throwable throwable) {
+ super(message, throwable);
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/AnalysisAction.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/AnalysisAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff0876db89fad53011fdf6fbd6028fa89a3d1b98
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/AnalysisAction.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.executor;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.configuration.OmniAdvisorConfigure;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.fetcher.Fetcher;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherFactory;
+import com.huawei.boostkit.omniadvisor.security.HadoopSecurity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+public class AnalysisAction implements PrivilegedAction {
+ private static final Logger LOG = LoggerFactory.getLogger(AnalysisAction.class);
+
+ private static final int WAIT_INTERVAL = 1000;
+
+ private final HadoopSecurity hadoopSecurity;
+ private final long startTimeMills;
+ private final long finishTimeMills;
+
+ private final Object appsLock;
+
+ public AnalysisAction(HadoopSecurity hadoopSecurity,long startTimeMills, long finishTImeMills) {
+ this.appsLock = new Object();
+ this.hadoopSecurity = hadoopSecurity;
+ this.startTimeMills = startTimeMills;
+ this.finishTimeMills = finishTImeMills;
+ }
+
+ @Override
+ public Void run() {
+ OmniAdvisorContext context = OmniAdvisorContext.getInstance();
+
+ FetcherFactory fetcherFactory = context.getFetcherFactory();
+ OmniAdvisorConfigure omniAdvisorConfigure = context.getOmniAdvisorConfigure();
+
+ try {
+ hadoopSecurity.checkLogin();
+ } catch (IOException e) {
+ LOG.error("Error with hadoop kerberos login", e);
+ throw new OmniAdvisorException(e);
+ }
+
+ LOG.info("Fetching analytic job list");
+
+ List analyticJobs = new ArrayList<>();
+ for (Fetcher fetcher : fetcherFactory.getAllFetchers()) {
+ LOG.info("Fetching jobs from {}", fetcher.getType().getName());
+ List fetchedJobs = fetcher.fetchAnalyticJobs(startTimeMills, finishTimeMills);
+ LOG.info("Fetched {} jobs from {}", fetchedJobs.size(), fetcher.getType().getName());
+ analyticJobs.addAll(fetchedJobs);
+ }
+
+ LOG.info("Fetchers get total {} Jobs", analyticJobs.size());
+
+ if (!analyticJobs.isEmpty()) {
+ ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("omni-tuning-thread-%d").build();
+ int executorNum = Integer.min(analyticJobs.size(), omniAdvisorConfigure.getThreadCount());
+ int queueSize = Integer.max(analyticJobs.size(), executorNum);
+ ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(executorNum, executorNum, 0L,
+ TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(queueSize), factory);
+ for (AnalyticJob analyticJob : analyticJobs) {
+ synchronized (appsLock) {
+ threadPoolExecutor.submit(new ExecutorJob(analyticJob, fetcherFactory, appsLock));
+ }
+ }
+ Timer timer = new Timer();
+ timer.schedule(new ThreadPoolListener(timer, threadPoolExecutor), WAIT_INTERVAL, WAIT_INTERVAL);
+ }
+ return null;
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/ExecutorJob.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/ExecutorJob.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d8203e5b55d634509cf35363f2f9c85ddbc23bb
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/ExecutorJob.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.executor;
+
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.fetcher.Fetcher;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherFactory;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+import io.ebean.DB;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+import static com.huawei.boostkit.omniadvisor.utils.MathUtils.SECOND_IN_MS;
+
+class ExecutorJob implements Runnable {
+ private static final Logger LOG = LoggerFactory.getLogger(ExecutorJob.class);
+
+ private final AnalyticJob analyticJob;
+ private final FetcherFactory fetcherFactory;
+ private final Object appsLock;
+
+ public ExecutorJob(AnalyticJob analyticJob, FetcherFactory fetcherFactory, Object appsLock) {
+ this.analyticJob = analyticJob;
+ this.fetcherFactory = fetcherFactory;
+ this.appsLock = appsLock;
+ }
+
+ @Override
+ public void run() {
+ FetcherType type = analyticJob.getType();
+ String appId = analyticJob.getApplicationId();
+
+ LOG.info("Analyzing {} {}", type.getName(), appId);
+
+ long analysisStartTime = System.currentTimeMillis();
+
+ Fetcher fetcher = fetcherFactory.getFetcher(type);
+
+ final Optional result = fetcher.analysis(analyticJob);
+ if (result.isPresent()) {
+ synchronized (appsLock) {
+ AppResult analyzeResult = result.get();
+ LOG.info("Analysis get result {}", appId);
+ try {
+ DB.execute(analyzeResult::save);
+ } catch (Throwable e) {
+ LOG.error("Error in saving analyze result, {}", e.getMessage());
+ }
+ }
+ } else {
+ LOG.info("Analysis get empty result {}", appId);
+ }
+
+ long analysisTimeMills = System.currentTimeMillis() - analysisStartTime;
+
+ LOG.info("Finish analysis {} {} using {}s", type, appId, analysisTimeMills / SECOND_IN_MS);
+ }
+}
\ No newline at end of file
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/OmniAdvisorRunner.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/OmniAdvisorRunner.java
new file mode 100644
index 0000000000000000000000000000000000000000..680d4cf1ba234acca09939508b6c8a72b80dbb51
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/OmniAdvisorRunner.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.executor;
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.security.HadoopSecurity;
+import org.apache.hadoop.conf.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class OmniAdvisorRunner implements Runnable {
+ private static final Logger LOG = LoggerFactory.getLogger(OmniAdvisorRunner.class);
+
+ private final long startTimeMills;
+ private final long finishTimeMills;
+
+ public OmniAdvisorRunner(long startTimeMills, long finishTimeMills) {
+ this.startTimeMills = startTimeMills;
+ this.finishTimeMills = finishTimeMills;
+ }
+
+ @Override
+ public void run() {
+ LOG.info("OmniAdvisor has started");
+ try {
+ Configuration hadoopConf = OmniAdvisorContext.getHadoopConfig();
+ HadoopSecurity hadoopSecurity = new HadoopSecurity(hadoopConf);
+ hadoopSecurity.doAs(new AnalysisAction(hadoopSecurity, startTimeMills, finishTimeMills));
+ } catch (IOException e) {
+ LOG.error("failed to analyze jobs", e);
+ throw new OmniAdvisorException(e);
+ }
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/ThreadPoolListener.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/ThreadPoolListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ec2bf2a9321c69d0eb4d60cb91dfa77d722de19
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/executor/ThreadPoolListener.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.executor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ThreadPoolExecutor;
+
+public class ThreadPoolListener extends TimerTask {
+ private static final Logger LOG = LoggerFactory.getLogger(ThreadPoolListener.class);
+
+ private final Timer timer;
+ private final ThreadPoolExecutor executor;
+
+ public ThreadPoolListener(Timer timer, ThreadPoolExecutor executor) {
+ this.timer = timer;
+ this.executor = executor;
+ }
+
+ @Override
+ public void run() {
+ LOG.info("Executor taskCount {}, active count {}, complete count {}, {} left",
+ executor.getTaskCount(), executor.getActiveCount(), executor.getCompletedTaskCount(),
+ executor.getTaskCount() - executor.getCompletedTaskCount());
+ if (executor.getActiveCount() == 0) {
+ executor.shutdown();
+ timer.cancel();
+ }
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/Fetcher.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/Fetcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..89dfd89b87339ebc3fec1d56176aa7b8c3312a29
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/Fetcher.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.huawei.boostkit.omniadvisor.fetcher;
+
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface Fetcher {
+ boolean isEnable();
+
+ FetcherType getType();
+
+ List fetchAnalyticJobs(long startTimeMills, long finishedTimeMills);
+
+ Optional analysis(AnalyticJob job);
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/FetcherFactory.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/FetcherFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..9358b6fd15c355dbb6dcd104976e354b7303a4b4
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/FetcherFactory.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.fetcher;
+
+import com.google.common.collect.ImmutableList;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.spark.SparkFetcher;
+import com.huawei.boostkit.omniadvisor.tez.TezFetcher;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.lang.String.format;
+
+public class FetcherFactory {
+ private static final Logger LOG = LoggerFactory.getLogger(FetcherFactory.class);
+
+ private final Map enabledFetchers;
+
+ public FetcherFactory(PropertiesConfiguration configuration) {
+ Map fetchers = new HashMap<>();
+
+ // init TEZ fetcher
+ Fetcher tezFetcher = new TezFetcher(configuration);
+ if (tezFetcher.isEnable()) {
+ LOG.info("TEZ Fetcher is enabled.");
+ fetchers.put(FetcherType.TEZ, tezFetcher);
+ }
+
+ // init SPARK fetcher
+ Fetcher sparkFetcher = new SparkFetcher(configuration);
+ if (sparkFetcher.isEnable()) {
+ LOG.info("Spark Fetcher is enabled.");
+ fetchers.put(FetcherType.SPARK, sparkFetcher);
+ }
+
+ this.enabledFetchers = fetchers;
+ }
+
+ public Fetcher getFetcher(FetcherType type) {
+ if (enabledFetchers.containsKey(type)) {
+ return enabledFetchers.get(type);
+ } else {
+ throw new OmniAdvisorException(format("Fetcher [%s] is disabled", type.getName()));
+ }
+ }
+
+ public List getAllFetchers() {
+ return ImmutableList.copyOf(enabledFetchers.values());
+ }
+
+ public void addFetcher(FetcherType type, Fetcher fetcher) {
+ enabledFetchers.put(type, fetcher);
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/FetcherType.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/FetcherType.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4a78e562b153853a2ba7dcd847dd7d31e246c4a
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/fetcher/FetcherType.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.fetcher;
+
+public enum FetcherType {
+ SPARK("SPARK"), TEZ("TEZ");
+
+ private final String name;
+
+ FetcherType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/models/AppResult.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/models/AppResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c91ff2897deac8292fddd72ef677391ed0ca80e
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/models/AppResult.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.models;
+
+import com.huawei.boostkit.omniadvisor.utils.MathUtils;
+import io.ebean.Model;
+import io.ebean.annotation.Index;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = AppResult.RESULT_TABLE_NAME)
+@Index(name = "yarn_app_result_i1", columnNames = {"application_id"})
+@Index(name = "yarn_app_result_i2", columnNames = {"application_name"})
+public class AppResult extends Model {
+ private static final long serialVersionUID = 1L;
+
+ public static final long FAILED_JOB_DURATION = MathUtils.DAY_IN_MS;
+ public static final String RESULT_TABLE_NAME = "yarn_app_result";
+ public static final int FAILED_STATUS = 0;
+ public static final int SUCCEEDED_STATUS = 1;
+ private static final int APPLICATION_ID_LIMIT = 50;
+ private static final int APPLICATION_NAME_LIMIT = 100;
+ private static final int APPLICATION_WORKLOAD_LIMIT = 50;
+ private static final int JOB_TYPE_LIMIT = 50;
+
+ @Id
+ @Column(length = APPLICATION_ID_LIMIT, unique = true, nullable = false)
+ public String applicationId;
+
+ @Column(length = APPLICATION_NAME_LIMIT, nullable = false)
+ public String applicationName;
+
+ @Column(length = APPLICATION_WORKLOAD_LIMIT)
+ public String applicationWorkload;
+
+ @Column()
+ public long startTime;
+
+ @Column()
+ public long finishTime;
+
+ @Column()
+ public long durationTime;
+
+ @Column(length = JOB_TYPE_LIMIT)
+ public String jobType;
+
+ @Column(columnDefinition = "TEXT CHARACTER SET utf8mb4")
+ public String parameters;
+
+ @Column()
+ public int executionStatus;
+
+ @Column(columnDefinition = "TEXT CHARACTER SET utf8mb4")
+ public String query;
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/security/HadoopSecurity.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/security/HadoopSecurity.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a6b45ed375809e9d5177b2459ace359ac4c9e74
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/security/HadoopSecurity.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.security;
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import com.huawei.boostkit.omniadvisor.configuration.OmniAdvisorConfigure;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.PrivilegedAction;
+
+public final class HadoopSecurity {
+ private static final Logger LOG = LoggerFactory.getLogger(HadoopSecurity.class);
+
+ private String keytabFile;
+ private String principal;
+ private UserGroupInformation loginUser;
+
+ public HadoopSecurity(Configuration hadoopConf) throws IOException {
+ OmniAdvisorConfigure configure = OmniAdvisorContext.getInstance().getOmniAdvisorConfigure();
+ UserGroupInformation.setConfiguration(hadoopConf);
+ boolean securityEnabled = UserGroupInformation.isSecurityEnabled();
+ if (securityEnabled) {
+ LOG.info("This cluster is Kerberos enabled.");
+ boolean login = true;
+
+ principal = configure.getKerberosPrincipal();
+ if (principal == null) {
+ LOG.error("Keytab user not set. Please set keytab_user in the configuration file");
+ login = false;
+ }
+
+ keytabFile = configure.getKerberosKeytabFile();
+ if (keytabFile == null) {
+ LOG.error("Keytab location not set. Please set keytab_location in the configuration file");
+ login = false;
+ }
+
+ if (keytabFile != null && !new File(keytabFile).exists()) {
+ LOG.error("The keytab file at location [" + keytabFile + "] does not exist.");
+ login = false;
+ }
+
+ if (!login) {
+ throw new OmniAdvisorException("Cannot login. This cluster is security enabled.");
+ }
+ }
+
+ this.loginUser = getLoginUser();
+ }
+
+ public UserGroupInformation getUGI() throws IOException {
+ checkLogin();
+ return loginUser;
+ }
+
+ public UserGroupInformation getLoginUser() throws IOException {
+ LOG.info("No login user. Creating login user");
+ LOG.info("Logging with " + principal + " and " + keytabFile);
+ UserGroupInformation.loginUserFromKeytab(principal, keytabFile);
+ UserGroupInformation user = UserGroupInformation.getLoginUser();
+ LOG.info("Logged in with user " + user);
+ if (UserGroupInformation.isLoginKeytabBased()) {
+ LOG.info("Login is keytab based");
+ } else {
+ LOG.info("Login is not keytab based");
+ }
+ return user;
+ }
+
+ public void checkLogin() throws IOException {
+ if (loginUser == null) {
+ loginUser = getLoginUser();
+ } else {
+ loginUser.checkTGTAndReloginFromKeytab();
+ }
+ }
+
+ public void doAs(PrivilegedAction action) throws IOException {
+ UserGroupInformation ugi = getUGI();
+ if (ugi != null) {
+ ugi.doAs(action);
+ }
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/TezFetcher.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/TezFetcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f165dba51672121c1755d6f1d4ef30757fae83b
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/TezFetcher.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.fetcher.Fetcher;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+import com.huawei.boostkit.omniadvisor.tez.data.TezAnalyticJob;
+import com.huawei.boostkit.omniadvisor.tez.data.TezDagIdData;
+import com.huawei.boostkit.omniadvisor.tez.utils.TezJsonUtils;
+import com.huawei.boostkit.omniadvisor.tez.utils.TezUrlFactory;
+import com.huawei.boostkit.omniadvisor.tez.utils.TimelineClient;
+import com.huawei.boostkit.omniadvisor.utils.Utils;
+import com.sun.jersey.api.client.ClientHandlerException;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.apache.hadoop.yarn.api.records.YarnApplicationState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import static com.huawei.boostkit.omniadvisor.utils.Utils.loadParamsFromConf;
+
+public class TezFetcher implements Fetcher {
+ private static final Logger LOG = LoggerFactory.getLogger(TezFetcher.class);
+
+ private static final String TEZ_ENABLE_KEY = "tez.enable";
+ private static final String TEZ_WORKLOAD_KEY = "tez.workload";
+ private static final String TEZ_TIMELINE_URL_KEY = "tez.timeline.url";
+ private static final String TEZ_TIMELINE_TIMEOUT_KEY = "tez.timeline.timeout.ms";
+ private static final String DEFAULT_WORKLOAD = "default";
+ private static final String DEFAULT_TIMELINE_URL = "http://localhost:8188";
+ private static final String HTTPS_PREFIX = "https://";
+ private static final int DEFAULT_CONNECTION_TIMEOUT_MS = 6000;
+ private static final String TEZ_PARAMS_CONF_FILE = "TezParams";
+
+ private final boolean enable;
+ private String workload;
+ private TezJsonUtils tezJsonUtils;
+
+ public TezFetcher(PropertiesConfiguration configuration) {
+ this.enable = configuration.getBoolean(TEZ_ENABLE_KEY, false);
+ if (enable) {
+ String timelineUrl = configuration.getString(TEZ_TIMELINE_URL_KEY, DEFAULT_TIMELINE_URL);
+ TezUrlFactory tezUrlFactory = new TezUrlFactory(timelineUrl);
+ this.workload = configuration.getString(TEZ_WORKLOAD_KEY, DEFAULT_WORKLOAD);
+ int timeout = configuration.getInt(TEZ_TIMELINE_TIMEOUT_KEY, DEFAULT_CONNECTION_TIMEOUT_MS);
+ boolean useHttps = timelineUrl.startsWith(HTTPS_PREFIX);
+ this.tezJsonUtils = new TezJsonUtils(tezUrlFactory, useHttps, timeout);
+ }
+ }
+
+ @Override
+ public boolean isEnable() {
+ if (enable) {
+ try {
+ tezJsonUtils.verifyTimeLineServer();
+ return true;
+ } catch (IOException e) {
+ LOG.error("Connect to timeline server failed {}, TEZ fetcher is disabled", e.getMessage());
+ return false;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public FetcherType getType() {
+ return FetcherType.TEZ;
+ }
+
+ @Override
+ public List fetchAnalyticJobs(long startTimeMills, long finishedTimeMills) {
+ try {
+ return tezJsonUtils.getApplicationJobs(startTimeMills, finishedTimeMills);
+ } catch (IOException | AuthenticationException | ClientHandlerException e) {
+ LOG.error("Fetch applications from timeline server failed.", e);
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public Optional analysis(AnalyticJob job) {
+ if (!(job instanceof TezAnalyticJob)) {
+ throw new OmniAdvisorException("TezFetcher only support TezAnalyticJob");
+ }
+ TezAnalyticJob tezJob = (TezAnalyticJob) job;
+
+ List dagIds;
+ try {
+ dagIds = tezJsonUtils.getDAGIds(job.getApplicationId());
+ } catch (IOException | ClientHandlerException e) {
+ LOG.error("Get dagIds from timeline server failed.", e);
+ return Optional.empty();
+ }
+
+ if (dagIds.isEmpty()) {
+ LOG.info("There is no dag in application {}, skip it", job.getApplicationId());
+ return Optional.empty();
+ }
+
+ // If there is more than one dag in application, only analyze the last one
+ TezDagIdData tezDagId = dagIds.stream().max(TezDagIdData::compareTo).get();
+
+ return extractAppResult(tezJob, tezDagId);
+ }
+
+ private Optional extractAppResult(TezAnalyticJob tezJob, TezDagIdData dagIdData) {
+ LOG.info("Analyzing dag {}", dagIdData.getDagId());
+ AppResult appResult = new AppResult();
+ Map jobConf;
+ try {
+ jobConf = tezJsonUtils.getConfigure(tezJob.getApplicationId());
+ appResult.parameters = Utils.parseMapToJsonString(loadParamsFromConf(TEZ_PARAMS_CONF_FILE, jobConf));
+ appResult.query = tezJsonUtils.getQueryString(dagIdData.getDagId());
+ } catch (IOException e) {
+ LOG.error("Analyze job failed. ", e);
+ return Optional.empty();
+ }
+
+ appResult.applicationId = tezJob.getApplicationId();
+ appResult.applicationName = tezJob.getApplicationName();
+ appResult.applicationWorkload = workload;
+ appResult.jobType = tezJob.getType().getName();
+
+ if (dagIdData.isComplete()) {
+ appResult.startTime = dagIdData.getStartTime();
+ appResult.finishTime = dagIdData.getEndTime();
+ appResult.executionStatus = dagIdData.isSuccess() ? AppResult.SUCCEEDED_STATUS : AppResult.FAILED_STATUS;
+ appResult.durationTime = dagIdData.isSuccess() ? dagIdData.getDuration() : AppResult.FAILED_JOB_DURATION;
+ } else {
+ appResult.startTime = tezJob.getStartTimeMills();
+ appResult.finishTime = tezJob.getFinishTimeMills();
+ if (tezJob.getState() == YarnApplicationState.KILLED) {
+ LOG.info("Application {} is killed, regarded as a failed task", tezJob.getApplicationId());
+ appResult.executionStatus = AppResult.FAILED_STATUS;
+ appResult.durationTime = AppResult.FAILED_JOB_DURATION;
+ } else {
+ LOG.info("Application {} using input time", tezJob.getApplicationId());
+ appResult.executionStatus = AppResult.SUCCEEDED_STATUS;
+ appResult.durationTime = appResult.finishTime - appResult.startTime;
+ }
+ }
+
+ return Optional.of(appResult);
+ }
+
+ @VisibleForTesting
+ protected void setTezJsonUtils(TezJsonUtils jsonUtils) {
+ this.tezJsonUtils = jsonUtils;
+ }
+
+ @VisibleForTesting
+ protected void setTimelineClient(TimelineClient timelineClient) {
+ this.tezJsonUtils.setTimelineClient(timelineClient);
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/data/TezAnalyticJob.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/data/TezAnalyticJob.java
new file mode 100644
index 0000000000000000000000000000000000000000..6fcfa9c705d16237d42ff9f0a283913d3146f04e
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/data/TezAnalyticJob.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.data;
+
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType;
+import org.apache.hadoop.yarn.api.records.YarnApplicationState;
+
+public class TezAnalyticJob implements AnalyticJob {
+ private final String applicationId;
+ private final String applicationName;
+ private final long startTimeMills;
+ private final long finishTimeMills;
+ private final YarnApplicationState state;
+
+ public TezAnalyticJob(String appId, String appName, long startTime, long finishTime, YarnApplicationState state) {
+ this.applicationId = appId;
+ this.applicationName = appName;
+ this.startTimeMills = startTime;
+ this.finishTimeMills = finishTime;
+ this.state = state;
+ }
+
+ @Override
+ public String getApplicationId() {
+ return applicationId;
+ }
+
+ @Override
+ public FetcherType getType() {
+ return FetcherType.TEZ;
+ }
+
+ public String getApplicationName() {
+ return applicationName;
+ }
+
+ public long getStartTimeMills() {
+ return startTimeMills;
+ }
+
+ public long getFinishTimeMills() {
+ return finishTimeMills;
+ }
+
+ public YarnApplicationState getState() {
+ return state;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (!(other instanceof TezAnalyticJob)) {
+ return false;
+ }
+
+ TezAnalyticJob otherJob = (TezAnalyticJob) other;
+ return this.applicationId.equals(otherJob.applicationId)
+ && this.applicationName.equals(otherJob.applicationName)
+ && this.startTimeMills == otherJob.startTimeMills
+ && this.finishTimeMills == otherJob.finishTimeMills;
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/data/TezDagIdData.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/data/TezDagIdData.java
new file mode 100644
index 0000000000000000000000000000000000000000..a47a0f36c97e522cea7e30613233bc4d286bd393
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/data/TezDagIdData.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.data;
+
+import org.apache.tez.dag.app.dag.DAGState;
+
+public class TezDagIdData implements Comparable {
+ private final String dagId;
+ private final long startTime;
+ private final long endTime;
+ private final long duration;
+ private final DAGState status;
+
+ public TezDagIdData(String dagId, long startTime, long endTime, long duration, DAGState status) {
+ this.dagId = dagId;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ this.duration = duration;
+ this.status = status;
+ }
+
+ public String getDagId() {
+ return dagId;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public long getEndTime() {
+ return endTime;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public boolean isComplete() {
+ return (status == DAGState.SUCCEEDED ||
+ status == DAGState.FAILED ||
+ status == DAGState.KILLED ||
+ status == DAGState.ERROR ||
+ status == DAGState.TERMINATING);
+ }
+
+ public boolean isSuccess() {
+ return status == DAGState.SUCCEEDED;
+ }
+
+ @Override
+ public int compareTo(TezDagIdData other) {
+ return Long.compare(this.startTime, other.startTime);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof TezDagIdData)) {
+ return false;
+ }
+ return this.dagId.equals(((TezDagIdData) other).dagId);
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TezJsonUtils.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TezJsonUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..43c02a8b7e96d6a4523a0d4e2f867dded63430f7
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TezJsonUtils.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.tez.data.TezAnalyticJob;
+import com.huawei.boostkit.omniadvisor.tez.data.TezDagIdData;
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.apache.hadoop.yarn.api.records.YarnApplicationState;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWSConsts;
+import org.apache.tez.common.ATSConstants;
+import org.apache.tez.dag.app.dag.DAGState;
+import org.apache.tez.dag.history.utils.DAGUtils;
+import org.codehaus.jackson.JsonNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class TezJsonUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(TezJsonUtils.class);
+ private static final String HIVE_APP_NAME_PREFIX = "HIVE-";
+
+ private final TezUrlFactory tezUrlFactory;
+ private TimelineClient timelineClient;
+
+ public TezJsonUtils(TezUrlFactory tezUrlFactory, boolean useHttps, int timeout) {
+ this.tezUrlFactory = tezUrlFactory;
+ this.timelineClient = new TimelineClient(OmniAdvisorContext.getHadoopConfig(), useHttps, timeout);
+ }
+
+ public void verifyTimeLineServer() throws IOException {
+ URL timeLineUrl = tezUrlFactory.getRootURL();
+ URLConnection connection = timeLineUrl.openConnection();
+ connection.connect();
+ }
+
+ public List getApplicationJobs(long startedTime, long finishedTime)
+ throws IOException, AuthenticationException {
+ URL historyUrl = tezUrlFactory.getApplicationHistoryURL(startedTime, finishedTime);
+ LOG.info("calling REST API at {} to get applications", historyUrl.toString());
+ JsonNode rootNode = timelineClient.readJsonNode(historyUrl);
+ JsonNode apps = rootNode.path("app");
+ List analyticJobs = new ArrayList<>();
+ for (JsonNode app : apps) {
+ String appId = app.get(RMWSConsts.APP_ID).getTextValue();
+ if (OmniAdvisorContext.getInstance().getFinder().byId(appId) == null) {
+ String name = getApplicationName(app.get("name").getTextValue());
+ String state = app.get("appState").getTextValue();
+ TezAnalyticJob tezJob =
+ new TezAnalyticJob(appId, name, startedTime, finishedTime, YarnApplicationState.valueOf(state));
+ analyticJobs.add(tezJob);
+ }
+ }
+ return analyticJobs;
+ }
+
+ private String getApplicationName(String name) {
+ if (name.startsWith(HIVE_APP_NAME_PREFIX)) {
+ return name.substring(HIVE_APP_NAME_PREFIX.length());
+ } else {
+ return name;
+ }
+ }
+
+ public List getDAGIds(String applicationId) throws MalformedURLException {
+ URL dagIdUrl = tezUrlFactory.getDagIdURL(applicationId);
+ LOG.info("Get DAG ids from REST API at {}", dagIdUrl.toString());
+ JsonNode rootNode = timelineClient.readJsonNode(dagIdUrl);
+ List dagIds = new ArrayList<>();
+
+ for (JsonNode entity : rootNode.get(ATSConstants.ENTITIES)) {
+ String dagId = entity.get(ATSConstants.ENTITY).getTextValue();
+ long startTime = entity.get(ATSConstants.OTHER_INFO).path(ATSConstants.START_TIME).getLongValue();
+ long endTime = entity.get(ATSConstants.OTHER_INFO).path(ATSConstants.FINISH_TIME).getLongValue();
+ long duration = entity.get(ATSConstants.OTHER_INFO).path(ATSConstants.TIME_TAKEN).getLongValue();
+ DAGState status =
+ DAGState.valueOf(entity.path(ATSConstants.OTHER_INFO).path(ATSConstants.STATUS).getTextValue());
+ dagIds.add(new TezDagIdData(dagId, startTime, endTime, duration, status));
+ }
+ LOG.info("Get {} dags for application {}", dagIds.size(), applicationId);
+ return dagIds;
+ }
+
+ public Map getConfigure(String applicationId) throws MalformedURLException {
+ URL applicationURL = tezUrlFactory.getApplicationURL(applicationId);
+ LOG.info("Get configuration by calling REST API {}", applicationURL);
+ JsonNode rootNode = timelineClient.readJsonNode(applicationURL);
+ JsonNode config = rootNode.path(ATSConstants.OTHER_INFO).path(ATSConstants.CONFIG);
+ Iterator fieldNames = config.getFieldNames();
+ Map params = new HashMap<>();
+ while (fieldNames.hasNext()) {
+ String key = fieldNames.next();
+ String value = config.get(key).getTextValue();
+ params.put(key, value);
+ }
+ return params;
+ }
+
+ public String getQueryString(String dagId) throws MalformedURLException {
+ URL dagExtraInfoURL = tezUrlFactory.getDagExtraInfoURL(dagId);
+ LOG.info("Get query string by calling REST API {}", dagExtraInfoURL);
+ JsonNode rootNode = timelineClient.readJsonNode(dagExtraInfoURL);
+ return rootNode.path(ATSConstants.OTHER_INFO)
+ .path(ATSConstants.DAG_PLAN)
+ .path(DAGUtils.DAG_CONTEXT_KEY)
+ .get(ATSConstants.DESCRIPTION)
+ .getTextValue();
+ }
+
+ public void setTimelineClient(TimelineClient timelineClient) {
+ this.timelineClient = timelineClient;
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TezUrlFactory.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TezUrlFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..7980c5720e21ccb9ad5a2ee5a3f9753a29863f76
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TezUrlFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWSConsts;
+import org.apache.tez.common.ATSConstants;
+import org.apache.tez.dag.history.logging.EntityTypes;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import static java.lang.String.format;
+
+public class TezUrlFactory {
+ private static final String APPLICATION_TYPE = "TEZ";
+ private static final String TEZ_APPLICATION_PREFIX = "tez_";
+
+ private static final String APPLICATION_HISTORY_URL = "%s/ws/v1/applicationhistory/apps?%s=%s&%s=%s&%s=%s";
+ private static final String TIMELINE_BASE_URL = "%s" + ATSConstants.RESOURCE_URI_BASE;
+ private static final String TIMELINE_ENTITY_URL = TIMELINE_BASE_URL + "/%s/%s";
+ private static final String TIMELINE_ENTITY_WITH_FILTER_URL = TIMELINE_BASE_URL + "/%s?primaryFilter=%s:%s";
+
+ private final String baseUrl;
+
+ public TezUrlFactory(String baseUrl) {
+ this.baseUrl = baseUrl;
+ }
+
+ public URL getRootURL() throws MalformedURLException {
+ return new URL(format(TIMELINE_BASE_URL, baseUrl));
+ }
+
+ public URL getApplicationURL(String applicationId) throws MalformedURLException {
+ return new URL(format(TIMELINE_ENTITY_URL, baseUrl, EntityTypes.TEZ_APPLICATION,
+ TEZ_APPLICATION_PREFIX + applicationId));
+ }
+
+ public URL getDagIdURL(String applicationId) throws MalformedURLException {
+ return new URL(format(TIMELINE_ENTITY_WITH_FILTER_URL, baseUrl, EntityTypes.TEZ_DAG_ID,
+ ATSConstants.APPLICATION_ID, applicationId));
+ }
+
+ public URL getDagExtraInfoURL(String dagId) throws MalformedURLException {
+ return new URL(format(TIMELINE_ENTITY_URL, baseUrl, EntityTypes.TEZ_DAG_EXTRA_INFO, dagId));
+ }
+
+ public URL getApplicationHistoryURL(long startTime, long finishTime) throws MalformedURLException {
+ return new URL(format(APPLICATION_HISTORY_URL, baseUrl, RMWSConsts.APPLICATION_TYPES, APPLICATION_TYPE,
+ RMWSConsts.STARTED_TIME_BEGIN, startTime, RMWSConsts.STARTED_TIME_END, finishTime));
+
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TimelineClient.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TimelineClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..61c26824f483b7617fd1b91c85561d8f5a09a496
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/tez/utils/TimelineClient.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.tez.dag.api.TezException;
+import org.apache.tez.dag.api.client.TimelineReaderFactory;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jettison.json.JSONObject;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.io.IOException;
+import java.net.URL;
+
+import static java.lang.String.format;
+
+public class TimelineClient implements AutoCloseable {
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private Client httpClient;
+
+ public TimelineClient(Configuration conf, boolean useHttps, int connTimeout) {
+ try {
+ this.httpClient = TimelineReaderFactory.getTimelineReaderStrategy(conf, useHttps, connTimeout).getHttpClient();
+ } catch (TezException | IOException e) {
+ throw new OmniAdvisorException(e);
+ }
+ }
+
+ public JsonNode readJsonNode(URL url) {
+ WebResource resource = httpClient.resource(url.toString());
+ ClientResponse response = resource.accept(MediaType.APPLICATION_JSON_TYPE)
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .get(ClientResponse.class);
+
+ if (response.getStatus() == Response.Status.OK.getStatusCode()) {
+ try {
+ return MAPPER.readTree(response.getEntity(JSONObject.class).toString());
+ } catch (IOException e) {
+ throw new OmniAdvisorException(e);
+ }
+ } else {
+ throw new OmniAdvisorException(format("Failed to get data from %s", url));
+ }
+ }
+
+ @VisibleForTesting
+ protected void setClient(Client client) {
+ this.httpClient = client;
+ }
+
+ @Override
+ public void close() {
+ httpClient.destroy();
+ }
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/utils/MathUtils.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/utils/MathUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1be9b790db2decfc4174270a15f199cd19b1ab1
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/utils/MathUtils.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.utils;
+
+public final class MathUtils {
+ public static final long SECOND_IN_MS = 1000L;
+ public static final long MINUTE_IN_MS = 60L * SECOND_IN_MS;
+ public static final long HOUR_IN_MS = 60L * MINUTE_IN_MS;
+ public static final long DAY_IN_MS = 24 * HOUR_IN_MS;
+
+ private MathUtils() {}
+}
diff --git a/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/utils/Utils.java b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/utils/Utils.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bcdb2b089d444029f88416f7f542308a0cc837f
--- /dev/null
+++ b/omniadvisor/src/main/java/com/huawei/boostkit/omniadvisor/utils/Utils.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.utils;
+
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import net.minidev.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+
+public final class Utils {
+ private Utils() {}
+
+ public static Map loadParamsFromConf(String configParamName, Map conf) {
+ URL fileURL = requireNonNull(Thread.currentThread().getContextClassLoader().getResource(configParamName),
+ format("Tez param config file %s is not found", configParamName));
+ Map params = new HashMap<>();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(new FileInputStream(fileURL.getPath()), StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ params.put(line, conf.getOrDefault(line, ""));
+ }
+ } catch (IOException e) {
+ throw new OmniAdvisorException(e);
+ }
+ return params;
+ }
+
+ public static String parseMapToJsonString(Map map) {
+ JSONObject json = new JSONObject();
+ json.putAll(map);
+ return json.toJSONString();
+ }
+}
diff --git a/omniadvisor/src/main/resources/conf/SparkParams b/omniadvisor/src/main/resources/conf/SparkParams
new file mode 100644
index 0000000000000000000000000000000000000000..6fffe44a0073b39e7ef70308aefe7f4be907cc83
--- /dev/null
+++ b/omniadvisor/src/main/resources/conf/SparkParams
@@ -0,0 +1,15 @@
+spark.executor.memory
+spark.executor.cores
+spark.executor.instances
+spark.driver.cores
+spark.driver.memory
+spark.memory.offHeap.size
+spark.broadcast.blockSize
+spark.sql.shuffle.partitions
+spark.executor.memoryOverhead
+spark.memory.fraction
+spark.memory.storageFraction
+spark.sql.autoBroadcastJoinThreshold
+spark.sql.join.preferSortMergeJoin
+spark.sql.adaptive.enabled
+spark.sql.adaptive.skewJoin.enabled
\ No newline at end of file
diff --git a/omniadvisor/src/main/resources/conf/TezParams b/omniadvisor/src/main/resources/conf/TezParams
new file mode 100644
index 0000000000000000000000000000000000000000..e54c8dc2d436f239c4349c32a59f4afedf38cc29
--- /dev/null
+++ b/omniadvisor/src/main/resources/conf/TezParams
@@ -0,0 +1,14 @@
+hive.exec.reducers.max
+hive.tez.container.size
+hive.exec.parallel.thread.number
+hive.cbo.enable
+hive.exec.parallel
+hive.tez.auto.reducer.parallelism
+tez.runtime.io.sort.mb
+tez.am.resource.memory.mb
+tez.am.resource.cpu.vcores
+tez.task.resource.memory.mb
+tez.task.resource.cpu.vcores
+tez.runtime.sort.spill.percent
+tez.runtime.compress
+tez.am.speculation.enabled
\ No newline at end of file
diff --git a/omniadvisor/src/main/resources/conf/log4j.properties b/omniadvisor/src/main/resources/conf/log4j.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f9ab97535daaf1053250c2b8296b18e116c84cee
--- /dev/null
+++ b/omniadvisor/src/main/resources/conf/log4j.properties
@@ -0,0 +1,5 @@
+log4j.rootLogger=INFO, console
+# console log
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} %p [%c] %m%n
\ No newline at end of file
diff --git a/omniadvisor/src/main/resources/conf/omniAdvisorLogAnalyzer.properties b/omniadvisor/src/main/resources/conf/omniAdvisorLogAnalyzer.properties
new file mode 100644
index 0000000000000000000000000000000000000000..d39eba9ff9316d496e462b0468f8acbfe7edea80
--- /dev/null
+++ b/omniadvisor/src/main/resources/conf/omniAdvisorLogAnalyzer.properties
@@ -0,0 +1,15 @@
+log.analyzer.thread.count=3
+
+datasource.db.driver=com.mysql.cj.jdbc.Driver
+datasource.db.url=url
+
+spark.enable=true
+spark.workload=default
+spark.eventLogs.mode=rest
+spark.rest.url=http://server1:18080
+spark.timeout.seconds=30
+
+tez.enable=true
+tez.workload=default
+tez.timeline.url=http://server1:8188
+tez.timeline.timeout.ms=6000
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/SparkFetcher.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/SparkFetcher.scala
new file mode 100644
index 0000000000000000000000000000000000000000..8694d5b58fefb53a60f6fa853d2b26b50fe4ae87
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/SparkFetcher.scala
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob
+import com.huawei.boostkit.omniadvisor.fetcher.{Fetcher, FetcherType}
+import com.huawei.boostkit.omniadvisor.models.AppResult
+import com.huawei.boostkit.omniadvisor.spark.client.{SparkEventClient, SparkLogClient, SparkRestClient}
+import com.huawei.boostkit.omniadvisor.spark.config.SparkFetcherConfigure
+import com.huawei.boostkit.omniadvisor.spark.utils.SparkUtils
+import org.apache.commons.configuration2.PropertiesConfiguration
+import org.apache.commons.io.FileUtils
+import org.apache.hadoop.conf.Configuration
+import org.apache.spark.SparkConf
+import org.slf4j.{Logger, LoggerFactory}
+
+import java.util
+import java.util.Optional
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.duration.{Duration, SECONDS}
+import scala.concurrent.{Await, Future}
+import scala.util.{Failure, Success, Try}
+
+class SparkFetcher(configure: PropertiesConfiguration)
+ extends Fetcher
+{
+ private val LOG: Logger = LoggerFactory.getLogger(classOf[SparkFetcher])
+
+ val sparkFetcherConfig = new SparkFetcherConfigure(configure)
+
+ lazy val hadoopConfigure: Configuration = OmniAdvisorContext.getHadoopConfig
+
+ lazy val sparkConf: SparkConf = {
+ val sparkConf = new SparkConf()
+ SparkUtils.getDefaultPropertiesFile() match {
+ case Some(fileName) => sparkConf.setAll(SparkUtils.getPropertiesFromFile(fileName))
+ case None => LOG.warn("Can't find Spark conf, use default config, Please set SPARK_HOME or SPARK_CONF_DIR")
+ }
+ sparkConf
+ }
+
+ lazy val sparkClient: SparkEventClient = {
+ if (sparkFetcherConfig.isRestMode) {
+ new SparkRestClient(sparkFetcherConfig.restUrl, sparkFetcherConfig.timeoutSeconds, sparkConf,
+ sparkFetcherConfig.workload)
+ } else {
+ new SparkLogClient(hadoopConfigure, sparkConf, sparkFetcherConfig.logDirectory, sparkFetcherConfig.workload,
+ sparkFetcherConfig.maxLogSizeInMB * FileUtils.ONE_MB)
+ }
+ }
+
+ override def isEnable: Boolean = sparkFetcherConfig.enable
+
+ override def analysis(job: AnalyticJob): Optional[AppResult] = {
+ val appId = job.getApplicationId
+ LOG.info(s"Fetching data for ${appId}")
+ val result = Try {
+ Await.result(doAnalysisApplication(job), Duration(sparkFetcherConfig.timeoutSeconds, SECONDS))
+ }.transform(
+ data => {
+ LOG.info(s"Succeed fetching data for ${appId}")
+ Success(data)
+ },
+ e => {
+ LOG.error(s"Failed fetching data for ${appId}, Exception Message is ${e.getMessage}")
+ Failure(e)
+ })
+ result match {
+ case Success(data) => Optional.of(data)
+ case Failure(e) => Optional.empty()
+ }
+ }
+
+ private def doAnalysisApplication(job: AnalyticJob): Future[AppResult] = {
+ Future {
+ sparkClient.fetchAnalyticResult(job)
+ }
+ }
+
+ override def getType: FetcherType = FetcherType.SPARK
+
+ override def fetchAnalyticJobs(startTimeMills: Long, finishedTimeMills: Long): util.List[AnalyticJob] = {
+ val jobs: util.List[AnalyticJob] = new util.ArrayList[AnalyticJob]()
+ sparkClient.fetchAnalyticJobs(startTimeMills, finishedTimeMills).foreach(job => jobs.add(job))
+ jobs
+ }
+}
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkEventClient.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkEventClient.scala
new file mode 100644
index 0000000000000000000000000000000000000000..e67d3ffbd0c617e49e3eb6edf1aa2af26dff4f9e
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkEventClient.scala
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.client
+
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob
+import com.huawei.boostkit.omniadvisor.models.AppResult
+
+trait SparkEventClient {
+ def fetchAnalyticJobs(startTimeMills: Long, finishedTimeMills: Long): List[AnalyticJob]
+
+ def fetchAnalyticResult(job: AnalyticJob): AppResult
+}
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkLogClient.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkLogClient.scala
new file mode 100644
index 0000000000000000000000000000000000000000..e125c3f712e62e61301ae44f6c46d4a13bf1292a
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkLogClient.scala
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.client
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob
+import com.huawei.boostkit.omniadvisor.models.AppResult
+import com.huawei.boostkit.omniadvisor.spark.data.SparkLogAnalyticJob
+import com.huawei.boostkit.omniadvisor.spark.utils.SparkUtils
+import org.apache.hadoop.conf.Configuration
+import org.apache.hadoop.fs.{FileSystem, Path}
+import org.apache.spark.SparkApplicationDataExtractor.extractAppResultFromAppStatusStore
+import org.apache.spark.SparkConf
+import org.apache.spark.SparkDataCollection
+
+class SparkLogClient(hadoopConfiguration: Configuration, sparkConf: SparkConf, eventLogUri: String,
+ workload: String, maxFileSize: Long)
+ extends SparkEventClient {
+
+ override def fetchAnalyticJobs(startTimeMills: Long, finishedTimeMills: Long): List[AnalyticJob] = {
+ SparkUtils.findApplicationFiles(hadoopConfiguration, eventLogUri, startTimeMills, finishedTimeMills, maxFileSize)
+ .map(file => new SparkLogAnalyticJob(SparkUtils.getApplicationIdFromFile(file), file))
+ .filter(job => OmniAdvisorContext.getInstance().getFinder.byId(job.getApplicationId) == null)
+ }
+
+ override def fetchAnalyticResult(job: AnalyticJob): AppResult = {
+ require(job.isInstanceOf[SparkLogAnalyticJob], "Require SparkLogAnalyticJob")
+ val logJob = job.asInstanceOf[SparkLogAnalyticJob]
+ val path = new Path(logJob.getFilePath)
+ val compressCodec = SparkUtils.compressionCodecForLogName(sparkConf, path.getName)
+ val dataCollection = new SparkDataCollection
+
+ SparkUtils.withEventLog(
+ FileSystem.get(path.toUri, hadoopConfiguration), path, compressCodec) { in =>
+ dataCollection.replayEventLogs(in, path.toString)
+ }
+
+ val appInfo = dataCollection.appInfo
+ val jobData = dataCollection.jobData
+ val environmentInfo = dataCollection.environmentInfo
+
+ extractAppResultFromAppStatusStore(appInfo, workload, environmentInfo, jobData)
+ }
+}
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkRestClient.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkRestClient.scala
new file mode 100644
index 0000000000000000000000000000000000000000..dcdcf8e6ebc932cb38693c7f1aa6e0a494f5d18f
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/client/SparkRestClient.scala
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.client
+
+import com.fasterxml.jackson.databind.{DeserializationFeature, ObjectMapper}
+import com.fasterxml.jackson.module.scala.{DefaultScalaModule, ScalaObjectMapper}
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException
+import com.huawei.boostkit.omniadvisor.models.AppResult
+import com.huawei.boostkit.omniadvisor.spark.data.SparkRestAnalyticJob
+import com.huawei.boostkit.omniadvisor.spark.utils.SparkUtils
+import org.apache.spark.SparkConf
+import org.apache.spark.SparkDataCollection
+import org.apache.spark.status.api.v1.ApplicationInfo
+import org.glassfish.jersey.client.ClientProperties
+import org.slf4j.{Logger, LoggerFactory}
+
+import java.io.{BufferedInputStream, InputStream}
+import java.net.URI
+import java.text.SimpleDateFormat
+import java.util.{Calendar, Date, SimpleTimeZone}
+import java.util.zip.ZipInputStream
+import javax.ws.rs.client.{Client, ClientBuilder, WebTarget}
+import javax.ws.rs.core.MediaType
+import scala.collection.mutable.ListBuffer
+import scala.concurrent.duration.{Duration, FiniteDuration, SECONDS}
+import scala.util.control.NonFatal
+
+class SparkRestClient(historyUri: String, timeoutSeconds: Int, sparkConf: SparkConf, workload: String)
+ extends SparkEventClient {
+ private val LOG: Logger = LoggerFactory.getLogger(classOf[SparkRestClient])
+
+ private val historyServerUri: URI = {
+ val baseUri: URI = {
+ if (historyUri.contains("http://")) {
+ new URI(historyUri)
+ } else {
+ new URI(s"http://${historyUri}")
+ }
+ }
+ require(baseUri.getPath == "")
+ baseUri
+ }
+
+ val timeout: FiniteDuration = Duration(timeoutSeconds, SECONDS)
+ val API_V1_MOUNT_PATH = "api/v1"
+ val IN_PROGRESS = ".inprogress"
+
+ val sparkRestObjectMapper: ObjectMapper with ScalaObjectMapper = {
+ val dateFormat = {
+ val formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'GMT'")
+ val cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT"))
+ formatter.setCalendar(cal)
+ formatter
+ }
+
+ val objectMapper = new ObjectMapper() with ScalaObjectMapper
+ objectMapper.setDateFormat(dateFormat)
+ objectMapper.registerModule(DefaultScalaModule)
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ objectMapper
+ }
+
+ private val client: Client = ClientBuilder.newClient()
+
+ private var apiTarget: WebTarget = client.property(ClientProperties.CONNECT_TIMEOUT, timeout.toMillis.toInt)
+ .property(ClientProperties.READ_TIMEOUT, timeout.toMillis.toInt)
+ .target(historyServerUri)
+ .path(API_V1_MOUNT_PATH)
+
+ protected def setApiTarget(apiTarget: WebTarget): Unit = {
+ this.apiTarget = apiTarget
+ }
+
+ override def fetchAnalyticJobs(startTimeMills: Long, finishedTimeMills: Long): List[AnalyticJob] = {
+ val minDate = sparkRestObjectMapper.getDateFormat.format(new Date(startTimeMills))
+ val maxDate = sparkRestObjectMapper.getDateFormat.format(new Date(finishedTimeMills))
+ val appTarget = apiTarget.path("applications").queryParam("minDate", minDate).queryParam("maxDate", maxDate)
+
+ try {
+ LOG.info(s"calling REST API at ${appTarget.getUri}")
+ val applications = getApplications(appTarget, sparkRestObjectMapper.readValue[Seq[ApplicationInfo]])
+ .filter(job => OmniAdvisorContext.getInstance().getFinder.byId(job.id) == null)
+ val analyticJobs = new ListBuffer[AnalyticJob]()
+ for (appInfo <- applications) {
+ val attempts = appInfo.attempts
+ if (attempts.isEmpty) {
+ LOG.info("application {} attempt is empty, skip it", appInfo.id)
+ } else {
+ analyticJobs += new SparkRestAnalyticJob(appInfo.id)
+ }
+ }
+ analyticJobs.toList
+ } catch {
+ case NonFatal(e) =>
+ LOG.error(s"error reading jobData ${appTarget.getUri}. Exception Message = ${e}")
+ throw new OmniAdvisorException(e)
+ }
+ }
+
+ override def fetchAnalyticResult(job: AnalyticJob): AppResult = {
+ require(job.isInstanceOf[SparkRestAnalyticJob], "Require SparkRestAnalyticJob")
+ val sparkJob = job.asInstanceOf[SparkRestAnalyticJob]
+ val attemptTarget = getApplicationMetaData(sparkJob.getApplicationId)
+ val logTarget = attemptTarget.path("logs")
+ LOG.info(s"creating SparkApplication by calling REST API at ${logTarget.getUri} to get eventLogs")
+ resource.managed {
+ getApplicationLogs(logTarget)
+ }.acquireAndGet{ zipInputStream =>
+ getLogInputStream(zipInputStream, logTarget) match {
+ case (None, _) =>
+ throw new OmniAdvisorException(s"Failed to read log for application ${sparkJob.getApplicationId}")
+ case (Some(inputStream), fileName) =>
+ val dataCollection = new SparkDataCollection()
+ dataCollection.replayEventLogs(inputStream, fileName)
+ dataCollection.getAppResult(workload)
+ }
+ }
+ }
+
+ def getApplications[T](webTarget: WebTarget, converter: String => T): T = {
+ converter(webTarget.request(MediaType.APPLICATION_JSON).get(classOf[String]))
+ }
+
+ private def getApplicationMetaData(appId: String): WebTarget = {
+ val appTarget = apiTarget.path(s"applications/${appId}")
+ LOG.info(s"calling REST API at ${appTarget.getUri}")
+
+ val applicationInfo = getApplicationInfo(appTarget)
+
+ val lastAttemptId = applicationInfo.attempts.maxBy{
+ _.startTime
+ }.attemptId
+ lastAttemptId.map(appTarget.path).getOrElse(appTarget)
+ }
+
+ private def getApplicationInfo(appTarget: WebTarget): ApplicationInfo = {
+ try {
+ getApplications(appTarget, sparkRestObjectMapper.readValue[ApplicationInfo])
+ } catch {
+ case NonFatal(e) =>
+ LOG.error(s"error reading applicationInfo ${appTarget.getUri}. Exception Message = ${e.getMessage}")
+ throw e
+ }
+ }
+
+ private def getApplicationLogs(logTarget: WebTarget): ZipInputStream = {
+ try {
+ val inputStream = logTarget.request(MediaType.APPLICATION_OCTET_STREAM)
+ .get(classOf[java.io.InputStream])
+ new ZipInputStream(new BufferedInputStream(inputStream))
+ }catch {
+ case NonFatal(e) =>
+ LOG.error(s"error reading logs ${logTarget.getUri}. Exception Message = ${e.getMessage}")
+ throw e
+ }
+ }
+
+ private def getLogInputStream(zis: ZipInputStream, attemptTarget: WebTarget): (Option[InputStream], String) = {
+ val entry = zis.getNextEntry
+ if (entry == null) {
+ LOG.warn(s"failed to resolve log for ${attemptTarget.getUri}")
+ (None, "")
+ } else {
+ val entryName = entry.getName
+ if (entryName.equals(IN_PROGRESS)) {
+ throw new OmniAdvisorException(s"Application for the log ${entryName} has not finished yes.")
+ }
+ val codec = SparkUtils.compressionCodecForLogName(sparkConf, entryName)
+ (Some(codec.map{
+ _.compressedInputStream(zis)
+ }.getOrElse(zis)), entryName)
+ }
+ }
+}
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/config/SparkFetcherConfigure.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/config/SparkFetcherConfigure.scala
new file mode 100644
index 0000000000000000000000000000000000000000..f9563b8d29cd84c9e1f2c0249160ffb0498db06e
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/config/SparkFetcherConfigure.scala
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.config
+
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException
+import org.apache.commons.configuration2.PropertiesConfiguration
+
+class SparkFetcherConfigure(propertiesConfiguration: PropertiesConfiguration) {
+ val enableKey = "spark.enable"
+ val eventLogModeKey = "spark.eventLogs.mode"
+ val workloadKey = "spark.workload"
+ val defaultWorkload = "default"
+ val restEventLogMode = "rest"
+ val restUrlKey = "spark.rest.url"
+ val defaultRestUrl = "http://localhost:18080"
+ val timeoutKey = "spark.timeout.seconds"
+ val logEventLogMode = "log"
+ val logDirectoryKey = "spark.log.directory"
+ val maxLogFileSizeInMBKey = "spark.log.maxSize.mb"
+
+ val defaultTimeoutSeconds = 30
+ val defaultMaxLogSize = 500
+
+ val enable: Boolean = propertiesConfiguration.getBoolean(enableKey, false)
+ val mode: String = propertiesConfiguration.getString(eventLogModeKey)
+ val restUrl: String = propertiesConfiguration.getString(restUrlKey, defaultRestUrl)
+ val timeoutSeconds: Int = propertiesConfiguration.getInt(timeoutKey, defaultTimeoutSeconds)
+ val logDirectory: String = propertiesConfiguration.getString(logDirectoryKey, "")
+ val maxLogSizeInMB: Int = propertiesConfiguration.getInt(maxLogFileSizeInMBKey, defaultMaxLogSize)
+ val workload: String = propertiesConfiguration.getString(workloadKey, defaultWorkload)
+
+ def isRestMode: Boolean = {
+ if (mode.equals(restEventLogMode)) {
+ true
+ } else if (mode.equals(logEventLogMode)) {
+ false
+ } else {
+ throw new OmniAdvisorException(s"Unknown event log mode ${mode}")
+ }
+ }
+}
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/data/SparkLogAnalyticJob.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/data/SparkLogAnalyticJob.scala
new file mode 100644
index 0000000000000000000000000000000000000000..6eb085de7439d99ac42345df0bd7f7637d53031e
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/data/SparkLogAnalyticJob.scala
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.data
+
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType
+
+class SparkLogAnalyticJob(applicationId: String, filePath: String) extends AnalyticJob {
+ override def getApplicationId: String = applicationId
+
+ override def getType: FetcherType = FetcherType.SPARK
+
+ def getFilePath:String = filePath
+}
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/data/SparkRestAnalyticJob.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/data/SparkRestAnalyticJob.scala
new file mode 100644
index 0000000000000000000000000000000000000000..6e73f5c0dade1a3af9e0f222ad0d0472f24806b7
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/data/SparkRestAnalyticJob.scala
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.data
+
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType
+
+class SparkRestAnalyticJob (applicationId: String) extends AnalyticJob {
+ override def getApplicationId: String = applicationId
+
+ override def getType: FetcherType = FetcherType.SPARK
+}
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/utils/ScalaUtils.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/utils/ScalaUtils.scala
new file mode 100644
index 0000000000000000000000000000000000000000..e18f446a0aed26d5256b0fd30bdbdfc1966d29d8
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/utils/ScalaUtils.scala
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.utils
+
+import com.alibaba.fastjson.JSONObject
+import org.apache.spark.JobExecutionStatus
+import org.apache.spark.status.api.v1.JobData
+
+object ScalaUtils {
+ def parseMapToJsonString(map: Map[String, String]): String = {
+ val json = new JSONObject
+ map.foreach(m => {
+ json.put(m._1, m._2)
+ })
+ json.toJSONString
+ }
+
+ def checkSuccess(jobs: Seq[JobData]): Boolean = {
+ !jobs.exists(_.status.equals(JobExecutionStatus.FAILED))
+ }
+}
diff --git a/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/utils/SparkUtils.scala b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/utils/SparkUtils.scala
new file mode 100644
index 0000000000000000000000000000000000000000..b7a1f725896d0c21cc544c360f81dc9034e42f36
--- /dev/null
+++ b/omniadvisor/src/main/scala/com/huawei/boostkit/omniadvisor/spark/utils/SparkUtils.scala
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.utils
+
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException
+import org.apache.hadoop.conf.Configuration
+import org.apache.hadoop.fs.{FileSystem, Path}
+import org.apache.spark.SparkConf
+import org.apache.spark.io.{CompressionCodec, LZ4CompressionCodec, LZFCompressionCodec, SnappyCompressionCodec, ZStdCompressionCodec}
+
+import java.io.{BufferedInputStream, File, FileInputStream, FileNotFoundException, InputStream}
+import java.net.URI
+import java.util.Properties
+import scala.collection.JavaConverters.asScalaSetConverter
+import scala.collection.mutable
+import scala.tools.jline_embedded.internal.InputStreamReader
+
+object SparkUtils {
+ def findApplicationFiles(hadoopConfiguration: Configuration, eventLogDir: String, startTimeMills: Long,
+ finishTimeMills: Long, maxFileSize: Long): List[String] = {
+ val uri = new URI(eventLogDir)
+ val fs = FileSystem.get(uri, hadoopConfiguration)
+ val eventLogDirPath: Path = new Path(eventLogDir)
+ if (fs.exists(eventLogDirPath) && fs.getFileStatus(eventLogDirPath).isDirectory) {
+ fs.listStatus(eventLogDirPath).filter(status => {
+ val fileSize = status.getLen
+ val modifyTime = status.getModificationTime
+ modifyTime >= startTimeMills && modifyTime <= finishTimeMills && fileSize <= maxFileSize
+ }).map { status => status.getPath.toString }.toList
+ } else {
+ throw new OmniAdvisorException("eventLog path is not exist or not a Directory")
+ }
+ }
+
+ private val IN_PROGRESS = ".inprogress"
+
+ private val compressionCodecClassNamesByShortName = Map(
+ "lz4" -> classOf[LZ4CompressionCodec].getName,
+ "lzf" -> classOf[LZFCompressionCodec].getName,
+ "snappy" -> classOf[SnappyCompressionCodec].getName,
+ "zstd" -> classOf[ZStdCompressionCodec].getName)
+
+ private val compressionCodecMap = mutable.HashMap.empty[String, CompressionCodec]
+
+ private def loadCompressionCodec(conf: SparkConf, codecName: String): CompressionCodec = {
+ val codecClass = compressionCodecClassNamesByShortName.getOrElse(codecName.toLowerCase, codecName)
+ val classLoader = Option(Thread.currentThread().getContextClassLoader).getOrElse(getClass.getClassLoader)
+ val codec = try {
+ val constructor = Class.forName(codecClass, true, classLoader).getConstructor(classOf[SparkConf])
+ Some(constructor.newInstance(conf).asInstanceOf[CompressionCodec])
+ } catch {
+ case _: ClassNotFoundException => None
+ case _: IllegalArgumentException => None
+ }
+ codec.getOrElse(throw new IllegalArgumentException(s"Codec [$codecName] is not available."))
+ }
+
+ def compressionCodecForLogName(conf: SparkConf, logName: String): Option[CompressionCodec] = {
+ val logBaseName = logName.stripSuffix(IN_PROGRESS)
+ logBaseName.split("\\.").tail.lastOption.map {
+ codecName =>
+ compressionCodecMap.getOrElseUpdate(codecName, loadCompressionCodec(conf, codecName))
+ }
+ }
+
+ def getApplicationIdFromFile(file: String): String = {
+ val fileName = new Path(file).getName
+ val logBaseName = fileName.stripSuffix(IN_PROGRESS)
+ logBaseName.split("\\.").apply(0)
+ }
+
+ def withEventLog[T](fs: FileSystem, path: Path, codec: Option[CompressionCodec])(f: InputStream => T): T = {
+ resource.managed { openEventLog(path, fs)}
+ .map { in => codec.map { _.compressedInputStream(in) }.getOrElse(in) }
+ .acquireAndGet(f)
+ }
+
+ private def openEventLog(logPath: Path, fs: FileSystem): InputStream = {
+ if (!fs.exists(logPath)) {
+ throw new FileNotFoundException(s"File ${logPath} does not exist.")
+ }
+
+ new BufferedInputStream(fs.open(logPath))
+ }
+
+ def defaultEnv: Map[String, String] = sys.env
+
+ def getDefaultPropertiesFile(env: Map[String, String] = defaultEnv): Option[String] = {
+ env.get("SPARK_CONF_DIR").orElse(env.get("SPARK_HOME").map {
+ t => s"$t${File.separator}conf"})
+ .map {t => new File(s"$t${File.separator}spark-defaults.conf")}
+ .filter(_.isFile)
+ .map(_.getAbsolutePath)
+ }
+
+ def getPropertiesFromFile(fileName: String): Map[String, String] = {
+ val file = new File(fileName)
+ require(file.exists(), s"Properties file $file does not exist")
+ require(file.isFile, s"Properties file $file is not a normal file")
+
+ val inReader = new InputStreamReader(new FileInputStream(file), "UTF-8")
+ try {
+ val properties = new Properties()
+ properties.load(inReader)
+ properties.stringPropertyNames().asScala.map(
+ k => (k, properties.getProperty(k).trim)).toMap
+ } finally {
+ inReader.close()
+ }
+ }
+}
diff --git a/omniadvisor/src/main/scala/org/apache/spark/SparkApplicationDataExtractor.scala b/omniadvisor/src/main/scala/org/apache/spark/SparkApplicationDataExtractor.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d5b2b598ffb405559685b9ee4f3265b2c0f6915c
--- /dev/null
+++ b/omniadvisor/src/main/scala/org/apache/spark/SparkApplicationDataExtractor.scala
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark
+
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType
+import com.huawei.boostkit.omniadvisor.models.AppResult
+import com.huawei.boostkit.omniadvisor.spark.utils.ScalaUtils.{checkSuccess, parseMapToJsonString}
+import com.nimbusds.jose.util.StandardCharset
+import org.apache.spark.status.api.v1._
+import org.slf4j.{Logger, LoggerFactory}
+
+import scala.collection.mutable
+import scala.io.{BufferedSource, Source}
+
+object SparkApplicationDataExtractor {
+ val LOG: Logger = LoggerFactory.getLogger(SparkApplicationDataExtractor.getClass)
+
+ val SPARK_REQUIRED_PARAMS_FILE = "SparkParams"
+
+ def extractAppResultFromAppStatusStore(appInfo: ApplicationInfo,
+ workload: String,
+ environmentInfo: ApplicationEnvironmentInfo,
+ jobsList: Seq[JobData]): AppResult = {
+ val appResult = new AppResult
+ appResult.applicationId = appInfo.id
+ appResult.applicationName = appInfo.name
+ appResult.jobType = FetcherType.SPARK.getName
+ appResult.applicationWorkload = workload
+
+ val attempt: ApplicationAttemptInfo = lastAttempt(appInfo)
+ appResult.startTime = attempt.startTime.getTime
+ appResult.finishTime = attempt.endTime.getTime
+
+ val configurations: Map[String, String] = extractAppConfigurations(environmentInfo)
+ appResult.parameters = parseMapToJsonString(extractRequiredConfiguration(configurations))
+
+ if (!attempt.completed) {
+ // In this case, the task is killed, consider as a failed task
+ appResult.executionStatus = AppResult.FAILED_STATUS
+ appResult.durationTime = AppResult.FAILED_JOB_DURATION
+ appResult.query = ""
+ } else {
+ if (jobsList.nonEmpty) {
+ val query: Option[String] = jobsList.maxBy(job => job.jobId).description
+
+ if (checkSuccess(jobsList)) {
+ appResult.executionStatus = AppResult.SUCCEEDED_STATUS
+ appResult.durationTime = attempt.duration
+ appResult.query = query.getOrElse("")
+ } else {
+ appResult.executionStatus = AppResult.FAILED_STATUS
+ appResult.durationTime = AppResult.FAILED_JOB_DURATION
+ appResult.query = ""
+ }
+ } else {
+ appResult.query = ""
+ appResult.executionStatus = AppResult.FAILED_STATUS
+ appResult.durationTime = AppResult.FAILED_JOB_DURATION
+ }
+ }
+
+ appResult
+ }
+
+ private def extractRequiredConfiguration(sparkConfigure: Map[String, String]): Map[String, String] = {
+ var sparkParamsFile: BufferedSource = null
+ try {
+ sparkParamsFile = Source.fromFile(Thread.currentThread().getContextClassLoader
+ .getResource(SPARK_REQUIRED_PARAMS_FILE).getPath, StandardCharset.UTF_8.name)
+ val params: Iterator[String] = sparkParamsFile.getLines()
+ val requiredParams = new mutable.HashMap[String, String]()
+ for (param <- params) {
+ val paramRequired = param.trim
+ if (paramRequired.nonEmpty) {
+ requiredParams.put(paramRequired, sparkConfigure.getOrElse(paramRequired, ""))
+ }
+ }
+ requiredParams.toMap[String, String]
+ } finally {
+ if (sparkParamsFile.nonEmpty) {
+ sparkParamsFile.close
+ }
+ }
+ }
+
+ private def extractAppConfigurations(environmentInfo: ApplicationEnvironmentInfo): Map[String, String] = {
+ environmentInfo.sparkProperties.toMap
+ }
+
+ def lastAttempt(applicationInfo: ApplicationInfo): ApplicationAttemptInfo = {
+ require(applicationInfo.attempts.nonEmpty)
+ applicationInfo.attempts.last
+ }
+}
diff --git a/omniadvisor/src/main/scala/org/apache/spark/SparkDataCollection.scala b/omniadvisor/src/main/scala/org/apache/spark/SparkDataCollection.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d738bd3d2c49d75bc246b08f4bcd0a4faed2a09f
--- /dev/null
+++ b/omniadvisor/src/main/scala/org/apache/spark/SparkDataCollection.scala
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark
+
+import com.huawei.boostkit.omniadvisor.models.AppResult
+import org.apache.spark.status.api.v1
+import org.apache.spark.util.kvstore.{InMemoryStore, KVStore}
+import org.apache.spark.internal.config.Status.ASYNC_TRACKING_ENABLED
+import org.apache.spark.scheduler.ReplayListenerBus
+import org.apache.spark.status.{AppStatusListener, AppStatusStore, ElementTrackingStore}
+import org.apache.spark.util.Utils
+import org.slf4j.{Logger, LoggerFactory}
+
+import java.io.InputStream
+
+class SparkDataCollection {
+ val LOG: Logger = LoggerFactory.getLogger(classOf[SparkDataCollection])
+
+ private val conf = new SparkConf
+
+ var environmentInfo: v1.ApplicationEnvironmentInfo = _
+ var jobData: Seq[v1.JobData] = _
+ var appInfo: v1.ApplicationInfo = _
+
+ def replayEventLogs(in: InputStream, sourceName: String): Unit = {
+ val store: KVStore = createInMemoryStore()
+ val replayConf: SparkConf = conf.clone().set(ASYNC_TRACKING_ENABLED, false)
+ val trackingStore: ElementTrackingStore = new ElementTrackingStore(store, replayConf)
+ val replayBus: ReplayListenerBus = new ReplayListenerBus()
+ val listener = new AppStatusListener(trackingStore, replayConf, false)
+ replayBus.addListener(listener)
+
+ try {
+ replayBus.replay(in, sourceName, maybeTruncated = true)
+ trackingStore.close(false)
+ } catch {
+ case e: Exception =>
+ Utils.tryLogNonFatalError {
+ trackingStore.close()
+ }
+ throw e
+ }
+ LOG.info("Replay of logs complete")
+ val appStatusStore: AppStatusStore = new AppStatusStore(store)
+ appInfo = appStatusStore.applicationInfo()
+ environmentInfo = appStatusStore.environmentInfo()
+ jobData = appStatusStore.jobsList(null)
+ appStatusStore.close()
+ }
+
+ def getAppResult(workload: String): AppResult = {
+ SparkApplicationDataExtractor.extractAppResultFromAppStatusStore(appInfo, workload, environmentInfo, jobData)
+ }
+
+ private def createInMemoryStore(): KVStore = {
+ val store = new InMemoryStore()
+ store
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/TestOmniAdvisor.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/TestOmniAdvisor.java
new file mode 100644
index 0000000000000000000000000000000000000000..3372be5638fdefd10cb960a532d394cbfb435d36
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/TestOmniAdvisor.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor;
+
+import com.huawei.boostkit.omniadvisor.configuration.BaseTestConfiguration;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import org.junit.Test;
+
+public class TestOmniAdvisor extends BaseTestConfiguration {
+ @Test
+ public void testOmniTuning() {
+ OmniAdvisor.main(new String[]{"2020-09-02 00:00:00", "2020-09-02 00:00:00", "user", "passwd"});
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testErrorNumberParams() {
+ OmniAdvisor.main(new String[] {"2020-09-02 00:00:00", "2020-09-02 00:00:00"});
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testErrorTimeParser() {
+ OmniAdvisor.main(new String[] {"2020-09-02 00-00-00", "2020-09-02 00-00-00", "user", "pass"});
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testErrorTimeOrder() {
+ OmniAdvisor.main(new String[] {"2020-09-02 20:00:00", "2020:09:02 00-00-00", "user", "pass"});
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/BaseTestConfiguration.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/BaseTestConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9f4271541dfe403c53df7f7ce90b9e2bcdecdd3
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/BaseTestConfiguration.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.configuration;
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import io.ebean.Finder;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.junit.BeforeClass;
+import org.mockito.Mockito;
+
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Locale;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+public class BaseTestConfiguration {
+ private static final String TESTING_CONFIG_FILE = "omniAdvisorLogAnalyzer.properties";
+ private static final String ENCODING = StandardCharsets.UTF_8.displayName(Locale.ENGLISH);
+
+ protected static PropertiesConfiguration testConfiguration;
+
+ @BeforeClass
+ public static void setUp() throws ConfigurationException {
+ Configurations configurations = new Configurations();
+ URL configUrl = Thread.currentThread().getContextClassLoader().getResource(TESTING_CONFIG_FILE);
+ FileBasedConfigurationBuilder.setDefaultEncoding(OmniAdvisorConfigure.class, ENCODING);
+ testConfiguration = configurations.properties(configUrl);
+
+ OmniAdvisorContext.initContext();
+ OmniAdvisorContext context = OmniAdvisorContext.getInstance();
+ Finder finder = Mockito.mock(Finder.class);
+ when(finder.byId(any())).thenReturn(null);
+ context.setFinder(finder);
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestConfiguration.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..752add90b578668a0a2097784f0742925f87dc9f
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.configuration;
+
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.fluent.Configurations;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.junit.BeforeClass;
+
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+
+public class TestConfiguration {
+ private static final String TESTING_CONFIG_FILE_NAME = "TestingConfigure.properties";
+ private static final String TESTING_SPARK_CONFIG_FILE_NAME = "TestingSparkConfigure.properties";
+ private static final String ENCODING = StandardCharsets.UTF_8.displayName();
+
+ protected static PropertiesConfiguration testConfiguration;
+ protected static PropertiesConfiguration testSparkConfiguration;
+
+ @BeforeClass
+ public static void setUpClass() throws ConfigurationException {
+ Configurations configurations = new Configurations();
+ URL configFileUrl = Thread.currentThread().getContextClassLoader().getResource(TESTING_CONFIG_FILE_NAME);
+ URL sparkConfig = Thread.currentThread().getContextClassLoader().getResource(TESTING_SPARK_CONFIG_FILE_NAME);
+ FileBasedConfigurationBuilder.setDefaultEncoding(OmniAdvisorConfigure.class, ENCODING);
+ testConfiguration = configurations.properties(configFileUrl);
+ testSparkConfiguration = configurations.properties(sparkConfig);
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestDBConfigure.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestDBConfigure.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e4a67e44199f91f4abe8224f482f4e7a8e5bdaa
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestDBConfigure.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.configuration;
+
+import io.ebean.config.DatabaseConfig;
+import io.ebean.datasource.DataSourceInitialiseException;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.sql.DataSource;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+public class TestDBConfigure {
+ @Test(expected = DataSourceInitialiseException.class)
+ public void testDBConfigureWithErrorUrl() {
+ PropertiesConfiguration testConfiguration = Mockito.mock(PropertiesConfiguration.class);
+ when(testConfiguration.getString("datasource.db.driver", "com.mysql.cj.jdbc.Driver"))
+ .thenReturn("com.mysql.cj.jdbc.Driver");
+ when(testConfiguration.getString("datasource.db.url")).thenReturn("jdbc://mysql:errorUrl");
+ DBConfigure.initDatabase(testConfiguration, "user", "passwd");
+ }
+
+ @Test
+ public void testInitDataBase() throws SQLException {
+ ResultSet resultSet = Mockito.mock(ResultSet.class);
+ DatabaseMetaData metaData = Mockito.mock(DatabaseMetaData.class);
+ Connection connection = Mockito.mock(Connection.class);
+ DataSource dataSource = Mockito.mock(DataSource.class);
+ DatabaseConfig dbConfig = Mockito.mock(DatabaseConfig.class);
+
+ when(resultSet.next()).thenReturn(true);
+ when(metaData.getTables(any(), any(), any(), any())).thenReturn(resultSet);
+ when(connection.getMetaData()).thenReturn(metaData);
+ when(dbConfig.getDataSource()).thenReturn(dataSource);
+ when(dataSource.getConnection()).thenReturn(connection);
+ DBConfigure.checkInit(dbConfig);
+ }
+
+ @Test
+ public void testNotInitDatabase() throws SQLException {
+ ResultSet resultSet = Mockito.mock(ResultSet.class);
+ DatabaseMetaData metaData = Mockito.mock(DatabaseMetaData.class);
+ Connection connection = Mockito.mock(Connection.class);
+ DataSource dataSource = Mockito.mock(DataSource.class);
+ DatabaseConfig dbConfig = Mockito.mock(DatabaseConfig.class);
+
+ when(resultSet.next()).thenReturn(false);
+ when(metaData.getTables(any(), any(), any(), any())).thenReturn(resultSet);
+ when(connection.getMetaData()).thenReturn(metaData);
+ when(dbConfig.getDataSource()).thenReturn(dataSource);
+ when(dataSource.getConnection()).thenReturn(connection);
+ DBConfigure.checkInit(dbConfig);
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestOmniAdvisorConfigure.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestOmniAdvisorConfigure.java
new file mode 100644
index 0000000000000000000000000000000000000000..0fd25f6cf0f9fc1f0c8784a25fb82b73343e2276
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/configuration/TestOmniAdvisorConfigure.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.configuration;
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestOmniAdvisorConfigure extends TestConfiguration {
+ @Test
+ public void getOmniTuningConfigure() {
+ assertEquals(OmniAdvisorContext.getInstance().getOmniAdvisorConfigure().getThreadCount(), 3);
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/exception/TestOmniAdvisorException.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/exception/TestOmniAdvisorException.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b2b8efe3d9078badd52356b561674bd040ab1c3
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/exception/TestOmniAdvisorException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.exception;
+
+import org.junit.Test;
+
+public class TestOmniAdvisorException {
+ @Test(expected = OmniAdvisorException.class)
+ public void testThrowExceptionWithMessage() {
+ throw new OmniAdvisorException("errorMessage");
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testThrowExceptionWithThrowable() {
+ throw new OmniAdvisorException(new IllegalArgumentException());
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testThrowExceptionWithMessageAndThrowable() {
+ throw new OmniAdvisorException("message", new RuntimeException());
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/executor/TestOmniAdvisorRunner.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/executor/TestOmniAdvisorRunner.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd3aff958b22992d717f9c0b12352fcb47107366
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/executor/TestOmniAdvisorRunner.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.executor;
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import com.huawei.boostkit.omniadvisor.configuration.BaseTestConfiguration;
+import com.huawei.boostkit.omniadvisor.fetcher.Fetcher;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType;
+import com.huawei.boostkit.omniadvisor.spark.SparkFetcher;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.net.URL;
+
+import static org.mockito.Mockito.when;
+
+public class TestOmniAdvisorRunner extends BaseTestConfiguration {
+ @Test
+ public void testOmniTuningRunner() {
+ PropertiesConfiguration sparkConfig = Mockito.mock(PropertiesConfiguration.class);
+ when(sparkConfig.getBoolean("spark.enable", false)).thenReturn(true);
+ when(sparkConfig.getString("spark.workload", "default")).thenReturn("default");
+ when(sparkConfig.getString("spark.eventLogs.mode")).thenReturn("log");
+ when(sparkConfig.getInt("spark.timeout.seconds", 30)).thenReturn(30);
+ URL resource = Thread.currentThread().getContextClassLoader().getResource("spark-events");
+ when(sparkConfig.getString("spark.log.directory", "")).thenReturn(resource.getPath());
+ when(sparkConfig.getInt("spark.log.maxSize.mb", 500)).thenReturn(500);
+ Fetcher sparkFetcher = new SparkFetcher(sparkConfig);
+
+ OmniAdvisorContext.getInstance().getFetcherFactory().addFetcher(FetcherType.SPARK, sparkFetcher);
+
+ OmniAdvisorRunner runner = new OmniAdvisorRunner(0L, Long.MAX_VALUE);
+ runner.run();
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/fetcher/TestFetcherFactory.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/fetcher/TestFetcherFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7d615b779681b6360e68b9a88a818ae74c2bf37
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/fetcher/TestFetcherFactory.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.fetcher;
+
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.spark.SparkFetcher;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+public class TestFetcherFactory {
+ @Test
+ public void testFetcherFactory() {
+ PropertiesConfiguration config = Mockito.mock(PropertiesConfiguration.class);
+
+ when(config.getBoolean("spark.enable", false)).thenReturn(true);
+ when(config.getBoolean("tez.enable", false)).thenReturn(false);
+
+ FetcherFactory fetcherFactory = new FetcherFactory(config);
+ assertEquals(fetcherFactory.getAllFetchers().size(), 1);
+ }
+
+ @Test
+ public void testFetcherFactoryWithEmptyFetcher() {
+ PropertiesConfiguration config = Mockito.mock(PropertiesConfiguration.class);
+
+ when(config.getBoolean("spark.enable", false)).thenReturn(false);
+ when(config.getBoolean("tez.enable", false)).thenReturn(false);
+
+ FetcherFactory fetcherFactory = new FetcherFactory(config);
+ assertEquals(fetcherFactory.getAllFetchers().size(), 0);
+ }
+
+ @Test
+ public void testGetFetcher() {
+ PropertiesConfiguration config = Mockito.mock(PropertiesConfiguration.class);
+
+ when(config.getBoolean("spark.enable", false)).thenReturn(true);
+ when(config.getBoolean("tez.enable", false)).thenReturn(false);
+
+ FetcherFactory fetcherFactory = new FetcherFactory(config);
+ assertEquals(fetcherFactory.getFetcher(FetcherType.SPARK).getClass(), SparkFetcher.class);
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testGetUnknownFetcher() {
+ PropertiesConfiguration config = Mockito.mock(PropertiesConfiguration.class);
+
+ when(config.getBoolean("spark.enable", false)).thenReturn(false);
+ when(config.getBoolean("tez.enable", false)).thenReturn(false);
+
+ FetcherFactory fetcherFactory = new FetcherFactory(config);
+ fetcherFactory.getFetcher(FetcherType.TEZ);
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/security/TestHadoopSecurity.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/security/TestHadoopSecurity.java
new file mode 100644
index 0000000000000000000000000000000000000000..c7cc2f4a4cbfc3712d373d6564bfd232084434c1
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/security/TestHadoopSecurity.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.security;
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import com.huawei.boostkit.omniadvisor.configuration.OmniAdvisorConfigure;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
+import org.apache.hadoop.minikdc.MiniKdc;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Locale;
+import java.util.Properties;
+
+public class TestHadoopSecurity {
+ private static Configuration conf;
+ private static MiniKdc kdc;
+ private static File keytab;
+
+ @BeforeClass
+ public static void setupKdc() throws Exception {
+ conf = new Configuration();
+ conf.set(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION,
+ UserGroupInformation.AuthenticationMethod.KERBEROS.toString().toLowerCase(Locale.ENGLISH));
+ UserGroupInformation.setConfiguration(conf);
+
+ final String principal = "test";
+ final File workDir = new File(System.getProperty("test.dir", "target"));
+ keytab = new File(workDir, "test.keytab");
+
+ Properties kdcConf = MiniKdc.createConf();
+ kdc = new MiniKdc(kdcConf, workDir);
+ kdc.start();
+ kdc.createPrincipal(keytab, principal);
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ UserGroupInformation.reset();
+ if (kdc != null) {
+ kdc.stop();
+ }
+ }
+
+ @After
+ public void clearProperties() {
+ OmniAdvisorConfigure configure = OmniAdvisorContext.getInstance().getOmniAdvisorConfigure();
+ configure.setKerberosPrincipal(null);
+ configure.setKerberosKeytabFile(null);
+ }
+
+ @Test
+ public void testHadoopSecurity() throws Exception {
+ OmniAdvisorConfigure configure = OmniAdvisorContext.getInstance().getOmniAdvisorConfigure();
+ configure.setKerberosPrincipal("test");
+ configure.setKerberosKeytabFile(keytab.getAbsolutePath());
+ HadoopSecurity security = new HadoopSecurity(conf);
+ security.checkLogin();
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testHadoopSecurityWithoutKeytabUser() throws Exception {
+ OmniAdvisorConfigure configure = OmniAdvisorContext.getInstance().getOmniAdvisorConfigure();
+ configure.setKerberosKeytabFile(keytab.getAbsolutePath());
+ HadoopSecurity security = new HadoopSecurity(conf);
+ security.checkLogin();
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testHadoopSecurityWithoutKeytabLocation() throws Exception {
+ OmniAdvisorConfigure configure = OmniAdvisorContext.getInstance().getOmniAdvisorConfigure();
+ configure.setKerberosPrincipal("test");
+ HadoopSecurity security = new HadoopSecurity(conf);
+ security.checkLogin();
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testHadoopSecurityWithErrorKeytabFile() throws Exception {
+ OmniAdvisorConfigure configure = OmniAdvisorContext.getInstance().getOmniAdvisorConfigure();
+ configure.setKerberosPrincipal("test");
+ configure.setKerberosKeytabFile("errorPath");
+ HadoopSecurity security = new HadoopSecurity(conf);
+ security.checkLogin();
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/TestSparkFetcher.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/TestSparkFetcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c1cd94f24a6e68d552e6fa64c0602964cbf562c
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/TestSparkFetcher.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark;
+
+import com.huawei.boostkit.omniadvisor.OmniAdvisorContext;
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+import com.huawei.boostkit.omniadvisor.spark.data.SparkLogAnalyticJob;
+import io.ebean.Finder;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+public class TestSparkFetcher {
+ private static String testResourcePath;
+ private static SparkFetcher sparkFetcher;
+
+ @BeforeClass
+ public static void setUp() {
+ PropertiesConfiguration sparkConfig = Mockito.mock(PropertiesConfiguration.class);
+ when(sparkConfig.getBoolean("spark.enable", false)).thenReturn(true);
+ when(sparkConfig.getString("spark.workload", "default")).thenReturn("default");
+ when(sparkConfig.getString("spark.eventLogs.mode")).thenReturn("log");
+ when(sparkConfig.getInt("spark.timeout.seconds", 30)).thenReturn(30);
+ URL resource = Thread.currentThread().getContextClassLoader().getResource("spark-events");
+ testResourcePath = resource.getPath();
+ when(sparkConfig.getString("spark.log.directory", "")).thenReturn(resource.getPath());
+ when(sparkConfig.getInt("spark.log.maxSize.mb", 500)).thenReturn(500);
+ sparkFetcher = new SparkFetcher(sparkConfig);
+ }
+
+ @Test
+ public void testEnable() {
+ assertTrue(sparkFetcher.isEnable());
+ }
+
+ @Test
+ public void testFetcherType() {
+ assertEquals(sparkFetcher.getType(), FetcherType.SPARK);
+ }
+
+ @Test
+ public void testGetApplications() {
+ OmniAdvisorContext.initContext();
+ Finder finder = Mockito.mock(Finder.class);
+ when(finder.byId(any())).thenReturn(null);
+ OmniAdvisorContext.getInstance().setFinder(finder);
+ List jobs = sparkFetcher.fetchAnalyticJobs(0L, Long.MAX_VALUE);
+ assertEquals(jobs.size(), 1);
+ }
+
+ @Test
+ public void testAnalysis() {
+ SparkLogAnalyticJob logJob = new SparkLogAnalyticJob("appId",
+ testResourcePath + System.getProperty("file.separator") + "application_1516285256255_0012");
+ Optional result = sparkFetcher.analysis(logJob);
+ assertTrue(result.isPresent());
+ AppResult appResult = result.get();
+ assertEquals(appResult.applicationId, "application_1516285256255_0012");
+ assertEquals(appResult.applicationName, "Spark shell");
+ assertEquals(appResult.applicationWorkload, "default");
+ assertEquals(appResult.startTime, 1516300235119L);
+ assertEquals(appResult.finishTime, 1516300707938L);
+ assertEquals(appResult.durationTime, 472819L);
+ assertEquals(appResult.jobType, "SPARK");
+ assertEquals(appResult.parameters, "{\"spark.executor.memory\":\"2G\",\"spark.executor.cores\":\"\",\"spark.executor.instances\":\"8\"}");
+ assertEquals(appResult.query, "");
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/client/TestRestClient.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/client/TestRestClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f136fad9f333b10550f36e697f83af9b934dd92
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/client/TestRestClient.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.client;
+
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.configuration.BaseTestConfiguration;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+import com.huawei.boostkit.omniadvisor.spark.data.SparkRestAnalyticJob;
+import org.apache.spark.SparkConf;
+import org.junit.Test;
+import org.mockito.Mockito;
+import scala.collection.immutable.List;
+
+import javax.ws.rs.client.Invocation.Builder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+public class TestRestClient extends BaseTestConfiguration {
+ private static final String TEST_URL = "http://testUri";
+ private static final String TEST_APP_INFO =
+ "{" +
+ "\"id\" : \"test\"," +
+ "\"name\" : \"test\"," +
+ "\"attempts\" : [{" +
+ "\"startTime\" : \"2023-09-08T03:10:30.194GMT\"," +
+ "\"endTime\" : \"2023-09-08T03:11:34.864GMT\"," +
+ "\"lastUpdated\" : \"2023-09-08T03:11:34.970GMT\"," +
+ "\"duration\" : 62670," +
+ "\"sparkUser\" : \"root\"," +
+ "\"completed\" : true," +
+ "\"appSparkVersion\" : \"3.1.1\"," +
+ "\"startTimeEpoch\" : 1694142632194," +
+ "\"lastUpdatedEpoch\" : 1694142694970," +
+ "\"endTimeEpoch\" : 1694142694864" +
+ "}]" +
+ "}";
+
+ private static final String TEST_APP_INFO_LIST = "[" + TEST_APP_INFO + "]";
+
+ private static final String TEST_EMPTY_APP_INFO_LIST = "[{\"id\":\"test\",\"name\":\"test\",\"attempts\":[]}]";
+
+ @Test
+ public void testGetApplications() throws URISyntaxException {
+ SparkRestClient restClient = new SparkRestClient("history-url", 1, new SparkConf(), "default");
+ WebTarget webTarget = Mockito.mock(WebTarget.class);
+ when(webTarget.getUri()).thenReturn(new URI(TEST_URL));
+ when(webTarget.path(any())).thenReturn(webTarget);
+ when(webTarget.queryParam(any(), any())).thenReturn(webTarget);
+ Builder builder = Mockito.mock(Builder.class);
+ when(builder.get(String.class)).thenReturn(TEST_APP_INFO_LIST);
+ when(webTarget.request(MediaType.APPLICATION_JSON)).thenReturn(builder);
+ restClient.setApiTarget(webTarget);
+ List jobList = restClient.fetchAnalyticJobs(0L, 100L);
+ assertEquals(jobList.size(), 1);
+ }
+
+ @Test
+ public void testGetEmptyApplication() throws URISyntaxException {
+ SparkRestClient restClient = new SparkRestClient("history-url", 1, new SparkConf(), "default");
+ WebTarget webTarget = Mockito.mock(WebTarget.class);
+ when(webTarget.getUri()).thenReturn(new URI(TEST_URL));
+ when(webTarget.path(any())).thenReturn(webTarget);
+ when(webTarget.queryParam(any(), any())).thenReturn(webTarget);
+ Builder builder = Mockito.mock(Builder.class);
+ when(builder.get(String.class)).thenReturn(TEST_EMPTY_APP_INFO_LIST);
+ when(webTarget.request(MediaType.APPLICATION_JSON)).thenReturn(builder);
+ restClient.setApiTarget(webTarget);
+ List jobList = restClient.fetchAnalyticJobs(0L, 100L);
+ assertEquals(jobList.size(), 0);
+ }
+
+ @Test
+ public void testAnalysis() throws IOException, URISyntaxException {
+ // build test file
+ final File workDir = new File(System.getProperty("test.dir", "target"));
+
+ URL filePath = Thread.currentThread().getContextClassLoader()
+ .getResource("spark-events/application_1516285256255_0012");
+ assertNotNull(filePath);
+ File fileToZip = new File(filePath.getPath());
+
+ String outZip = workDir + System.getProperty("file.separator") + "output.zip";
+ File outputFile = new File(outZip);
+
+ try (FileOutputStream fos = new FileOutputStream(outputFile);
+ ZipOutputStream zos = new ZipOutputStream(fos)) {
+
+ ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
+ zos.putNextEntry(zipEntry);
+
+ try (FileInputStream fis = new FileInputStream(fileToZip)) {
+ byte[] buffer = new byte[1024];
+ int len;
+ while ((len = fis.read(buffer)) > 0) {
+ zos.write(buffer, 0, len);
+ }
+ }
+ }
+
+ // test analyze
+ SparkRestAnalyticJob restJob = new SparkRestAnalyticJob("application_1516285256255_0012");
+ assertEquals(restJob.getType(), FetcherType.SPARK);
+ SparkRestClient restClient = new SparkRestClient("history-url", 1, new SparkConf(), "default");
+ WebTarget webTarget = Mockito.mock(WebTarget.class);
+ when(webTarget.getUri()).thenReturn(new URI(TEST_URL));
+ when(webTarget.path(any())).thenReturn(webTarget);
+ when(webTarget.queryParam(any(), any())).thenReturn(webTarget);
+ Builder builder = Mockito.mock(Builder.class);
+ InputStream inputStream = new FileInputStream(outputFile.getAbsoluteFile());
+ when(builder.get(InputStream.class)).thenReturn(inputStream);
+ when(builder.get(String.class)).thenReturn(TEST_APP_INFO);
+ when(webTarget.request(MediaType.APPLICATION_OCTET_STREAM)).thenReturn(builder);
+ when(webTarget.request(MediaType.APPLICATION_JSON)).thenReturn(builder);
+ restClient.setApiTarget(webTarget);
+ AppResult result = restClient.fetchAnalyticResult(restJob);
+ assertEquals(result.applicationId, "application_1516285256255_0012");
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/utils/TestSparkUtils.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/utils/TestSparkUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..66c8078f1d5a7b02e631ea8a51e19d78a08042b3
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/spark/utils/TestSparkUtils.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.spark.utils;
+
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.spark.SparkConf;
+import org.apache.spark.io.CompressionCodec;
+import org.apache.spark.io.ZStdCompressionCodec;
+import org.junit.Test;
+import scala.Option;
+import scala.collection.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class TestSparkUtils {
+ @Test
+ public void testGetPropertiesFromFile() {
+ String filePath = Thread.currentThread().getContextClassLoader().getResource("test-spark.conf").getPath();
+ Map map = SparkUtils.getPropertiesFromFile(filePath);
+ assertEquals(map.size(), 1);
+ assertEquals(map.get("spark.master").get(), "yarn");
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testLoadLogFileFromErrorPath() {
+ SparkUtils.findApplicationFiles(new Configuration(), "errorPath", 0L, 100L, 500);
+ }
+
+ @Test
+ public void getApplicationIdFromFile() {
+ String fileName = "app_id.ztsd";
+ assertEquals(SparkUtils.getApplicationIdFromFile(fileName), "app_id");
+ }
+
+ @Test
+ public void testLoadCompressionCodec() {
+ SparkConf conf = new SparkConf();
+ Option codec = SparkUtils.compressionCodecForLogName(conf, "app_id.zstd");
+ assertTrue(codec.isDefined());
+ assertEquals(codec.get().getClass(), ZStdCompressionCodec.class);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testUnKnownLoadCompressionCodec() {
+ SparkConf conf = new SparkConf();
+ SparkUtils.compressionCodecForLogName(conf, "app_id.unknown");
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/TestTezFetcher.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/TestTezFetcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e67edc2ae054f6758fef64a4e6b08796a0f0cbb
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/TestTezFetcher.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez;
+
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.configuration.BaseTestConfiguration;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.fetcher.FetcherType;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+import com.huawei.boostkit.omniadvisor.spark.data.SparkRestAnalyticJob;
+import com.huawei.boostkit.omniadvisor.tez.data.TezAnalyticJob;
+import com.huawei.boostkit.omniadvisor.tez.utils.TestTezClient;
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.apache.hadoop.yarn.api.records.YarnApplicationState;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.List;
+import java.util.Optional;
+
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestJsonUtilsFactory.getAppListJsonUtils;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestJsonUtilsFactory.getFailedJsonUtils;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestJsonUtilsFactory.getKilledJsonUtils;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestJsonUtilsFactory.getSuccessJsonUtils;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestJsonUtilsFactory.getUnFinishedJsonUtils;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.FAILED_JOB;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.KILLED_JOB;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.SUCCESS;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.SUCCESS_JOB;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.TIME_14;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.TIME_18;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.UNFINISHED_JOB;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class TestTezFetcher extends BaseTestConfiguration {
+ @Test
+ public void testGetApplicationFromTimeline() throws IOException {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ fetcher.setTimelineClient(TestTezClient.getTestTimelineClient());
+ List job = fetcher.fetchAnalyticJobs(0L, 100L);
+ assertEquals(job.size(), 1);
+ }
+
+ @Test
+ public void testGetType() {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ assertEquals(fetcher.getType(), FetcherType.TEZ);
+ }
+
+ @Test
+ public void tesGetApplicationsWithError() {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ List jobs = fetcher.fetchAnalyticJobs(0L, 100L);
+ assertTrue(jobs.isEmpty());
+ }
+
+ @Test
+ public void testAnalyzeWithError() {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ Optional result = fetcher.analysis(new TezAnalyticJob("id", "name", 0L, 1L, YarnApplicationState.FINISHED));
+ assertFalse(result.isPresent());
+ }
+
+ @Test
+ public void testEnable() {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ assertFalse(fetcher.isEnable());
+ }
+
+ @Test
+ public void testAnalyze() throws IOException {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ fetcher.setTimelineClient(TestTezClient.getTestTimelineClient());
+ AnalyticJob testJob = new TezAnalyticJob("test", "test", 0, 100, YarnApplicationState.FINISHED);
+ fetcher.analysis(testJob);
+ }
+
+ @Test
+ public void testGetApplications() throws AuthenticationException, IOException {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ fetcher.setTezJsonUtils(getAppListJsonUtils());
+ List tezJobs = fetcher.fetchAnalyticJobs(TIME_14, TIME_18);
+ assertEquals(tezJobs.size(), 4);
+ }
+
+ @Test(expected = OmniAdvisorException.class)
+ public void testAnalyzeJobWithErrorType() {
+ SparkRestAnalyticJob sparkRestAnalyticJob = new SparkRestAnalyticJob("sparkRest");
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ fetcher.analysis(sparkRestAnalyticJob);
+ }
+
+ @Test
+ public void testAnalyzeJobWithSuccessJob() throws MalformedURLException {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ fetcher.setTezJsonUtils(getSuccessJsonUtils());
+ Optional successJob = fetcher.analysis(SUCCESS_JOB);
+ assertTrue(successJob.isPresent());
+ assertEquals(successJob.get().applicationId, SUCCESS);
+ }
+
+ @Test
+ public void testAnalyzeJobWithFailedJob() throws MalformedURLException {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ fetcher.setTezJsonUtils(getFailedJsonUtils());
+ Optional failedJob = fetcher.analysis(FAILED_JOB);
+ assertTrue(failedJob.isPresent());
+ }
+
+ @Test
+ public void testAnalyzeJobWithKilledJob() throws MalformedURLException {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ fetcher.setTezJsonUtils(getKilledJsonUtils());
+ Optional killedJob = fetcher.analysis(KILLED_JOB);
+ assertTrue(killedJob.isPresent());
+ }
+
+ @Test
+ public void testAnalyzeJobWithUnFinishedJob() throws MalformedURLException {
+ TezFetcher fetcher = new TezFetcher(testConfiguration);
+ fetcher.setTezJsonUtils(getUnFinishedJsonUtils());
+ Optional unFinishedJob = fetcher.analysis(UNFINISHED_JOB);
+ assertTrue(unFinishedJob.isPresent());
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/data/TestTezData.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/data/TestTezData.java
new file mode 100644
index 0000000000000000000000000000000000000000..de71cda9a5c28de3b2dab4754ea3843022aca048
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/data/TestTezData.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.data;
+
+import com.huawei.boostkit.omniadvisor.spark.data.SparkRestAnalyticJob;
+import org.apache.hadoop.yarn.api.records.YarnApplicationState;
+import org.apache.tez.dag.app.dag.DAGState;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class TestTezData {
+ @Test
+ public void testTezAnalyticJobEquals() {
+ TezAnalyticJob job1 = new TezAnalyticJob("id", "name", 0L, 1L, YarnApplicationState.RUNNING);
+ TezAnalyticJob job2 = new TezAnalyticJob("id", "name", 0L, 1L, YarnApplicationState.RUNNING);
+ TezAnalyticJob job3 = new TezAnalyticJob("no", "nn", 0L, 1L, YarnApplicationState.RUNNING);
+ SparkRestAnalyticJob restJob = new SparkRestAnalyticJob("id");
+
+ assertTrue(job1.equals(job1));
+ assertTrue(job1.equals(job2));
+ assertFalse(job1.equals(job3));
+ assertFalse(job1.equals(restJob));
+ }
+
+ @Test
+ public void testTezDagIdEquals() {
+ TezDagIdData data1 = new TezDagIdData("id", 0L, 1L, 1L, DAGState.SUCCEEDED);
+ TezDagIdData data2 = new TezDagIdData("id", 0L, 1L, 1L, DAGState.SUCCEEDED);
+ TezDagIdData data3 = new TezDagIdData("id2", 0L, 1L, 1L, DAGState.SUCCEEDED);
+ TezAnalyticJob job = new TezAnalyticJob("id", "name", 0L, 1L, YarnApplicationState.RUNNING);
+
+ assertEquals(data1, data1);
+ assertEquals(data1, data2);
+ assertFalse(data1.equals(data3));
+ assertFalse(data1.equals(job));
+ }
+
+ @Test
+ public void testTezDatIdCompare() {
+ TezDagIdData data1 = new TezDagIdData("id1", 0L, 1L, 1L, DAGState.SUCCEEDED);
+ TezDagIdData data2 = new TezDagIdData("id2", 0L, 2L, 2L, DAGState.SUCCEEDED);
+ assertEquals(0, data1.compareTo(data2));
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestJsonUtils.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestJsonUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..95aab125c8f418c91681bba03a41934f32ccd735
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestJsonUtils.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import com.sun.jersey.api.client.ClientHandlerException;
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.MalformedURLException;
+
+public class TestJsonUtils {
+ private static TezJsonUtils testJsonUtils;
+
+ @BeforeClass
+ public static void setUpClass() {
+ testJsonUtils = new TezJsonUtils(new TezUrlFactory("http://localhost:9999"), false, 10);
+ }
+
+ @Test(expected = ConnectException.class)
+ public void testVerifyTimeLineServer() throws IOException {
+ testJsonUtils.verifyTimeLineServer();
+ }
+
+ @Test(expected = ClientHandlerException.class)
+ public void testGetApplicationJobs() throws AuthenticationException, IOException {
+ testJsonUtils.getApplicationJobs(0L, 1000L);
+ }
+
+ @Test(expected = ClientHandlerException.class)
+ public void testGetDAGIDs() throws MalformedURLException {
+ testJsonUtils.getDAGIds("appId");
+ }
+
+ @Test(expected = ClientHandlerException.class)
+ public void testGetConfigure() throws MalformedURLException {
+ testJsonUtils.getConfigure("appId");
+ }
+
+ @Test(expected = ClientHandlerException.class)
+ public void testGetQueryString() throws MalformedURLException {
+ testJsonUtils.getQueryString("appId");
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestJsonUtilsFactory.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestJsonUtilsFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1d046503db130e5e1cb2fe14332d47750713bf6
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestJsonUtilsFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.FAILED;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.FAILED_DAG;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.KILLED;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.KILLED_DAG;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.SUCCESS;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.SUCCESS_DAG;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.TEST_APP_LIST;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.TEST_TEZ_CONFIGURE;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.TEST_TEZ_QUERY;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.TIME_14;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.TIME_18;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.UNFINISHED;
+import static com.huawei.boostkit.omniadvisor.tez.utils.TestTezContext.UNFINISHED_DAG;
+
+public class TestJsonUtilsFactory {
+ public static TezJsonUtils getAppListJsonUtils() throws AuthenticationException, IOException {
+ TezJsonUtils tezJsonUtils = Mockito.mock(TezJsonUtils.class);
+ Mockito.when(tezJsonUtils.getApplicationJobs(TIME_14, TIME_18)).thenReturn(TEST_APP_LIST);
+ return tezJsonUtils;
+ }
+
+ public static TezJsonUtils getSuccessJsonUtils() throws MalformedURLException {
+ TezJsonUtils successJsonUtils = Mockito.mock(TezJsonUtils.class);
+ Mockito.when(successJsonUtils.getDAGIds(SUCCESS)).thenReturn(ImmutableList.of(SUCCESS_DAG));
+ Mockito.when(successJsonUtils.getConfigure(SUCCESS)).thenReturn(TEST_TEZ_CONFIGURE);
+ Mockito.when(successJsonUtils.getQueryString(SUCCESS)).thenReturn(TEST_TEZ_QUERY);
+ return successJsonUtils;
+ }
+
+ public static TezJsonUtils getFailedJsonUtils() throws MalformedURLException {
+ TezJsonUtils failedJsonUtils = Mockito.mock(TezJsonUtils.class);
+ Mockito.when(failedJsonUtils.getDAGIds(FAILED)).thenReturn(ImmutableList.of(FAILED_DAG));
+ Mockito.when(failedJsonUtils.getConfigure(FAILED)).thenReturn(TEST_TEZ_CONFIGURE);
+ Mockito.when(failedJsonUtils.getQueryString(FAILED)).thenReturn(TEST_TEZ_QUERY);
+ return failedJsonUtils;
+ }
+
+ public static TezJsonUtils getKilledJsonUtils() throws MalformedURLException {
+ TezJsonUtils killedJsonUtils = Mockito.mock(TezJsonUtils.class);
+ Mockito.when(killedJsonUtils.getDAGIds(KILLED)).thenReturn(ImmutableList.of(KILLED_DAG));
+ Mockito.when(killedJsonUtils.getConfigure(KILLED)).thenReturn(TEST_TEZ_CONFIGURE);
+ Mockito.when(killedJsonUtils.getQueryString(KILLED)).thenReturn(TEST_TEZ_QUERY);
+ return killedJsonUtils;
+ }
+
+ public static TezJsonUtils getUnFinishedJsonUtils() throws MalformedURLException {
+ TezJsonUtils unFinishedJsonUtils = Mockito.mock(TezJsonUtils.class);
+ Mockito.when(unFinishedJsonUtils.getDAGIds(UNFINISHED)).thenReturn(ImmutableList.of(UNFINISHED_DAG));
+ Mockito.when(unFinishedJsonUtils.getConfigure(UNFINISHED)).thenReturn(TEST_TEZ_CONFIGURE);
+ Mockito.when(unFinishedJsonUtils.getQueryString(UNFINISHED)).thenReturn(TEST_TEZ_QUERY);
+ return unFinishedJsonUtils;
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTezClient.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTezClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..3be61a4cc05d71115cd76481ce501e8d0b627645
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTezClient.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+import java.net.URL;
+
+import static org.mockito.Mockito.when;
+
+public class TestTezClient {
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private static final String TEST_APP_STRING =
+ "{" +
+ "\"app\":[" +
+ "{" +
+ "\"appId\":\"application_test\"," +
+ "\"name\":\"sql_test\"," +
+ "\"appState\":\"FINISHED\"" +
+ "}" +
+ "]" +
+ "}";
+
+ private static final String TEST_APP_INFO =
+ "{" +
+ "\"entitytype\":\"TEZ_APPLICATION\"," +
+ "\"otherinfo\":{" +
+ "\"config\":{" +
+ "\"tez.am.resource.memory.mb\":1024," +
+ "\"tez.am.resource.cpu.vcores\":5," +
+ "\"tez.task.resource.memory.mb\":1024," +
+ "\"tez.task.reource.cpu.vcores\":5" +
+ "}" +
+ "}" +
+ "}";
+
+ private static final String TEST_DAG_INFO =
+ "{" +
+ "\"entities\":[" +
+ "{" +
+ "\"entitytype\":\"TEZ_DAG_ID\"," +
+ "\"entity\":\"dag_test_1\"," +
+ "\"otherinfo\":{" +
+ "\"startTime\":0," +
+ "\"timeTaken\":100," +
+ "\"endTime\":100," +
+ "\"status\":\"SUCCEEDED\"" +
+ "}" +
+ "}" +
+ "]" +
+ "}";
+
+ private static final String TEST_DAG_EXTRA_INFO =
+ "{" +
+ "\"entitytype\":\"TEZ_DAG_EXTRA_INFO\"," +
+ "\"otherinfo\":{" +
+ "\"dagPlan\":{" +
+ "\"dagContext\":{" +
+ "\"description\":\"select * from table\"" +
+ "}" +
+ "}" +
+ "}" +
+ "}";
+
+ public static TimelineClient getTestTimelineClient() throws IOException {
+ TimelineClient testClient = Mockito.mock(TimelineClient.class);
+ when(testClient.readJsonNode(new URL("http://testUrl:8188/ws/v1/applicationhistory/apps?applicationTypes=TEZ&startedTimeBegin=0&startedTimeEnd=100")))
+ .thenReturn(MAPPER.readTree(TEST_APP_STRING));
+ when(testClient.readJsonNode(new URL("http://testUrl:8188/ws/v1/timeline/TEZ_APPLICATION/tez_test")))
+ .thenReturn(MAPPER.readTree(TEST_APP_INFO));
+ when(testClient.readJsonNode(new URL("http://testUrl:8188/ws/v1/timeline/TEZ_DAG_ID?primaryFilter=applicationId:test")))
+ .thenReturn(MAPPER.readTree(TEST_DAG_INFO));
+ when((testClient.readJsonNode(new URL("http://testUrl:8188/ws/v1/timeline/TEZ_DAG_EXTRA_INFO/dag_test_1"))))
+ .thenReturn(MAPPER.readTree(TEST_DAG_EXTRA_INFO));
+ return testClient;
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTezContext.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTezContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..25526b18fff384a699fe25f9606bedfee38c553f
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTezContext.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableList;
+import com.huawei.boostkit.omniadvisor.analysis.AnalyticJob;
+import com.huawei.boostkit.omniadvisor.exception.OmniAdvisorException;
+import com.huawei.boostkit.omniadvisor.tez.data.TezAnalyticJob;
+import com.huawei.boostkit.omniadvisor.tez.data.TezDagIdData;
+import com.huawei.boostkit.omniadvisor.utils.MathUtils;
+import org.apache.hadoop.yarn.api.records.YarnApplicationState;
+import org.apache.tez.dag.app.dag.DAGState;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Map;
+
+public class TestTezContext {
+ public static final SimpleDateFormat DF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ public static final String DATE_14 = "2023-09-02 14:00:00";
+ public static final String DATE_15 = "2023-09-02 15:00:00";
+ public static final String DATE_16 = "2023-09-02 16:00:00";
+ public static final String DATE_17 = "2023-09-02 17:00:00";
+ public static final String DATE_18 = "2023-09-02 18:00:00";
+
+ public static final long TIME_14;
+ public static final long TIME_15;
+ public static final long TIME_16;
+ public static final long TIME_17;
+ public static final long TIME_18;
+
+ static {
+ try {
+ TIME_14 = DF.parse(DATE_14).getTime();
+ TIME_15 = DF.parse(DATE_15).getTime();
+ TIME_16 = DF.parse(DATE_16).getTime();
+ TIME_17 = DF.parse(DATE_17).getTime();
+ TIME_18 = DF.parse(DATE_18).getTime();
+ } catch (ParseException e) {
+ throw new OmniAdvisorException("Parse time failed", e);
+ }
+ }
+
+ public static final String SUCCESS = "success";
+ public static final String FAILED = "failed";
+ public static final String KILLED = "killed";
+ public static final String UNFINISHED = "UNFINISHED";
+
+ public static final AnalyticJob SUCCESS_JOB =
+ new TezAnalyticJob(SUCCESS, SUCCESS, TIME_14, TIME_15, YarnApplicationState.FINISHED);
+ public static final AnalyticJob FAILED_JOB =
+ new TezAnalyticJob(FAILED, FAILED, TIME_15, TIME_16, YarnApplicationState.FINISHED);
+ public static final AnalyticJob KILLED_JOB =
+ new TezAnalyticJob(KILLED, KILLED, TIME_16, TIME_17, YarnApplicationState.KILLED);
+ public static final AnalyticJob UNFINISHED_JOB =
+ new TezAnalyticJob(UNFINISHED, UNFINISHED, TIME_17, TIME_18, YarnApplicationState.RUNNING);
+
+ public static final TezDagIdData SUCCESS_DAG =
+ new TezDagIdData(SUCCESS, TIME_14, TIME_15, MathUtils.HOUR_IN_MS, DAGState.SUCCEEDED);
+ public static final TezDagIdData FAILED_DAG =
+ new TezDagIdData(FAILED, TIME_15, TIME_16, MathUtils.HOUR_IN_MS, DAGState.FAILED);
+ public static final TezDagIdData KILLED_DAG =
+ new TezDagIdData(KILLED, TIME_16, TIME_17, MathUtils.HOUR_IN_MS, DAGState.RUNNING);
+ public static final TezDagIdData UNFINISHED_DAG =
+ new TezDagIdData(UNFINISHED, TIME_17, TIME_18, MathUtils.HOUR_IN_MS, DAGState.RUNNING);
+
+ public static final List TEST_APP_LIST =
+ ImmutableList.of(SUCCESS_JOB, FAILED_JOB, KILLED_JOB, UNFINISHED_JOB);
+
+ public static final String TEST_TEZ_QUERY = "select id, name from table";
+
+ public static final Map TEST_TEZ_CONFIGURE = ImmutableBiMap.of(
+ "tez.am.resource.memory.mb", "200", "tez.am.resource.cpu.vcores", "2",
+ "tez.task.resource.memory.mb", "300", "tez.task.resource.cpu.vcores", "4");
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTimelineClient.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTimelineClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6624f38a0064fc53018e03b5df8c7df728142b8
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestTimelineClient.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import org.apache.hadoop.conf.Configuration;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+public class TestTimelineClient {
+ @Test
+ public void testReadJsonNode() throws MalformedURLException, JSONException {
+ try (TimelineClient timelineClient = new TimelineClient(new Configuration(), false, 6000)) {
+ String testUrl = "http://test-url:8188/test";
+
+ ClientResponse response = Mockito.mock(ClientResponse.class);
+ when(response.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
+ JSONObject jsonObject = new JSONObject("{\"name\" : \"test\"}");
+ when(response.getEntity(JSONObject.class)).thenReturn(jsonObject);
+ WebResource resource = Mockito.mock(WebResource.class);
+ WebResource.Builder builder = Mockito.mock(WebResource.Builder.class);
+ when(resource.accept(MediaType.APPLICATION_JSON_TYPE)).thenReturn(builder);
+ when(builder.type(MediaType.APPLICATION_JSON_TYPE)).thenReturn(builder);
+ when(builder.get(ClientResponse.class)).thenReturn(response);
+
+ Client httpClient = Mockito.mock(Client.class);
+ when(httpClient.resource(testUrl)).thenReturn(resource);
+ timelineClient.setClient(httpClient);
+ JsonNode object = timelineClient.readJsonNode(new URL(testUrl));
+ assertEquals(object.get("name").getTextValue(), "test");
+ }
+ }
+}
diff --git a/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestUrlFactory.java b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestUrlFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f5be00489f7c48eaedcd1f5eb2fbf4def04e849
--- /dev/null
+++ b/omniadvisor/src/test/java/com/huawei/boostkit/omniadvisor/tez/utils/TestUrlFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.huawei.boostkit.omniadvisor.tez.utils;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.net.MalformedURLException;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestUrlFactory {
+ private static final String BASE_URL = "http://localhost:8088";
+ private static TezUrlFactory urlFactory;
+
+ @BeforeClass
+ public static void setUpClass() {
+ urlFactory = new TezUrlFactory(BASE_URL);
+ }
+
+ @Test
+ public void testGetRootURL() throws MalformedURLException {
+ assertEquals(urlFactory.getRootURL().toString(), "http://localhost:8088/ws/v1/timeline");
+ }
+
+ @Test
+ public void testGetApplicationURL() throws MalformedURLException {
+ assertEquals(urlFactory.getApplicationURL("appId").toString(),
+ "http://localhost:8088/ws/v1/timeline/TEZ_APPLICATION/tez_appId");
+ }
+
+ @Test
+ public void testGetDagIdURL() throws MalformedURLException {
+ assertEquals(urlFactory.getDagIdURL("appId").toString(),
+ "http://localhost:8088/ws/v1/timeline/TEZ_DAG_ID?primaryFilter=applicationId:appId");
+ }
+
+ @Test
+ public void testGetDagExtraInfoURL() throws MalformedURLException {
+ assertEquals(urlFactory.getDagExtraInfoURL("dagId").toString(),
+ "http://localhost:8088/ws/v1/timeline/TEZ_DAG_EXTRA_INFO/dagId");
+ }
+
+ @Test
+ public void testGetApplicationHistoryURL() throws MalformedURLException {
+ assertEquals(urlFactory.getApplicationHistoryURL(0L, 1L).toString(),
+ "http://localhost:8088/ws/v1/applicationhistory/apps?applicationTypes=TEZ&startedTimeBegin=0&startedTimeEnd=1");
+ }
+}
diff --git a/omniadvisor/src/test/java/org/apache/spark/TestSparkApplicationDataExtractor.java b/omniadvisor/src/test/java/org/apache/spark/TestSparkApplicationDataExtractor.java
new file mode 100644
index 0000000000000000000000000000000000000000..b60bf8455022f2cd3d6700cef019ad02867b3aea
--- /dev/null
+++ b/omniadvisor/src/test/java/org/apache/spark/TestSparkApplicationDataExtractor.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020-2023. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark;
+
+import com.google.common.collect.ImmutableList;
+import com.huawei.boostkit.omniadvisor.models.AppResult;
+import org.apache.spark.status.api.v1.ApplicationAttemptInfo;
+import org.apache.spark.status.api.v1.ApplicationEnvironmentInfo;
+import org.apache.spark.status.api.v1.ApplicationInfo;
+import org.apache.spark.status.api.v1.JobData;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import scala.Option;
+import scala.Tuple2;
+import scala.collection.immutable.HashMap;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+import static scala.collection.JavaConverters.asScalaBuffer;
+
+public class TestSparkApplicationDataExtractor {
+ private static final String TEST_WORK_LOAD = "default";
+
+ private static ApplicationEnvironmentInfo environmentInfo;
+ private static ApplicationAttemptInfo completeAttemptInfo;
+ private static ApplicationAttemptInfo unCompleteAttemptInfo;
+
+ private static JobData jobData;
+ private static JobData failedData;
+ private static JobData runningData;
+
+ @BeforeClass
+ public static void setUp() throws ParseException {
+ List> configs = ImmutableList.of(
+ new Tuple2<>("spark.executor.memory", "1g"),
+ new Tuple2<>("spark.executor.cores", "1"),
+ new Tuple2<>("spark.executor.instances", "1"));
+ environmentInfo = Mockito.mock(ApplicationEnvironmentInfo.class);
+ when(environmentInfo.sparkProperties()).thenReturn(asScalaBuffer(configs));
+
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
+ Date startDate = format.parse("2020-05-01 18:00:00");
+ Date endDate = format.parse("2020-05-01 18:00:01");
+
+ completeAttemptInfo = new ApplicationAttemptInfo(Option.apply("attemptId"), startDate, endDate, endDate, 1000L, "user", true, "3.1.1");
+ unCompleteAttemptInfo = new ApplicationAttemptInfo(Option.apply("attemptId"), startDate, endDate, endDate, 1000L, "user", false, "3.1.1");
+
+ jobData = new JobData(1, "jobName", Option.empty(), Option.empty(), Option.empty(), asScalaBuffer(ImmutableList.of()), Option.empty(), JobExecutionStatus.SUCCEEDED, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, new HashMap<>());
+ failedData = new JobData(1, "jobName", Option.empty(), Option.empty(), Option.empty(), asScalaBuffer(ImmutableList.of()), Option.empty(), JobExecutionStatus.FAILED, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, new HashMap<>());
+ runningData = new JobData(1, "jobName", Option.empty(), Option.empty(), Option.empty(), asScalaBuffer(ImmutableList.of()), Option.empty(), JobExecutionStatus.RUNNING, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, new HashMap<>());
+ }
+
+ @Test
+ public void testExtractData() {
+ ApplicationInfo applicationInfo = new ApplicationInfo("id", "name", Option.empty(), Option.empty(), Option.empty(), Option.empty(), asScalaBuffer(ImmutableList.of(completeAttemptInfo)));
+ AppResult result = SparkApplicationDataExtractor.extractAppResultFromAppStatusStore(applicationInfo, TEST_WORK_LOAD, environmentInfo, asScalaBuffer(ImmutableList.of(jobData)));
+ assertEquals(result.applicationId, "id");
+ assertEquals(result.executionStatus, AppResult.SUCCEEDED_STATUS);
+ assertEquals(result.durationTime, 1000L);
+ }
+
+ @Test
+ public void testExtractDataWithUnCompleteApplication() {
+ ApplicationInfo applicationInfo = new ApplicationInfo("id", "name", Option.empty(), Option.empty(), Option.empty(), Option.empty(), asScalaBuffer(ImmutableList.of(unCompleteAttemptInfo)));
+ AppResult result = SparkApplicationDataExtractor.extractAppResultFromAppStatusStore(applicationInfo, TEST_WORK_LOAD, environmentInfo, asScalaBuffer(ImmutableList.of(runningData)));
+ assertEquals(result.applicationId, "id");
+ assertEquals(result.executionStatus, AppResult.FAILED_STATUS);
+ assertEquals(result.durationTime, AppResult.FAILED_JOB_DURATION);
+ }
+
+ @Test
+ public void testExtractDataWithFailedApplication() {
+ ApplicationInfo applicationInfo = new ApplicationInfo("id", "name", Option.empty(), Option.empty(), Option.empty(), Option.empty(), asScalaBuffer(ImmutableList.of(completeAttemptInfo)));
+ AppResult result = SparkApplicationDataExtractor.extractAppResultFromAppStatusStore(applicationInfo, TEST_WORK_LOAD, environmentInfo, asScalaBuffer(ImmutableList.of(failedData)));
+ assertEquals(result.applicationId, "id");
+ assertEquals(result.executionStatus, AppResult.FAILED_STATUS);
+ assertEquals(result.durationTime, AppResult.FAILED_JOB_DURATION);
+ }
+
+ @Test
+ public void testExtractDataWithEmptyJob() {
+ ApplicationInfo applicationInfo = new ApplicationInfo("id", "name", Option.empty(), Option.empty(), Option.empty(), Option.empty(), asScalaBuffer(ImmutableList.of(completeAttemptInfo)));
+ AppResult result = SparkApplicationDataExtractor.extractAppResultFromAppStatusStore(applicationInfo, TEST_WORK_LOAD, environmentInfo, asScalaBuffer(ImmutableList.of()));
+ assertEquals(result.applicationId, "id");
+ assertEquals(result.executionStatus, AppResult.FAILED_STATUS);
+ assertEquals(result.durationTime, AppResult.FAILED_JOB_DURATION);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testExtractDataWithEmptyApplication() {
+ ApplicationInfo applicationInfo = new ApplicationInfo("id", "name", Option.empty(), Option.empty(), Option.empty(), Option.empty(), asScalaBuffer(ImmutableList.of()));
+ SparkApplicationDataExtractor.extractAppResultFromAppStatusStore(applicationInfo, TEST_WORK_LOAD, environmentInfo, asScalaBuffer(ImmutableList.of()));
+ }
+}
diff --git a/omniadvisor/src/test/resources/SparkParams b/omniadvisor/src/test/resources/SparkParams
new file mode 100644
index 0000000000000000000000000000000000000000..f90561fd88b1e9e81f07d18483e1801935961e38
--- /dev/null
+++ b/omniadvisor/src/test/resources/SparkParams
@@ -0,0 +1,3 @@
+spark.executor.memory
+spark.executor.cores
+spark.executor.instances
diff --git a/omniadvisor/src/test/resources/TezParams b/omniadvisor/src/test/resources/TezParams
new file mode 100644
index 0000000000000000000000000000000000000000..7a42fcc60d453a92972da6b325c6c39cef2d8125
--- /dev/null
+++ b/omniadvisor/src/test/resources/TezParams
@@ -0,0 +1,4 @@
+tez.am.resource.memory.mb
+tez.am.resource.cpu.vcores
+tez.task.resource.memory.mb
+tez.task.resource.cpu.vcores
\ No newline at end of file
diff --git a/omniadvisor/src/test/resources/omniAdvisorLogAnalyzer.properties b/omniadvisor/src/test/resources/omniAdvisorLogAnalyzer.properties
new file mode 100644
index 0000000000000000000000000000000000000000..575cc4581c16db075263cd1cd8e1871626474c3b
--- /dev/null
+++ b/omniadvisor/src/test/resources/omniAdvisorLogAnalyzer.properties
@@ -0,0 +1,11 @@
+log.analyzer.thread.count=3
+
+datasource.db.driver=com.mysql.cj.jdbc.Driver
+datasource.db.url=url
+
+spark.enable=false
+
+tez.enable=true
+tez.workload=workload
+tez.timeline.url=http://testUrl:8188
+tez.timeline.timeout.ms=6000
diff --git a/omniadvisor/src/test/resources/spark-events/application_1516285256255_0012 b/omniadvisor/src/test/resources/spark-events/application_1516285256255_0012
new file mode 100644
index 0000000000000000000000000000000000000000..3e1736c3fe22494c5a4054e2473473cd2301a779
--- /dev/null
+++ b/omniadvisor/src/test/resources/spark-events/application_1516285256255_0012
@@ -0,0 +1,71 @@
+{"Event":"SparkListenerLogStart","Spark Version":"2.3.0-SNAPSHOT"}
+{"Event":"SparkListenerEnvironmentUpdate","JVM Information":{"Java Home":"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre","Java Version":"1.8.0_161 (Oracle Corporation)","Scala Version":"version 2.11.8"},"Spark Properties":{"spark.blacklist.enabled":"true","spark.driver.host":"apiros-1.gce.test.com","spark.eventLog.enabled":"true","spark.driver.port":"33058","spark.repl.class.uri":"spark://apiros-1.gce.test.com:33058/classes","spark.jars":"","spark.repl.class.outputDir":"/tmp/spark-6781fb17-e07a-4b32-848b-9936c2e88b33/repl-c0fd7008-04be-471e-a173-6ad3e62d53d7","spark.app.name":"Spark shell","spark.blacklist.stage.maxFailedExecutorsPerNode":"1","spark.scheduler.mode":"FIFO","spark.executor.instances":"8","spark.ui.showConsoleProgress":"true","spark.blacklist.stage.maxFailedTasksPerExecutor":"1","spark.executor.id":"driver","spark.submit.deployMode":"client","spark.master":"yarn","spark.ui.filters":"org.apache.hadoop.yarn.server.webproxy.amfilter.AmIpFilter","spark.executor.memory":"2G","spark.home":"/github/spark","spark.sql.catalogImplementation":"hive","spark.driver.appUIAddress":"http://apiros-1.gce.test.com:4040","spark.blacklist.application.maxFailedTasksPerExecutor":"10","spark.org.apache.hadoop.yarn.server.webproxy.amfilter.AmIpFilter.param.PROXY_HOSTS":"apiros-1.gce.test.com","spark.org.apache.hadoop.yarn.server.webproxy.amfilter.AmIpFilter.param.PROXY_URI_BASES":"http://apiros-1.gce.test.com:8088/proxy/application_1516285256255_0012","spark.app.id":"application_1516285256255_0012"},"System Properties":{"java.io.tmpdir":"/tmp","line.separator":"\n","path.separator":":","sun.management.compiler":"HotSpot 64-Bit Tiered Compilers","SPARK_SUBMIT":"true","sun.cpu.endian":"little","java.specification.version":"1.8","java.vm.specification.name":"Java Virtual Machine Specification","java.vendor":"Oracle Corporation","java.vm.specification.version":"1.8","user.home":"*********(redacted)","file.encoding.pkg":"sun.io","sun.nio.ch.bugLevel":"","sun.arch.data.model":"64","sun.boot.library.path":"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/amd64","user.dir":"*********(redacted)","java.library.path":"/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib","sun.cpu.isalist":"","os.arch":"amd64","java.vm.version":"25.161-b14","java.endorsed.dirs":"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/endorsed","java.runtime.version":"1.8.0_161-b14","java.vm.info":"mixed mode","java.ext.dirs":"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/ext:/usr/java/packages/lib/ext","java.runtime.name":"OpenJDK Runtime Environment","file.separator":"/","java.class.version":"52.0","scala.usejavacp":"true","java.specification.name":"Java Platform API Specification","sun.boot.class.path":"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/resources.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/rt.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/sunrsasign.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/jsse.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/jce.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/charsets.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/lib/jfr.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre/classes","file.encoding":"UTF-8","user.timezone":"*********(redacted)","java.specification.vendor":"Oracle Corporation","sun.java.launcher":"SUN_STANDARD","os.version":"3.10.0-693.5.2.el7.x86_64","sun.os.patch.level":"unknown","java.vm.specification.vendor":"Oracle Corporation","user.country":"*********(redacted)","sun.jnu.encoding":"UTF-8","user.language":"*********(redacted)","java.vendor.url":"*********(redacted)","java.awt.printerjob":"sun.print.PSPrinterJob","java.awt.graphicsenv":"sun.awt.X11GraphicsEnvironment","awt.toolkit":"sun.awt.X11.XToolkit","os.name":"Linux","java.vm.vendor":"Oracle Corporation","java.vendor.url.bug":"*********(redacted)","user.name":"*********(redacted)","java.vm.name":"OpenJDK 64-Bit Server VM","sun.java.command":"org.apache.spark.deploy.SparkSubmit --master yarn --deploy-mode client --conf spark.blacklist.stage.maxFailedTasksPerExecutor=1 --conf spark.blacklist.enabled=true --conf spark.blacklist.application.maxFailedTasksPerExecutor=10 --conf spark.blacklist.stage.maxFailedExecutorsPerNode=1 --conf spark.eventLog.enabled=true --class org.apache.spark.repl.Main --name Spark shell --executor-memory 2G --num-executors 8 spark-shell","java.home":"/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre","java.version":"1.8.0_161","sun.io.unicode.encoding":"UnicodeLittle"},"Classpath Entries":{"/github/spark/assembly/target/scala-2.11/jars/validation-api-1.1.0.Final.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/arrow-vector-0.8.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-io-2.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/javax.servlet-api-3.1.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-hive_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/scala-parser-combinators_2.11-1.0.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/stax-api-1.0-2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/json4s-ast_2.11-3.2.11.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/apache-log4j-extras-1.2.17.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hive-metastore-1.2.1.spark2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/avro-1.7.7.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/core-1.1.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jersey-common-2.22.2.jar":"System Classpath","/github/spark/conf/":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/metrics-json-3.1.5.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/protobuf-java-2.5.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/aircompressor-0.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/stax-api-1.0.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/leveldbjni-all-1.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/snappy-java-1.1.2.6.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/curator-recipes-2.7.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jersey-container-servlet-core-2.22.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/arrow-format-0.8.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/ivy-2.4.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/libthrift-0.9.3.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-lang-2.6.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-sketch_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-tags_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-yarn-common-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/slf4j-api-1.7.16.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jersey-server-2.22.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/stringtemplate-3.2.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/pyrolite-4.13.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-crypto-1.0.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/datanucleus-api-jdo-3.2.6.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-net-2.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-annotations-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/orc-core-1.4.1-nohive.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spire_2.11-0.13.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/arrow-memory-0.8.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/log4j-1.2.17.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-core-asl-1.9.13.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/scalap-2.11.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/scala-xml_2.11-1.0.5.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/JavaEWAH-0.3.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/bcprov-jdk15on-1.58.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/scala-reflect-2.11.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-sql_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/javolution-5.5.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/libfb303-0.9.3.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jersey-media-jaxb-2.22.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jodd-core-3.5.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/janino-3.0.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-unsafe_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/antlr4-runtime-4.7.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/snappy-0.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/guice-3.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/java-xmlbuilder-1.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/chill_2.11-0.8.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/apacheds-kerberos-codec-2.0.0-M15.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/stream-2.7.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/ST4-4.0.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/datanucleus-core-3.2.10.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-yarn-api-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/guice-servlet-3.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/avro-mapred-1.7.7-hadoop2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hive-exec-1.2.1.spark2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-beanutils-1.7.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jetty-6.1.26.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-yarn-server-common-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-configuration-1.6.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/minlog-1.3.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/base64-2.3.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/slf4j-log4j12-1.7.16.jar":"System Classpath","/etc/hadoop/conf/":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-httpclient-3.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-mapper-asl-1.9.13.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-yarn_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-repl_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spire-macros_2.11-0.13.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-client-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-jaxrs-1.9.13.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/apacheds-i18n-2.0.0-M15.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-cli-1.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/javax.annotation-api-1.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/lz4-java-1.4.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-mllib-local_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-compress-1.4.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/breeze-macros_2.11-0.13.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-module-scala_2.11-2.6.7.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/curator-framework-2.7.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/curator-client-2.7.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/netty-3.9.9.Final.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/calcite-avatica-1.2.0-incubating.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-annotations-2.6.7.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/machinist_2.11-0.6.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jaxb-api-2.2.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/api-asn1-api-1.0.0-M20.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/calcite-linq4j-1.2.0-incubating.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-network-common_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-auth-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/orc-mapreduce-1.4.1-nohive.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-common-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-mapreduce-client-common-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/xercesImpl-2.9.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hppc-0.7.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-beanutils-core-1.8.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-math3-3.4.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-core_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/scala-library-2.11.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jersey-container-servlet-2.22.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-mapreduce-client-app-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/parquet-hadoop-1.8.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-catalyst_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/metrics-jvm-3.1.5.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/scala-compiler-2.11.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/objenesis-2.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/shapeless_2.11-2.3.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/activation-1.1.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/py4j-0.10.6.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-mapreduce-client-core-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/zookeeper-3.4.6.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/parquet-hadoop-bundle-1.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/antlr-runtime-3.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-mllib_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/oro-2.0.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/eigenbase-properties-1.1.5.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-graphx_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hk2-locator-2.4.0-b34.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/javax.ws.rs-api-2.0.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/aopalliance-repackaged-2.4.0-b34.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-network-shuffle_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/parquet-format-2.3.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-launcher_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-mapreduce-client-shuffle-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/paranamer-2.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jta-1.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/derby-10.12.1.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/xz-1.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-yarn-client-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-logging-1.1.3.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-pool-1.5.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-streaming_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/javassist-3.18.1-GA.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/guava-14.0.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/xmlenc-0.52.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/htrace-core-3.0.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/javax.inject-2.4.0-b34.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/httpclient-4.5.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-databind-2.6.7.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/parquet-column-1.8.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/zstd-jni-1.3.2-2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-yarn-server-web-proxy-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/spark-kvstore_2.11-2.3.0-SNAPSHOT.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/parquet-encoding-1.8.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/univocity-parsers-2.5.9.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/compress-lzf-1.0.3.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-collections-3.2.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-mapreduce-client-jobclient-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/osgi-resource-locator-1.0.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jersey-client-2.22.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/chill-java-0.8.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/avro-ipc-1.7.7.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/antlr-2.7.7.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hk2-utils-2.4.0-b34.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/RoaringBitmap-0.5.11.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jul-to-slf4j-1.7.16.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/xbean-asm5-shaded-4.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/datanucleus-rdbms-3.2.9.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/arpack_combined_all-0.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hk2-api-2.4.0-b34.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/metrics-graphite-3.1.5.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/parquet-common-1.8.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/hadoop-hdfs-2.6.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/javax.inject-1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/opencsv-2.3.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/api-util-1.0.0-M20.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jdo-api-3.0.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-module-paranamer-2.7.9.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/kryo-shaded-3.0.3.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-dbcp-1.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/netty-all-4.1.17.Final.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/parquet-jackson-1.8.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/gson-2.2.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/calcite-core-1.2.0-incubating.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/macro-compat_2.11-1.1.1.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/flatbuffers-1.2.0-3f79e055.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/json4s-core_2.11-3.2.11.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/breeze_2.11-0.13.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-digester-1.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jsr305-1.3.9.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jtransforms-2.4.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jets3t-0.9.4.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-core-2.6.7.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jackson-xc-1.9.13.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/aopalliance-1.0.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/bonecp-0.8.0.RELEASE.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jetty-util-6.1.26.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/joda-time-2.9.3.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/json4s-jackson_2.11-3.2.11.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/metrics-core-3.1.5.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jcl-over-slf4j-1.7.16.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/httpcore-4.4.8.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-lang3-3.5.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/jersey-guava-2.22.2.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-codec-1.10.jar":"System Classpath","/github/spark/assembly/target/scala-2.11/jars/commons-compiler-3.0.8.jar":"System Classpath"}}
+{"Event":"SparkListenerApplicationStart","App Name":"Spark shell","App ID":"application_1516285256255_0012","Timestamp":1516300235119,"User":"attilapiros"}
+{"Event":"SparkListenerExecutorAdded","Timestamp":1516300252095,"Executor ID":"2","Executor Info":{"Host":"apiros-3.gce.test.com","Total Cores":1,"Log Urls":{"stdout":"http://apiros-3.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000003/attilapiros/stdout?start=-4096","stderr":"http://apiros-3.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000003/attilapiros/stderr?start=-4096"}}}
+{"Event":"SparkListenerBlockManagerAdded","Block Manager ID":{"Executor ID":"2","Host":"apiros-3.gce.test.com","Port":38670},"Maximum Memory":956615884,"Timestamp":1516300252260,"Maximum Onheap Memory":956615884,"Maximum Offheap Memory":0}
+{"Event":"SparkListenerExecutorAdded","Timestamp":1516300252715,"Executor ID":"3","Executor Info":{"Host":"apiros-2.gce.test.com","Total Cores":1,"Log Urls":{"stdout":"http://apiros-2.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000004/attilapiros/stdout?start=-4096","stderr":"http://apiros-2.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000004/attilapiros/stderr?start=-4096"}}}
+{"Event":"SparkListenerExecutorAdded","Timestamp":1516300252918,"Executor ID":"1","Executor Info":{"Host":"apiros-3.gce.test.com","Total Cores":1,"Log Urls":{"stdout":"http://apiros-3.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000002/attilapiros/stdout?start=-4096","stderr":"http://apiros-3.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000002/attilapiros/stderr?start=-4096"}}}
+{"Event":"SparkListenerBlockManagerAdded","Block Manager ID":{"Executor ID":"3","Host":"apiros-2.gce.test.com","Port":38641},"Maximum Memory":956615884,"Timestamp":1516300252959,"Maximum Onheap Memory":956615884,"Maximum Offheap Memory":0}
+{"Event":"SparkListenerBlockManagerAdded","Block Manager ID":{"Executor ID":"1","Host":"apiros-3.gce.test.com","Port":34970},"Maximum Memory":956615884,"Timestamp":1516300252988,"Maximum Onheap Memory":956615884,"Maximum Offheap Memory":0}
+{"Event":"SparkListenerExecutorAdded","Timestamp":1516300253542,"Executor ID":"4","Executor Info":{"Host":"apiros-2.gce.test.com","Total Cores":1,"Log Urls":{"stdout":"http://apiros-2.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000005/attilapiros/stdout?start=-4096","stderr":"http://apiros-2.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000005/attilapiros/stderr?start=-4096"}}}
+{"Event":"SparkListenerBlockManagerAdded","Block Manager ID":{"Executor ID":"4","Host":"apiros-2.gce.test.com","Port":33229},"Maximum Memory":956615884,"Timestamp":1516300253653,"Maximum Onheap Memory":956615884,"Maximum Offheap Memory":0}
+{"Event":"SparkListenerExecutorAdded","Timestamp":1516300254323,"Executor ID":"5","Executor Info":{"Host":"apiros-2.gce.test.com","Total Cores":1,"Log Urls":{"stdout":"http://apiros-2.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000007/attilapiros/stdout?start=-4096","stderr":"http://apiros-2.gce.test.com:8042/node/containerlogs/container_1516285256255_0012_01_000007/attilapiros/stderr?start=-4096"}}}
+{"Event":"SparkListenerBlockManagerAdded","Block Manager ID":{"Executor ID":"5","Host":"apiros-2.gce.test.com","Port":45147},"Maximum Memory":956615884,"Timestamp":1516300254385,"Maximum Onheap Memory":956615884,"Maximum Offheap Memory":0}
+{"Event":"SparkListenerJobStart","Job ID":0,"Submission Time":1516300392631,"Stage Infos":[{"Stage ID":0,"Stage Attempt ID":0,"Stage Name":"map at :27","Number of Tasks":10,"RDD Info":[{"RDD ID":1,"Name":"MapPartitionsRDD","Scope":"{\"id\":\"1\",\"name\":\"map\"}","Callsite":"map at :27","Parent IDs":[0],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0},{"RDD ID":0,"Name":"ParallelCollectionRDD","Scope":"{\"id\":\"0\",\"name\":\"parallelize\"}","Callsite":"parallelize at :27","Parent IDs":[],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0}],"Parent IDs":[],"Details":"org.apache.spark.rdd.RDD.map(RDD.scala:370)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:27)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:35)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw.(:37)\n$line15.$read$$iw$$iw$$iw$$iw$$iw.(:39)\n$line15.$read$$iw$$iw$$iw$$iw.(:41)\n$line15.$read$$iw$$iw$$iw.(:43)\n$line15.$read$$iw$$iw.(:45)\n$line15.$read$$iw.(:47)\n$line15.$read.(:49)\n$line15.$read$.(:53)\n$line15.$read$.()\n$line15.$eval$.$print$lzycompute(:7)\n$line15.$eval$.$print(:6)\n$line15.$eval.$print()\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\nscala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:786)","Accumulables":[]},{"Stage ID":1,"Stage Attempt ID":0,"Stage Name":"collect at :30","Number of Tasks":10,"RDD Info":[{"RDD ID":2,"Name":"ShuffledRDD","Scope":"{\"id\":\"2\",\"name\":\"reduceByKey\"}","Callsite":"reduceByKey at :30","Parent IDs":[1],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0}],"Parent IDs":[0],"Details":"org.apache.spark.rdd.RDD.collect(RDD.scala:936)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:30)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:35)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw.(:37)\n$line15.$read$$iw$$iw$$iw$$iw$$iw.(:39)\n$line15.$read$$iw$$iw$$iw$$iw.(:41)\n$line15.$read$$iw$$iw$$iw.(:43)\n$line15.$read$$iw$$iw.(:45)\n$line15.$read$$iw.(:47)\n$line15.$read.(:49)\n$line15.$read$.(:53)\n$line15.$read$.()\n$line15.$eval$.$print$lzycompute(:7)\n$line15.$eval$.$print(:6)\n$line15.$eval.$print()\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\nscala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:786)","Accumulables":[]}],"Stage IDs":[0,1],"Properties":{"spark.rdd.scope.noOverride":"true","spark.rdd.scope":"{\"id\":\"3\",\"name\":\"collect\"}"}}
+{"Event":"SparkListenerStageSubmitted","Stage Info":{"Stage ID":0,"Stage Attempt ID":0,"Stage Name":"map at :27","Number of Tasks":10,"RDD Info":[{"RDD ID":1,"Name":"MapPartitionsRDD","Scope":"{\"id\":\"1\",\"name\":\"map\"}","Callsite":"map at :27","Parent IDs":[0],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0},{"RDD ID":0,"Name":"ParallelCollectionRDD","Scope":"{\"id\":\"0\",\"name\":\"parallelize\"}","Callsite":"parallelize at :27","Parent IDs":[],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0}],"Parent IDs":[],"Details":"org.apache.spark.rdd.RDD.map(RDD.scala:370)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:27)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:35)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw.(:37)\n$line15.$read$$iw$$iw$$iw$$iw$$iw.(:39)\n$line15.$read$$iw$$iw$$iw$$iw.(:41)\n$line15.$read$$iw$$iw$$iw.(:43)\n$line15.$read$$iw$$iw.(:45)\n$line15.$read$$iw.(:47)\n$line15.$read.(:49)\n$line15.$read$.(:53)\n$line15.$read$.()\n$line15.$eval$.$print$lzycompute(:7)\n$line15.$eval$.$print(:6)\n$line15.$eval.$print()\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\nscala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:786)","Submission Time":1516300392658,"Accumulables":[]},"Properties":{"spark.rdd.scope.noOverride":"true","spark.rdd.scope":"{\"id\":\"3\",\"name\":\"collect\"}"}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":0,"Index":0,"Attempt":0,"Launch Time":1516300392816,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":1,"Index":1,"Attempt":0,"Launch Time":1516300392832,"Executor ID":"5","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":2,"Index":2,"Attempt":0,"Launch Time":1516300392832,"Executor ID":"3","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":3,"Index":3,"Attempt":0,"Launch Time":1516300392833,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":4,"Index":4,"Attempt":0,"Launch Time":1516300392833,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":5,"Index":5,"Attempt":0,"Launch Time":1516300394320,"Executor ID":"5","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":6,"Index":6,"Attempt":0,"Launch Time":1516300394323,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"org.apache.spark.scheduler.SparkListenerExecutorBlacklistedForStage","time":1516300394348,"executorId":"5","taskFailures":1,"stageId":0,"stageAttemptId":0}
+{"Event":"org.apache.spark.scheduler.SparkListenerNodeBlacklistedForStage","time":1516300394348,"hostId":"apiros-2.gce.test.com","executorFailures":1,"stageId":0,"stageAttemptId":0}
+{"Event":"org.apache.spark.scheduler.SparkListenerExecutorBlacklistedForStage","time":1516300394356,"executorId":"4","taskFailures":1,"stageId":0,"stageAttemptId":0}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"ExceptionFailure","Class Name":"java.lang.RuntimeException","Description":"Bad executor","Stack Trace":[{"Declaring Class":"$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2","Method Name":"apply","File Name":"","Line Number":28},{"Declaring Class":"$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2","Method Name":"apply","File Name":"","Line Number":27},{"Declaring Class":"scala.collection.Iterator$$anon$11","Method Name":"next","File Name":"Iterator.scala","Line Number":409},{"Declaring Class":"org.apache.spark.util.collection.ExternalSorter","Method Name":"insertAll","File Name":"ExternalSorter.scala","Line Number":193},{"Declaring Class":"org.apache.spark.shuffle.sort.SortShuffleWriter","Method Name":"write","File Name":"SortShuffleWriter.scala","Line Number":63},{"Declaring Class":"org.apache.spark.scheduler.ShuffleMapTask","Method Name":"runTask","File Name":"ShuffleMapTask.scala","Line Number":96},{"Declaring Class":"org.apache.spark.scheduler.ShuffleMapTask","Method Name":"runTask","File Name":"ShuffleMapTask.scala","Line Number":53},{"Declaring Class":"org.apache.spark.scheduler.Task","Method Name":"run","File Name":"Task.scala","Line Number":109},{"Declaring Class":"org.apache.spark.executor.Executor$TaskRunner","Method Name":"run","File Name":"Executor.scala","Line Number":345},{"Declaring Class":"java.util.concurrent.ThreadPoolExecutor","Method Name":"runWorker","File Name":"ThreadPoolExecutor.java","Line Number":1149},{"Declaring Class":"java.util.concurrent.ThreadPoolExecutor$Worker","Method Name":"run","File Name":"ThreadPoolExecutor.java","Line Number":624},{"Declaring Class":"java.lang.Thread","Method Name":"run","File Name":"Thread.java","Line Number":748}],"Full Stack Trace":"java.lang.RuntimeException: Bad executor\n\tat $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.apply(:28)\n\tat $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.apply(:27)\n\tat scala.collection.Iterator$$anon$11.next(Iterator.scala:409)\n\tat org.apache.spark.util.collection.ExternalSorter.insertAll(ExternalSorter.scala:193)\n\tat org.apache.spark.shuffle.sort.SortShuffleWriter.write(SortShuffleWriter.scala:63)\n\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)\n\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)\n\tat org.apache.spark.scheduler.Task.run(Task.scala:109)\n\tat org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:345)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat java.lang.Thread.run(Thread.java:748)\n","Accumulator Updates":[{"ID":2,"Update":"1332","Internal":false,"Count Failed Values":true},{"ID":4,"Update":"0","Internal":false,"Count Failed Values":true},{"ID":5,"Update":"33","Internal":false,"Count Failed Values":true},{"ID":20,"Update":"3075188","Internal":false,"Count Failed Values":true}]},"Task Info":{"Task ID":1,"Index":1,"Attempt":0,"Launch Time":1516300392832,"Executor ID":"5","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300394338,"Failed":true,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":3075188,"Value":3075188,"Internal":true,"Count Failed Values":true},{"ID":5,"Name":"internal.metrics.jvmGCTime","Update":33,"Value":33,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":1332,"Value":1332,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":0,"Executor Deserialize CPU Time":0,"Executor Run Time":1332,"Executor CPU Time":0,"Result Size":0,"JVM GC Time":33,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":3075188,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"ExceptionFailure","Class Name":"java.lang.RuntimeException","Description":"Bad executor","Stack Trace":[{"Declaring Class":"$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2","Method Name":"apply","File Name":"","Line Number":28},{"Declaring Class":"$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2","Method Name":"apply","File Name":"","Line Number":27},{"Declaring Class":"scala.collection.Iterator$$anon$11","Method Name":"next","File Name":"Iterator.scala","Line Number":409},{"Declaring Class":"org.apache.spark.util.collection.ExternalSorter","Method Name":"insertAll","File Name":"ExternalSorter.scala","Line Number":193},{"Declaring Class":"org.apache.spark.shuffle.sort.SortShuffleWriter","Method Name":"write","File Name":"SortShuffleWriter.scala","Line Number":63},{"Declaring Class":"org.apache.spark.scheduler.ShuffleMapTask","Method Name":"runTask","File Name":"ShuffleMapTask.scala","Line Number":96},{"Declaring Class":"org.apache.spark.scheduler.ShuffleMapTask","Method Name":"runTask","File Name":"ShuffleMapTask.scala","Line Number":53},{"Declaring Class":"org.apache.spark.scheduler.Task","Method Name":"run","File Name":"Task.scala","Line Number":109},{"Declaring Class":"org.apache.spark.executor.Executor$TaskRunner","Method Name":"run","File Name":"Executor.scala","Line Number":345},{"Declaring Class":"java.util.concurrent.ThreadPoolExecutor","Method Name":"runWorker","File Name":"ThreadPoolExecutor.java","Line Number":1149},{"Declaring Class":"java.util.concurrent.ThreadPoolExecutor$Worker","Method Name":"run","File Name":"ThreadPoolExecutor.java","Line Number":624},{"Declaring Class":"java.lang.Thread","Method Name":"run","File Name":"Thread.java","Line Number":748}],"Full Stack Trace":"java.lang.RuntimeException: Bad executor\n\tat $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.apply(:28)\n\tat $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.apply(:27)\n\tat scala.collection.Iterator$$anon$11.next(Iterator.scala:409)\n\tat org.apache.spark.util.collection.ExternalSorter.insertAll(ExternalSorter.scala:193)\n\tat org.apache.spark.shuffle.sort.SortShuffleWriter.write(SortShuffleWriter.scala:63)\n\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)\n\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)\n\tat org.apache.spark.scheduler.Task.run(Task.scala:109)\n\tat org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:345)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat java.lang.Thread.run(Thread.java:748)\n","Accumulator Updates":[{"ID":2,"Update":"1184","Internal":false,"Count Failed Values":true},{"ID":4,"Update":"0","Internal":false,"Count Failed Values":true},{"ID":5,"Update":"82","Internal":false,"Count Failed Values":true},{"ID":20,"Update":"16858066","Internal":false,"Count Failed Values":true}]},"Task Info":{"Task ID":4,"Index":4,"Attempt":0,"Launch Time":1516300392833,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300394355,"Failed":true,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":16858066,"Value":19933254,"Internal":true,"Count Failed Values":true},{"ID":5,"Name":"internal.metrics.jvmGCTime","Update":82,"Value":115,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":1184,"Value":2516,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":0,"Executor Deserialize CPU Time":0,"Executor Run Time":1184,"Executor CPU Time":0,"Result Size":0,"JVM GC Time":82,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":16858066,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"ExceptionFailure","Class Name":"java.lang.RuntimeException","Description":"Bad executor","Stack Trace":[{"Declaring Class":"$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2","Method Name":"apply","File Name":"","Line Number":28},{"Declaring Class":"$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2","Method Name":"apply","File Name":"","Line Number":27},{"Declaring Class":"scala.collection.Iterator$$anon$11","Method Name":"next","File Name":"Iterator.scala","Line Number":409},{"Declaring Class":"org.apache.spark.util.collection.ExternalSorter","Method Name":"insertAll","File Name":"ExternalSorter.scala","Line Number":193},{"Declaring Class":"org.apache.spark.shuffle.sort.SortShuffleWriter","Method Name":"write","File Name":"SortShuffleWriter.scala","Line Number":63},{"Declaring Class":"org.apache.spark.scheduler.ShuffleMapTask","Method Name":"runTask","File Name":"ShuffleMapTask.scala","Line Number":96},{"Declaring Class":"org.apache.spark.scheduler.ShuffleMapTask","Method Name":"runTask","File Name":"ShuffleMapTask.scala","Line Number":53},{"Declaring Class":"org.apache.spark.scheduler.Task","Method Name":"run","File Name":"Task.scala","Line Number":109},{"Declaring Class":"org.apache.spark.executor.Executor$TaskRunner","Method Name":"run","File Name":"Executor.scala","Line Number":345},{"Declaring Class":"java.util.concurrent.ThreadPoolExecutor","Method Name":"runWorker","File Name":"ThreadPoolExecutor.java","Line Number":1149},{"Declaring Class":"java.util.concurrent.ThreadPoolExecutor$Worker","Method Name":"run","File Name":"ThreadPoolExecutor.java","Line Number":624},{"Declaring Class":"java.lang.Thread","Method Name":"run","File Name":"Thread.java","Line Number":748}],"Full Stack Trace":"java.lang.RuntimeException: Bad executor\n\tat $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.apply(:28)\n\tat $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.apply(:27)\n\tat scala.collection.Iterator$$anon$11.next(Iterator.scala:409)\n\tat org.apache.spark.util.collection.ExternalSorter.insertAll(ExternalSorter.scala:193)\n\tat org.apache.spark.shuffle.sort.SortShuffleWriter.write(SortShuffleWriter.scala:63)\n\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)\n\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)\n\tat org.apache.spark.scheduler.Task.run(Task.scala:109)\n\tat org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:345)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat java.lang.Thread.run(Thread.java:748)\n","Accumulator Updates":[{"ID":2,"Update":"51","Internal":false,"Count Failed Values":true},{"ID":4,"Update":"0","Internal":false,"Count Failed Values":true},{"ID":20,"Update":"183718","Internal":false,"Count Failed Values":true}]},"Task Info":{"Task ID":6,"Index":6,"Attempt":0,"Launch Time":1516300394323,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300394390,"Failed":true,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":183718,"Value":20116972,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":51,"Value":2567,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":0,"Executor Deserialize CPU Time":0,"Executor Run Time":51,"Executor CPU Time":0,"Result Size":0,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":183718,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"ExceptionFailure","Class Name":"java.lang.RuntimeException","Description":"Bad executor","Stack Trace":[{"Declaring Class":"$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2","Method Name":"apply","File Name":"","Line Number":28},{"Declaring Class":"$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2","Method Name":"apply","File Name":"","Line Number":27},{"Declaring Class":"scala.collection.Iterator$$anon$11","Method Name":"next","File Name":"Iterator.scala","Line Number":409},{"Declaring Class":"org.apache.spark.util.collection.ExternalSorter","Method Name":"insertAll","File Name":"ExternalSorter.scala","Line Number":193},{"Declaring Class":"org.apache.spark.shuffle.sort.SortShuffleWriter","Method Name":"write","File Name":"SortShuffleWriter.scala","Line Number":63},{"Declaring Class":"org.apache.spark.scheduler.ShuffleMapTask","Method Name":"runTask","File Name":"ShuffleMapTask.scala","Line Number":96},{"Declaring Class":"org.apache.spark.scheduler.ShuffleMapTask","Method Name":"runTask","File Name":"ShuffleMapTask.scala","Line Number":53},{"Declaring Class":"org.apache.spark.scheduler.Task","Method Name":"run","File Name":"Task.scala","Line Number":109},{"Declaring Class":"org.apache.spark.executor.Executor$TaskRunner","Method Name":"run","File Name":"Executor.scala","Line Number":345},{"Declaring Class":"java.util.concurrent.ThreadPoolExecutor","Method Name":"runWorker","File Name":"ThreadPoolExecutor.java","Line Number":1149},{"Declaring Class":"java.util.concurrent.ThreadPoolExecutor$Worker","Method Name":"run","File Name":"ThreadPoolExecutor.java","Line Number":624},{"Declaring Class":"java.lang.Thread","Method Name":"run","File Name":"Thread.java","Line Number":748}],"Full Stack Trace":"java.lang.RuntimeException: Bad executor\n\tat $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.apply(:28)\n\tat $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.apply(:27)\n\tat scala.collection.Iterator$$anon$11.next(Iterator.scala:409)\n\tat org.apache.spark.util.collection.ExternalSorter.insertAll(ExternalSorter.scala:193)\n\tat org.apache.spark.shuffle.sort.SortShuffleWriter.write(SortShuffleWriter.scala:63)\n\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)\n\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)\n\tat org.apache.spark.scheduler.Task.run(Task.scala:109)\n\tat org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:345)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat java.lang.Thread.run(Thread.java:748)\n","Accumulator Updates":[{"ID":2,"Update":"27","Internal":false,"Count Failed Values":true},{"ID":4,"Update":"0","Internal":false,"Count Failed Values":true},{"ID":20,"Update":"191901","Internal":false,"Count Failed Values":true}]},"Task Info":{"Task ID":5,"Index":5,"Attempt":0,"Launch Time":1516300394320,"Executor ID":"5","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300394393,"Failed":true,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":191901,"Value":20308873,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":27,"Value":2594,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":0,"Executor Deserialize CPU Time":0,"Executor Run Time":27,"Executor CPU Time":0,"Result Size":0,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":191901,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":2,"Index":2,"Attempt":0,"Launch Time":1516300392832,"Executor ID":"3","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300394606,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":3322956,"Value":23631829,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":3,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":144,"Value":144,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":1080,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":6,"Name":"internal.metrics.resultSerializationTime","Update":1,"Value":1,"Internal":true,"Count Failed Values":true},{"ID":5,"Name":"internal.metrics.jvmGCTime","Update":78,"Value":193,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1134,"Value":1134,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":278399617,"Value":278399617,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":493,"Value":3087,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":263386625,"Value":263386625,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":1206,"Value":1206,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":1206,"Executor Deserialize CPU Time":263386625,"Executor Run Time":493,"Executor CPU Time":278399617,"Result Size":1134,"JVM GC Time":78,"Result Serialization Time":1,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":144,"Shuffle Write Time":3322956,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":7,"Index":5,"Attempt":1,"Launch Time":1516300394859,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":3,"Index":3,"Attempt":0,"Launch Time":1516300392833,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300394860,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":3587839,"Value":27219668,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":6,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":147,"Value":291,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":2160,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":6,"Name":"internal.metrics.resultSerializationTime","Update":1,"Value":2,"Internal":true,"Count Failed Values":true},{"ID":5,"Name":"internal.metrics.jvmGCTime","Update":102,"Value":295,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1134,"Value":2268,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":349920830,"Value":628320447,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":681,"Value":3768,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":365807898,"Value":629194523,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":1282,"Value":2488,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":1282,"Executor Deserialize CPU Time":365807898,"Executor Run Time":681,"Executor CPU Time":349920830,"Result Size":1134,"JVM GC Time":102,"Result Serialization Time":1,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":147,"Shuffle Write Time":3587839,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":8,"Index":6,"Attempt":1,"Launch Time":1516300394879,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":0,"Index":0,"Attempt":0,"Launch Time":1516300392816,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300394880,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":3662221,"Value":30881889,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":9,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":144,"Value":435,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":3240,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":6,"Name":"internal.metrics.resultSerializationTime","Update":1,"Value":3,"Internal":true,"Count Failed Values":true},{"ID":5,"Name":"internal.metrics.jvmGCTime","Update":75,"Value":370,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1134,"Value":3402,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":368865439,"Value":997185886,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":914,"Value":4682,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":353981050,"Value":983175573,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":1081,"Value":3569,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":1081,"Executor Deserialize CPU Time":353981050,"Executor Run Time":914,"Executor CPU Time":368865439,"Result Size":1134,"JVM GC Time":75,"Result Serialization Time":1,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":144,"Shuffle Write Time":3662221,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":9,"Index":4,"Attempt":1,"Launch Time":1516300394973,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":7,"Index":5,"Attempt":1,"Launch Time":1516300394859,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300394974,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":377601,"Value":31259490,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":12,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":147,"Value":582,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":4320,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1048,"Value":4450,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":28283110,"Value":1025468996,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":84,"Value":4766,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":10894331,"Value":994069904,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":11,"Value":3580,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":11,"Executor Deserialize CPU Time":10894331,"Executor Run Time":84,"Executor CPU Time":28283110,"Result Size":1048,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":147,"Shuffle Write Time":377601,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":10,"Index":1,"Attempt":1,"Launch Time":1516300395069,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":9,"Index":4,"Attempt":1,"Launch Time":1516300394973,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395069,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":366050,"Value":31625540,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":15,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":147,"Value":729,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":5400,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":6,"Name":"internal.metrics.resultSerializationTime","Update":1,"Value":4,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1091,"Value":5541,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":25678331,"Value":1051147327,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":48,"Value":4814,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":4793905,"Value":998863809,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":5,"Value":3585,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":5,"Executor Deserialize CPU Time":4793905,"Executor Run Time":48,"Executor CPU Time":25678331,"Result Size":1091,"JVM GC Time":0,"Result Serialization Time":1,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":147,"Shuffle Write Time":366050,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":11,"Index":7,"Attempt":0,"Launch Time":1516300395072,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":8,"Index":6,"Attempt":1,"Launch Time":1516300394879,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395073,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":311940,"Value":31937480,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":18,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":147,"Value":876,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":6480,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1048,"Value":6589,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":27304550,"Value":1078451877,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":54,"Value":4868,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":12246145,"Value":1011109954,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":56,"Value":3641,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":56,"Executor Deserialize CPU Time":12246145,"Executor Run Time":54,"Executor CPU Time":27304550,"Result Size":1048,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":147,"Shuffle Write Time":311940,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":12,"Index":8,"Attempt":0,"Launch Time":1516300395165,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":11,"Index":7,"Attempt":0,"Launch Time":1516300395072,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395165,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":323898,"Value":32261378,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":21,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":147,"Value":1023,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":7560,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1048,"Value":7637,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":21689428,"Value":1100141305,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":77,"Value":4945,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":4239884,"Value":1015349838,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":4,"Value":3645,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":4,"Executor Deserialize CPU Time":4239884,"Executor Run Time":77,"Executor CPU Time":21689428,"Result Size":1048,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":147,"Shuffle Write Time":323898,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":0,"Stage Attempt ID":0,"Task Info":{"Task ID":13,"Index":9,"Attempt":0,"Launch Time":1516300395200,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":10,"Index":1,"Attempt":1,"Launch Time":1516300395069,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395201,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":301705,"Value":32563083,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":24,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":144,"Value":1167,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":8640,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":6,"Name":"internal.metrics.resultSerializationTime","Update":1,"Value":5,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1091,"Value":8728,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":20826337,"Value":1120967642,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":76,"Value":5021,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":4598966,"Value":1019948804,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":5,"Value":3650,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":5,"Executor Deserialize CPU Time":4598966,"Executor Run Time":76,"Executor CPU Time":20826337,"Result Size":1091,"JVM GC Time":0,"Result Serialization Time":1,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":144,"Shuffle Write Time":301705,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":12,"Index":8,"Attempt":0,"Launch Time":1516300395165,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395225,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":319101,"Value":32882184,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":27,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":147,"Value":1314,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":9720,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1048,"Value":9776,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":21657558,"Value":1142625200,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":34,"Value":5055,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":4010338,"Value":1023959142,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":4,"Value":3654,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":4,"Executor Deserialize CPU Time":4010338,"Executor Run Time":34,"Executor CPU Time":21657558,"Result Size":1048,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":147,"Shuffle Write Time":319101,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":0,"Stage Attempt ID":0,"Task Type":"ShuffleMapTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":13,"Index":9,"Attempt":0,"Launch Time":1516300395200,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395276,"Failed":false,"Killed":false,"Accumulables":[{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Update":369513,"Value":33251697,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Update":3,"Value":30,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Update":147,"Value":1461,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Update":1080,"Value":10800,"Internal":true,"Count Failed Values":true},{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Update":1048,"Value":10824,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Update":20585619,"Value":1163210819,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Update":25,"Value":5080,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Update":5860574,"Value":1029819716,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Update":25,"Value":3679,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":25,"Executor Deserialize CPU Time":5860574,"Executor Run Time":25,"Executor CPU Time":20585619,"Result Size":1048,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":147,"Shuffle Write Time":369513,"Shuffle Records Written":3},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerStageCompleted","Stage Info":{"Stage ID":0,"Stage Attempt ID":0,"Stage Name":"map at :27","Number of Tasks":10,"RDD Info":[{"RDD ID":1,"Name":"MapPartitionsRDD","Scope":"{\"id\":\"1\",\"name\":\"map\"}","Callsite":"map at :27","Parent IDs":[0],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0},{"RDD ID":0,"Name":"ParallelCollectionRDD","Scope":"{\"id\":\"0\",\"name\":\"parallelize\"}","Callsite":"parallelize at :27","Parent IDs":[],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0}],"Parent IDs":[],"Details":"org.apache.spark.rdd.RDD.map(RDD.scala:370)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:27)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:35)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw.(:37)\n$line15.$read$$iw$$iw$$iw$$iw$$iw.(:39)\n$line15.$read$$iw$$iw$$iw$$iw.(:41)\n$line15.$read$$iw$$iw$$iw.(:43)\n$line15.$read$$iw$$iw.(:45)\n$line15.$read$$iw.(:47)\n$line15.$read.(:49)\n$line15.$read$.(:53)\n$line15.$read$.()\n$line15.$eval$.$print$lzycompute(:7)\n$line15.$eval$.$print(:6)\n$line15.$eval.$print()\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\nscala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:786)","Submission Time":1516300392658,"Completion Time":1516300395279,"Accumulables":[{"ID":8,"Name":"internal.metrics.diskBytesSpilled","Value":0,"Internal":true,"Count Failed Values":true},{"ID":2,"Name":"internal.metrics.executorRunTime","Value":5080,"Internal":true,"Count Failed Values":true},{"ID":20,"Name":"internal.metrics.shuffle.write.writeTime","Value":33251697,"Internal":true,"Count Failed Values":true},{"ID":5,"Name":"internal.metrics.jvmGCTime","Value":370,"Internal":true,"Count Failed Values":true},{"ID":4,"Name":"internal.metrics.resultSize","Value":10824,"Internal":true,"Count Failed Values":true},{"ID":7,"Name":"internal.metrics.memoryBytesSpilled","Value":0,"Internal":true,"Count Failed Values":true},{"ID":1,"Name":"internal.metrics.executorDeserializeCpuTime","Value":1029819716,"Internal":true,"Count Failed Values":true},{"ID":19,"Name":"internal.metrics.shuffle.write.recordsWritten","Value":30,"Internal":true,"Count Failed Values":true},{"ID":9,"Name":"internal.metrics.peakExecutionMemory","Value":10800,"Internal":true,"Count Failed Values":true},{"ID":18,"Name":"internal.metrics.shuffle.write.bytesWritten","Value":1461,"Internal":true,"Count Failed Values":true},{"ID":3,"Name":"internal.metrics.executorCpuTime","Value":1163210819,"Internal":true,"Count Failed Values":true},{"ID":6,"Name":"internal.metrics.resultSerializationTime","Value":5,"Internal":true,"Count Failed Values":true},{"ID":0,"Name":"internal.metrics.executorDeserializeTime","Value":3679,"Internal":true,"Count Failed Values":true}]}}
+{"Event":"SparkListenerStageSubmitted","Stage Info":{"Stage ID":1,"Stage Attempt ID":0,"Stage Name":"collect at :30","Number of Tasks":10,"RDD Info":[{"RDD ID":2,"Name":"ShuffledRDD","Scope":"{\"id\":\"2\",\"name\":\"reduceByKey\"}","Callsite":"reduceByKey at :30","Parent IDs":[1],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0}],"Parent IDs":[0],"Details":"org.apache.spark.rdd.RDD.collect(RDD.scala:936)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:30)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:35)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw.(:37)\n$line15.$read$$iw$$iw$$iw$$iw$$iw.(:39)\n$line15.$read$$iw$$iw$$iw$$iw.(:41)\n$line15.$read$$iw$$iw$$iw.(:43)\n$line15.$read$$iw$$iw.(:45)\n$line15.$read$$iw.(:47)\n$line15.$read.(:49)\n$line15.$read$.(:53)\n$line15.$read$.()\n$line15.$eval$.$print$lzycompute(:7)\n$line15.$eval$.$print(:6)\n$line15.$eval.$print()\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\nscala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:786)","Submission Time":1516300395292,"Accumulables":[]},"Properties":{"spark.rdd.scope.noOverride":"true","spark.rdd.scope":"{\"id\":\"3\",\"name\":\"collect\"}"}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":14,"Index":0,"Attempt":0,"Launch Time":1516300395302,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"NODE_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":15,"Index":1,"Attempt":0,"Launch Time":1516300395303,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"NODE_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":16,"Index":3,"Attempt":0,"Launch Time":1516300395304,"Executor ID":"5","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":17,"Index":4,"Attempt":0,"Launch Time":1516300395304,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":18,"Index":5,"Attempt":0,"Launch Time":1516300395304,"Executor ID":"3","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":19,"Index":6,"Attempt":0,"Launch Time":1516300395525,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":17,"Index":4,"Attempt":0,"Launch Time":1516300395304,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395525,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1134,"Value":1134,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":52455999,"Value":52455999,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":95,"Value":95,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":23136577,"Value":23136577,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":82,"Value":82,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":82,"Executor Deserialize CPU Time":23136577,"Executor Run Time":95,"Executor CPU Time":52455999,"Result Size":1134,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":20,"Index":7,"Attempt":0,"Launch Time":1516300395575,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":19,"Index":6,"Attempt":0,"Launch Time":1516300395525,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395576,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1134,"Value":2268,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":13617615,"Value":66073614,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":29,"Value":124,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":3469612,"Value":26606189,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":4,"Value":86,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":4,"Executor Deserialize CPU Time":3469612,"Executor Run Time":29,"Executor CPU Time":13617615,"Result Size":1134,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":21,"Index":8,"Attempt":0,"Launch Time":1516300395581,"Executor ID":"3","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":18,"Index":5,"Attempt":0,"Launch Time":1516300395304,"Executor ID":"3","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395581,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1134,"Value":3402,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":55540208,"Value":121613822,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":179,"Value":303,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":22400065,"Value":49006254,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":78,"Value":164,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":78,"Executor Deserialize CPU Time":22400065,"Executor Run Time":179,"Executor CPU Time":55540208,"Result Size":1134,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":22,"Index":9,"Attempt":0,"Launch Time":1516300395593,"Executor ID":"5","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":16,"Index":3,"Attempt":0,"Launch Time":1516300395304,"Executor ID":"5","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395593,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1134,"Value":4536,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":52311573,"Value":173925395,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":153,"Value":456,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":20519033,"Value":69525287,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":67,"Value":231,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":67,"Executor Deserialize CPU Time":20519033,"Executor Run Time":153,"Executor CPU Time":52311573,"Result Size":1134,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":20,"Index":7,"Attempt":0,"Launch Time":1516300395575,"Executor ID":"4","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395660,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1134,"Value":5670,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":11294260,"Value":185219655,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":33,"Value":489,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":3570887,"Value":73096174,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":4,"Value":235,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":4,"Executor Deserialize CPU Time":3570887,"Executor Run Time":33,"Executor CPU Time":11294260,"Result Size":1134,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":22,"Index":9,"Attempt":0,"Launch Time":1516300395593,"Executor ID":"5","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395669,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1134,"Value":6804,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":12983732,"Value":198203387,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":44,"Value":533,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":3518757,"Value":76614931,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":4,"Value":239,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":4,"Executor Deserialize CPU Time":3518757,"Executor Run Time":44,"Executor CPU Time":12983732,"Result Size":1134,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":21,"Index":8,"Attempt":0,"Launch Time":1516300395581,"Executor ID":"3","Host":"apiros-2.gce.test.com","Locality":"PROCESS_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395674,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1134,"Value":7938,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":14706240,"Value":212909627,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":64,"Value":597,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":7698059,"Value":84312990,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":21,"Value":260,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":21,"Executor Deserialize CPU Time":7698059,"Executor Run Time":64,"Executor CPU Time":14706240,"Result Size":1134,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":0,"Local Blocks Fetched":0,"Fetch Wait Time":0,"Remote Bytes Read":0,"Remote Bytes Read To Disk":0,"Local Bytes Read":0,"Total Records Read":0},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskStart","Stage ID":1,"Stage Attempt ID":0,"Task Info":{"Task ID":23,"Index":2,"Attempt":0,"Launch Time":1516300395686,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"NODE_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":0,"Failed":false,"Killed":false,"Accumulables":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":14,"Index":0,"Attempt":0,"Launch Time":1516300395302,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"NODE_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395687,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":10,"Value":10,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":52,"Value":52,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":195,"Value":195,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":292,"Value":292,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":4,"Value":4,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":6,"Value":6,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":944,"Value":944,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1286,"Value":9224,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":91696783,"Value":304606410,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":221,"Value":818,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":24063461,"Value":108376451,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":150,"Value":410,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":150,"Executor Deserialize CPU Time":24063461,"Executor Run Time":221,"Executor CPU Time":91696783,"Result Size":1286,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":6,"Local Blocks Fetched":4,"Fetch Wait Time":52,"Remote Bytes Read":292,"Remote Bytes Read To Disk":0,"Local Bytes Read":195,"Total Records Read":10},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":15,"Index":1,"Attempt":0,"Launch Time":1516300395303,"Executor ID":"2","Host":"apiros-3.gce.test.com","Locality":"NODE_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395687,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":10,"Value":20,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":107,"Value":159,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":244,"Value":439,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":243,"Value":535,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":5,"Value":9,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":5,"Value":11,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":944,"Value":1888,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1286,"Value":10510,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":91683507,"Value":396289917,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":289,"Value":1107,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":22106726,"Value":130483177,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":79,"Value":489,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":79,"Executor Deserialize CPU Time":22106726,"Executor Run Time":289,"Executor CPU Time":91683507,"Result Size":1286,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":5,"Local Blocks Fetched":5,"Fetch Wait Time":107,"Remote Bytes Read":243,"Remote Bytes Read To Disk":0,"Local Bytes Read":244,"Total Records Read":10},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerTaskEnd","Stage ID":1,"Stage Attempt ID":0,"Task Type":"ResultTask","Task End Reason":{"Reason":"Success"},"Task Info":{"Task ID":23,"Index":2,"Attempt":0,"Launch Time":1516300395686,"Executor ID":"1","Host":"apiros-3.gce.test.com","Locality":"NODE_LOCAL","Speculative":false,"Getting Result Time":0,"Finish Time":1516300395728,"Failed":false,"Killed":false,"Accumulables":[{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Update":10,"Value":30,"Internal":true,"Count Failed Values":true},{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Update":0,"Value":159,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Update":195,"Value":634,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Update":292,"Value":827,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Update":4,"Value":13,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Update":6,"Value":17,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Update":944,"Value":2832,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Update":0,"Value":0,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Update":1286,"Value":11796,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Update":17607810,"Value":413897727,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Update":33,"Value":1140,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Update":2897647,"Value":133380824,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Update":2,"Value":491,"Internal":true,"Count Failed Values":true}]},"Task Metrics":{"Executor Deserialize Time":2,"Executor Deserialize CPU Time":2897647,"Executor Run Time":33,"Executor CPU Time":17607810,"Result Size":1286,"JVM GC Time":0,"Result Serialization Time":0,"Memory Bytes Spilled":0,"Disk Bytes Spilled":0,"Shuffle Read Metrics":{"Remote Blocks Fetched":6,"Local Blocks Fetched":4,"Fetch Wait Time":0,"Remote Bytes Read":292,"Remote Bytes Read To Disk":0,"Local Bytes Read":195,"Total Records Read":10},"Shuffle Write Metrics":{"Shuffle Bytes Written":0,"Shuffle Write Time":0,"Shuffle Records Written":0},"Input Metrics":{"Bytes Read":0,"Records Read":0},"Output Metrics":{"Bytes Written":0,"Records Written":0},"Updated Blocks":[]}}
+{"Event":"SparkListenerStageCompleted","Stage Info":{"Stage ID":1,"Stage Attempt ID":0,"Stage Name":"collect at :30","Number of Tasks":10,"RDD Info":[{"RDD ID":2,"Name":"ShuffledRDD","Scope":"{\"id\":\"2\",\"name\":\"reduceByKey\"}","Callsite":"reduceByKey at :30","Parent IDs":[1],"Storage Level":{"Use Disk":false,"Use Memory":false,"Deserialized":false,"Replication":1},"Number of Partitions":10,"Number of Cached Partitions":0,"Memory Size":0,"Disk Size":0}],"Parent IDs":[0],"Details":"org.apache.spark.rdd.RDD.collect(RDD.scala:936)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:30)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw.(:35)\n$line15.$read$$iw$$iw$$iw$$iw$$iw$$iw.(:37)\n$line15.$read$$iw$$iw$$iw$$iw$$iw.(:39)\n$line15.$read$$iw$$iw$$iw$$iw.(:41)\n$line15.$read$$iw$$iw$$iw.(:43)\n$line15.$read$$iw$$iw.(:45)\n$line15.$read$$iw.(:47)\n$line15.$read.(:49)\n$line15.$read$.(:53)\n$line15.$read$.()\n$line15.$eval$.$print$lzycompute(:7)\n$line15.$eval$.$print(:6)\n$line15.$eval.$print()\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\nscala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:786)","Submission Time":1516300395292,"Completion Time":1516300395728,"Accumulables":[{"ID":41,"Name":"internal.metrics.shuffle.read.fetchWaitTime","Value":159,"Internal":true,"Count Failed Values":true},{"ID":32,"Name":"internal.metrics.memoryBytesSpilled","Value":0,"Internal":true,"Count Failed Values":true},{"ID":26,"Name":"internal.metrics.executorDeserializeCpuTime","Value":133380824,"Internal":true,"Count Failed Values":true},{"ID":29,"Name":"internal.metrics.resultSize","Value":11796,"Internal":true,"Count Failed Values":true},{"ID":38,"Name":"internal.metrics.shuffle.read.remoteBytesRead","Value":827,"Internal":true,"Count Failed Values":true},{"ID":40,"Name":"internal.metrics.shuffle.read.localBytesRead","Value":634,"Internal":true,"Count Failed Values":true},{"ID":25,"Name":"internal.metrics.executorDeserializeTime","Value":491,"Internal":true,"Count Failed Values":true},{"ID":34,"Name":"internal.metrics.peakExecutionMemory","Value":2832,"Internal":true,"Count Failed Values":true},{"ID":37,"Name":"internal.metrics.shuffle.read.localBlocksFetched","Value":13,"Internal":true,"Count Failed Values":true},{"ID":28,"Name":"internal.metrics.executorCpuTime","Value":413897727,"Internal":true,"Count Failed Values":true},{"ID":27,"Name":"internal.metrics.executorRunTime","Value":1140,"Internal":true,"Count Failed Values":true},{"ID":36,"Name":"internal.metrics.shuffle.read.remoteBlocksFetched","Value":17,"Internal":true,"Count Failed Values":true},{"ID":39,"Name":"internal.metrics.shuffle.read.remoteBytesReadToDisk","Value":0,"Internal":true,"Count Failed Values":true},{"ID":42,"Name":"internal.metrics.shuffle.read.recordsRead","Value":30,"Internal":true,"Count Failed Values":true},{"ID":33,"Name":"internal.metrics.diskBytesSpilled","Value":0,"Internal":true,"Count Failed Values":true}]}}
+{"Event":"SparkListenerJobEnd","Job ID":0,"Completion Time":1516300395734,"Job Result":{"Result":"JobSucceeded"}}
+{"Event":"SparkListenerApplicationEnd","Timestamp":1516300707938}
diff --git a/omniadvisor/src/test/resources/test-spark.conf b/omniadvisor/src/test/resources/test-spark.conf
new file mode 100644
index 0000000000000000000000000000000000000000..6cbe2baeb6e87dde158fa3a7d5fab538d4c8c1dc
--- /dev/null
+++ b/omniadvisor/src/test/resources/test-spark.conf
@@ -0,0 +1 @@
+spark.master yarn
\ No newline at end of file
diff --git a/omnicache/omnicache-spark-extension/plugin/src/main/scala/com/huawei/boostkit/spark/util/ViewMetadata.scala b/omnicache/omnicache-spark-extension/plugin/src/main/scala/com/huawei/boostkit/spark/util/ViewMetadata.scala
deleted file mode 100644
index a3ab16e76d12e1d5a6903a238ae029be8b523486..0000000000000000000000000000000000000000
--- a/omnicache/omnicache-spark-extension/plugin/src/main/scala/com/huawei/boostkit/spark/util/ViewMetadata.scala
+++ /dev/null
@@ -1,197 +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 com.huawei.boostkit.spark.util
-
-import com.huawei.boostkit.spark.conf.OmniCachePluginConfig._
-import java.util.concurrent.ConcurrentHashMap
-import scala.collection.mutable
-
-import org.apache.spark.sql.SparkSession
-import org.apache.spark.sql.catalyst.TableIdentifier
-import org.apache.spark.sql.catalyst.catalog.{CatalogTable, SessionCatalog}
-import org.apache.spark.sql.catalyst.optimizer.rules.RewriteTime
-import org.apache.spark.sql.catalyst.plans.logical.{LogicalPlan, RepartitionByExpression, SubqueryAlias}
-
-object ViewMetadata extends RewriteHelper {
-
- val viewToViewQueryPlan = new ConcurrentHashMap[String, LogicalPlan]()
-
- val viewToTablePlan = new ConcurrentHashMap[String, LogicalPlan]()
-
- val viewToContainsTables = new ConcurrentHashMap[String, Set[TableEqual]]()
-
- val tableToViews = new ConcurrentHashMap[String, mutable.Set[String]]()
-
- var spark: SparkSession = _
-
- val STATUS_UN_LOAD = "UN_LOAD"
- val STATUS_LOADING = "LOADING"
- val STATUS_LOADED = "LOADED"
-
- var status: String = STATUS_UN_LOAD
-
- def setSpark(sparkSession: SparkSession): Unit = {
- spark = sparkSession
- status = STATUS_LOADING
- }
-
- def saveViewMetadataToMap(catalogTable: CatalogTable): Unit = this.synchronized {
- // if QUERY_REWRITE_ENABLED is false, doesn't load ViewMetadata
- if (!catalogTable.properties.getOrElse(MV_REWRITE_ENABLED, "false").toBoolean) {
- return
- }
-
- val viewQuerySql = catalogTable.properties.getOrElse(MV_QUERY_ORIGINAL_SQL, "")
- if (viewQuerySql.isEmpty) {
- logError(s"mvTable: ${catalogTable.identifier.quotedString}'s viewQuerySql is empty!")
- return
- }
-
- // preserve preDatabase and set curDatabase
- val preDatabase = spark.catalog.currentDatabase
- val curDatabase = catalogTable.properties.getOrElse(MV_QUERY_ORIGINAL_SQL_CUR_DB, "")
- if (curDatabase.isEmpty) {
- logError(s"mvTable: ${catalogTable.identifier.quotedString}'s curDatabase is empty!")
- return
- }
- try {
- spark.sessionState.catalogManager.setCurrentNamespace(Array(curDatabase))
-
- // db.table
- val tableName = catalogTable.identifier.quotedString
- val viewTablePlan = RewriteTime
- .withTimeStat("viewTablePlan") {
- spark.table(tableName).queryExecution.analyzed match {
- case SubqueryAlias(_, child) => child
- case a@_ => a
- }
- }
- var viewQueryPlan = RewriteTime
- .withTimeStat("viewQueryPlan") {
- spark.sql(viewQuerySql).queryExecution.analyzed
- }
- viewQueryPlan = viewQueryPlan match {
- case RepartitionByExpression(_, child, _) =>
- child
- case _ =>
- viewQueryPlan
- }
- // reset preDatabase
- spark.sessionState.catalogManager.setCurrentNamespace(Array(preDatabase))
-
- // spark_catalog.db.table
- val viewName = catalogTable.identifier.toString()
-
- // mappedViewQueryPlan and mappedViewContainsTables
- val (mappedViewQueryPlan, mappedViewContainsTables) = RewriteTime
- .withTimeStat("extractTables") {
- extractTables(viewQueryPlan)
- }
-
- mappedViewContainsTables
- .foreach { mappedViewContainsTable =>
- val name = mappedViewContainsTable.tableName
- val views = tableToViews.getOrDefault(name, mutable.Set.empty)
- views += viewName
- tableToViews.put(name, views)
- }
-
- // extract view query project's Attr and replace view table's Attr by query project's Attr
- // match function is attributeReferenceEqualSimple, by name and data type
- // Attr of table cannot used, because same Attr in view query and view table,
- // it's table is different.
- val mappedViewTablePlan = RewriteTime
- .withTimeStat("mapTablePlanAttrToQuery") {
- mapTablePlanAttrToQuery(viewTablePlan, mappedViewQueryPlan)
- }
-
- viewToContainsTables.put(viewName, mappedViewContainsTables)
- viewToViewQueryPlan.putIfAbsent(viewName, mappedViewQueryPlan)
- viewToTablePlan.putIfAbsent(viewName, mappedViewTablePlan)
- } catch {
- case e: Throwable =>
- logDebug(s"Failed to saveViewMetadataToMap,errmsg: ${e.getMessage}")
- // reset preDatabase
- spark.sessionState.catalogManager.setCurrentNamespace(Array(preDatabase))
- }
- }
-
- def isEmpty: Boolean = {
- viewToTablePlan.isEmpty
- }
-
- def isViewExists(viewIdentifier: String): Boolean = {
- viewToTablePlan.containsKey(viewIdentifier)
- }
-
- def addCatalogTableToCache(table: CatalogTable): Unit = this.synchronized {
- saveViewMetadataToMap(table)
- }
-
- def removeMVCache(tableName: TableIdentifier): Unit = this.synchronized {
- val viewName = tableName.toString()
- viewToContainsTables.remove(viewName)
- viewToViewQueryPlan.remove(viewName)
- viewToTablePlan.remove(viewName)
- tableToViews.forEach { (key, value) =>
- if (value.contains(viewName)) {
- value -= viewName
- tableToViews.put(key, value)
- }
- }
- }
-
- def init(sparkSession: SparkSession): Unit = {
- if (status == STATUS_LOADED) {
- return
- }
-
- setSpark(sparkSession)
- forceLoad()
- status = STATUS_LOADED
- }
-
- def forceLoad(): Unit = this.synchronized {
- val catalog = spark.sessionState.catalog
-
- // load from all db
- for (db <- catalog.listDatabases()) {
- val tables = RewriteTime.withTimeStat("loadTable") {
- omniCacheFilter(catalog, db)
- }
- RewriteTime.withTimeStat("saveViewMetadataToMap") {
- tables.foreach(tableData => saveViewMetadataToMap(tableData))
- }
- }
- }
-
- def omniCacheFilter(catalog: SessionCatalog,
- mvDataBase: String): Seq[CatalogTable] = {
- try {
- val allTables = catalog.listTables(mvDataBase)
- catalog.getTablesByName(allTables).filter { tableData =>
- tableData.properties.contains(MV_QUERY_ORIGINAL_SQL)
- }
- } catch {
- // if db exists a table hive materialized view, will throw analysis exception
- case e: Throwable =>
- logDebug(s"Failed to listTables in $mvDataBase, errmsg: ${e.getMessage}")
- Seq.empty[CatalogTable]
- }
- }
-}
diff --git a/omnidata/omnidata-hive-connector/build.sh b/omnidata/omnidata-hive-connector/build.sh
deleted file mode 100644
index 98c426e22cc430cc1268816c9355bc13d98b8c9f..0000000000000000000000000000000000000000
--- a/omnidata/omnidata-hive-connector/build.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-mvn clean package
-jar_name=`ls -n connector/target/*.jar | grep hive-exec | awk -F ' ' '{print$9}' | awk -F '/' '{print$3}'`
-dir_name=`ls -n connector/target/*.jar | grep hive-exec | awk -F ' ' '{print$9}' | awk -F '/' '{print$3}' | awk -F '.jar' '{print$1}'`
-rm -r $dir_name
-rm -r $dir_name.zip
-mkdir -p $dir_name
-cp connector/target/$jar_name $dir_name
-cd $dir_name
-wget https://mirrors.huaweicloud.com/repository/maven/org/bouncycastle/bcpkix-jdk15on/1.68/bcpkix-jdk15on-1.68.jar
-wget https://mirrors.huaweicloud.com/repository/maven/org/bouncycastle/bcprov-jdk15on/1.68/bcprov-jdk15on-1.68.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/google/guava/guava/31.1-jre/guava-31.1-jre.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/hetu/core/hetu-transport/1.6.1/hetu-transport-1.6.1.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/core/jackson-annotations/2.12.4/jackson-annotations-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/core/jackson-core/2.12.4/jackson-core-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/core/jackson-databind/2.12.4/jackson-databind-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/datatype/jackson-datatype-guava/2.12.4/jackson-datatype-guava-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.12.4/jackson-datatype-jdk8-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/datatype/jackson-datatype-joda/2.12.4/jackson-datatype-joda-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.12.4/jackson-datatype-jsr310-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/module/jackson-module-parameter-names/2.12.4/jackson-module-parameter-names-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/org/jasypt/jasypt/1.9.3/jasypt-1.9.3.jar
-wget https://mirrors.huaweicloud.com/repository/maven/org/openjdk/jol/jol-core/0.2/jol-core-0.2.jar
-wget https://repo1.maven.org/maven2/io/airlift/joni/2.1.5.3/joni-2.1.5.3.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/esotericsoftware/kryo-shaded/4.0.2/kryo-shaded-4.0.2.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/airlift/log/0.193/log-0.193.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/perfmark/perfmark-api/0.23.0/perfmark-api-0.23.0.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/hetu/core/presto-main/1.6.1/presto-main-1.6.1.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/hetu/core/presto-spi/1.6.1/presto-spi-1.6.1.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/google/protobuf/protobuf-java/3.12.0/protobuf-java-3.12.0.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/airlift/slice/0.38/slice-0.38.jar
-cd ..
-zip -r -o $dir_name.zip $dir_name
-rm -r $dir_name
\ No newline at end of file
diff --git a/omnidata/omnidata-hive-connector/hive_build.sh b/omnidata/omnidata-hive-connector/hive_build.sh
new file mode 100644
index 0000000000000000000000000000000000000000..d32e27957388b29725cadb3ba05fd4cf0a8f56cb
--- /dev/null
+++ b/omnidata/omnidata-hive-connector/hive_build.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+mvn clean package
+jar_name=`ls -n connector/target/*.jar | grep hive-exec | awk -F ' ' '{print$9}' | awk -F '/' '{print$3}'`
+dir_name=`ls -n connector/target/*.jar | grep hive-exec | awk -F ' ' '{print$9}' | awk -F '/' '{print$3}' | awk -F '.jar' '{print$1}'`
+if [ -d "${dir_name}" ];then rm -rf ${dir_name}; fi
+if [ -d "${dir_name}.zip" ];then rm -rf ${dir_name}.zip; fi
+mkdir -p $dir_name
+cp connector/target/$jar_name $dir_name
+cd $dir_name
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/bcpkix-jdk15on/1.68/package/bcpkix-jdk15on-1.68.jar
+wget --proxy=off --no-check-certificate https://cmc-hgh-artifactory.cmc.tools.huawei.com/artifactory/opensource_general/guava/31.1-jre/package/guava-31.1-jre.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/hetu-transport/1.6.1/package/hetu-transport-1.6.1.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/jackson-annotations/2.12.4/package/jackson-annotations-2.12.4.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/jackson-core/2.12.4/package/jackson-core-2.12.4.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/jackson-databind/2.12.4/package/jackson-databind-2.12.4.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/jackson-datatype-guava/2.12.4/package/jackson-datatype-guava-2.12.4.jar
+wget --proxy=off --no-check-certificate https://cmc-hgh-artifactory.cmc.tools.huawei.com/artifactory/opensource_general/jackson-datatype-jdk8/2.12.4/package/jackson-datatype-jdk8-2.12.4.jar
+wget --proxy=off --no-check-certificate https://cmc-hgh-artifactory.cmc.tools.huawei.com/artifactory/opensource_general/Jackson-datatype-Joda/2.12.4/package/jackson-datatype-joda-2.12.4.jar
+wget --proxy=off --no-check-certificate https://cmc-hgh-artifactory.cmc.tools.huawei.com/artifactory/opensource_general/jackson-datatype-jsr310/2.12.4/package/jackson-datatype-jsr310-2.12.4.jar
+wget --proxy=off --no-check-certificate https://cmc-hgh-artifactory.cmc.tools.huawei.com/artifactory/opensource_general/jackson-module-parameter-names/2.12.4/package/jackson-module-parameter-names-2.12.4.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/jasypt/1.9.3/package/jasypt-1.9.3.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/jol-core/0.2/package/jol-core-0.2.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/joni/2.1.5.3/package/joni-2.1.5.3.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/kryo-shaded/4.0.2/package/kryo-shaded-4.0.2.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/log/0.193/package/log-0.193.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/perfmark-api/0.23.0/package/perfmark-api-0.23.0.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/presto-main/1.6.1/package/presto-main-1.6.1.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/presto-spi/1.6.1/package/presto-spi-1.6.1.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/protobuf-java/3.12.0/package/protobuf-java-3.12.0.jar
+wget --proxy=off --no-check-certificate https://cmc.cloudartifact.szv.dragon.tools.huawei.com/artifactory/opensource_general/slice/0.38/package/slice-0.38.jar
+cd ..
+zip -r -o $dir_name.zip $dir_name
\ No newline at end of file
diff --git a/omnidata/omnidata-server-lib/pom.xml b/omnidata/omnidata-server-lib/pom.xml
index a782bd38e282d3132443ba1c01f14822f9aa255a..13ebeb82298dbca42b7598a5a6dfdf65b1f90144 100644
--- a/omnidata/omnidata-server-lib/pom.xml
+++ b/omnidata/omnidata-server-lib/pom.xml
@@ -7,18 +7,24 @@
com.huawei.boostkit
omnidata-server-lib
pom
- 1.4.0
+ 1.5.0
${os.detected.arch}
2.11.4
1.2.3
- 1.6.1
+ 1.9.0
206
2.12.0
+ 0.9
+
+ net.openhft
+ zero-allocation-hashing
+ ${dep.net.openhft.version}
+
com.fasterxml.jackson.core
jackson-databind
@@ -96,11 +102,6 @@
-
- com.google.guava
- guava
- 30.0-jre
-
io.prestosql.hadoop
hadoop-apache
@@ -231,6 +232,21 @@
+
+ io.hetu.core
+ presto-expressions
+ ${dep.hetu.version}
+
+
+ io.hetu.core
+ hetu-common
+ ${dep.hetu.version}
+
+
+ com.google.guava
+ guava
+ 30.0-jre
+
io.airlift
units
diff --git a/omnidata/omnidata-spark-connector/README.md b/omnidata/omnidata-spark-connector/README.md
index c773c416e83311847a6aea19163aaf83aa5d9492..de2c8b8c72f7ae75d7346a6306e4dbe70c901bee 100644
--- a/omnidata/omnidata-spark-connector/README.md
+++ b/omnidata/omnidata-spark-connector/README.md
@@ -5,7 +5,7 @@
Introduction
============
-The omnidata spark connector library running on Kunpeng processors is a Spark SQL plugin that pushes computing-side operators to storage nodes for computing. It is developed based on original APIs of Apache [Spark 3.0.0](https://github.com/apache/spark/tree/v3.0.0). This library applies to the big data storage separation scenario or large-scale fusion scenario where a large number of compute nodes read data from remote nodes. In this scenario, a large amount of raw data is transferred from storage nodes to compute nodes over the network for processing, resulting in a low proportion of valid data and a huge waste of network bandwidth. You can find the latest documentation, including a programming guide, on the project web page. This README file only contains basic setup instructions.
+The omnidata spark connector library running on Kunpeng processors is a Spark SQL plugin that pushes computing-side operators to storage nodes for computing. It is developed based on original APIs of Apache [Spark 3.1.1](https://github.com/apache/spark/tree/v3.1.1). This library applies to the big data storage separation scenario or large-scale fusion scenario where a large number of compute nodes read data from remote nodes. In this scenario, a large amount of raw data is transferred from storage nodes to compute nodes over the network for processing, resulting in a low proportion of valid data and a huge waste of network bandwidth. You can find the latest documentation, including a programming guide, on the project web page. This README file only contains basic setup instructions.
Building And Packageing
diff --git a/omnidata/omnidata-spark-connector/build.sh b/omnidata/omnidata-spark-connector/build.sh
deleted file mode 100644
index 7a528d4476b1a6d758054576f289d09ce8ae9c3e..0000000000000000000000000000000000000000
--- a/omnidata/omnidata-spark-connector/build.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-mvn clean package
-jar_name=`ls -n connector/target/*.jar | grep omnidata-spark | awk -F ' ' '{print$9}' | awk -F '/' '{print$3}'`
-dir_name=`ls -n connector/target/*.jar | grep omnidata-spark | awk -F ' ' '{print$9}' | awk -F '/' '{print$3}' | awk -F '.jar' '{print$1}'`
-rm -r $dir_name-aarch64
-rm -r $dir_name-aarch64.zip
-mkdir -p $dir_name-aarch64
-cp connector/target/$jar_name $dir_name-aarch64
-cd $dir_name-aarch64
-wget https://mirrors.huaweicloud.com/repository/maven/org/bouncycastle/bcpkix-jdk15on/1.68/bcpkix-jdk15on-1.68.jar
-wget https://mirrors.huaweicloud.com/repository/maven/org/apache/curator/curator-client/2.12.0/curator-client-2.12.0.jar
-wget https://mirrors.huaweicloud.com/repository/maven/org/apache/curator/curator-framework/2.12.0/curator-framework-2.12.0.jar
-wget https://mirrors.huaweicloud.com/repository/maven/org/apache/curator/curator-recipes/2.12.0/curator-recipes-2.12.0.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/alibaba/fastjson/1.2.76/fastjson-1.2.76.jar
-wget https://mirrors.huaweicloud.com/repository/maven/de/ruedigermoeller/fst/2.57/fst-2.57.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/google/guava/guava/26.0-jre/guava-26.0-jre.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/hetu/core/hetu-transport/1.6.1/hetu-transport-1.6.1.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/datatype/jackson-datatype-guava/2.12.4/jackson-datatype-guava-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.12.4/jackson-datatype-jdk8-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/datatype/jackson-datatype-joda/2.12.4/jackson-datatype-joda-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.12.4/jackson-datatype-jsr310-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/fasterxml/jackson/module/jackson-module-parameter-names/2.12.4/jackson-module-parameter-names-2.12.4.jar
-wget https://mirrors.huaweicloud.com/repository/maven/org/jasypt/jasypt/1.9.3/jasypt-1.9.3.jar
-wget https://mirrors.huaweicloud.com/repository/maven/org/openjdk/jol/jol-core/0.2/jol-core-0.2.jar
-wget https://repo1.maven.org/maven2/io/airlift/joni/2.1.5.3/joni-2.1.5.3.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/airlift/log/0.193/log-0.193.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/perfmark/perfmark-api/0.23.0/perfmark-api-0.23.0.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/hetu/core/presto-main/1.6.1/presto-main-1.6.1.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/hetu/core/presto-spi/1.6.1/presto-spi-1.6.1.jar
-wget https://mirrors.huaweicloud.com/repository/maven/com/google/protobuf/protobuf-java/3.12.0/protobuf-java-3.12.0.jar
-wget https://mirrors.huaweicloud.com/repository/maven/io/airlift/slice/0.38/slice-0.38.jar
-cd ..
-zip -r -o $dir_name-aarch64.zip $dir_name-aarch64
-rm -r $dir_name-aarch64
\ No newline at end of file
diff --git a/omnidata/omnidata-spark-connector/connector/pom.xml b/omnidata/omnidata-spark-connector/connector/pom.xml
index 4fd2668b10b13f63ccef418c56af7ee9d1bfe8ce..6062530d9b26a1182ed29572f06b5ff811c7eaba 100644
--- a/omnidata/omnidata-spark-connector/connector/pom.xml
+++ b/omnidata/omnidata-spark-connector/connector/pom.xml
@@ -5,12 +5,12 @@
org.apache.spark
omnidata-spark-connector-root
- 1.4.0
+ 1.5.0
4.0.0
boostkit-omnidata-spark-sql_2.12-3.1.1
- 1.4.0
+ 1.5.0
boostkit omnidata spark sql
2021
jar
@@ -24,8 +24,14 @@
2.12.0
1.6.1
1.35.0
+ 2.12
+
+ io.hetu.core
+ presto-expressions
+ ${dep.hetu.version}
+
org.apache.spark
spark-hive_2.12
@@ -55,7 +61,7 @@
com.huawei.boostkit
boostkit-omnidata-stub
- 1.4.0
+ 1.5.0
compile
@@ -73,9 +79,111 @@
curator-recipes
${dep.curator.version}
+
+
+
+ io.airlift
+ log
+ 206
+ test
+
+
+ io.airlift
+ stats
+ 206
+
+
+ org.apache.lucene
+ lucene-analyzers-common
+ 7.2.1
+
+
+ it.unimi.dsi
+ fastutil
+ 6.5.9
+
+
+ io.airlift
+ bytecode
+ 1.2
+
+
+ io.hetu.core
+ presto-parser
+ ${dep.hetu.version}
+ test
+
+
+ io.airlift
+ json
+ 206
+
+
+ org.testng
+ testng
+ 6.10
+ test
+
+
+ org.mockito
+ mockito-core
+ 1.9.5
+ test
+
+
+ objenesis
+ org.objenesis
+
+
+
+
+ org.scalatest
+ scalatest_${scala.binary.version}
+ 3.2.3
+ test
+
+
+ org.apache.spark
+ spark-core_${scala.binary.version}
+ test-jar
+ test
+ ${spark.version}
+
+
+ org.apache.spark
+ spark-sql_${scala.binary.version}
+ test-jar
+ ${spark.version}
+ test
+
+
+ org.apache.spark
+ spark-catalyst_${scala.binary.version}
+ test-jar
+ test
+ ${spark.version}
+
+
+ org.apache.spark
+ spark-hive-thriftserver_${scala.binary.version}
+ test
+ ${spark.version}
+
+
+ org.apache.spark
+ spark-hive_${scala.binary.version}
+ test
+ ${spark.version}
+
+
+ org.apache.hive
+ hive-cli
+ 2.3.7
+
src/main/scala
+ src/test/java
org.codehaus.mojo
diff --git a/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/NdpConnectorUtils.java b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/NdpConnectorUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..9d0937625f48aa4ca15a601f274e0e05760944fc
--- /dev/null
+++ b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/NdpConnectorUtils.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+ * 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 com.huawei.boostkit.omnidata.spark;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+public class NdpConnectorUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NdpConnectorUtils.class);
+ public static Set getIpAddress() {
+ Set ipSet = new HashSet<>();
+ try {
+ Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces();
+ while (allNetInterfaces.hasMoreElements()) {
+ NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
+ if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
+ continue;
+ }
+ Enumeration addresses = netInterface.getInetAddresses();
+ while (addresses.hasMoreElements()) {
+ InetAddress ip = addresses.nextElement();
+ if (ip instanceof Inet4Address) {
+ ipSet.add(ip.getHostAddress());
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("getIpAddress exception:", e);
+ }
+ return ipSet;
+ }
+
+ public static boolean isNumeric(String str) {
+ return str != null && str.chars().allMatch(Character::isDigit);
+ }
+
+ private static int getIntSysEnv(String envName, int defaultVal) {
+ String val = System.getenv(envName);
+ if (isNumeric(val) && Integer.parseInt(val) > 0) {
+ return Integer.parseInt(val);
+ }
+ return defaultVal;
+ }
+
+ private static String getIntStrSysEnv(String envName, String defaultVal) {
+ String val = System.getenv(envName);
+ if (isNumeric(val) && Integer.parseInt(val) > 0) {
+ return val;
+ }
+ return defaultVal;
+ }
+
+ public static boolean getNdpEnable() {
+ String isEnable = System.getenv("NDP_PLUGIN_ENABLE");
+ return isEnable != null && isEnable.equals("true");
+ }
+
+ public static int getPushDownTaskTotal(int taskTotal) {
+ return getIntSysEnv("DEFAULT_PUSHDOWN_TASK", taskTotal);
+ }
+
+ public static String getNdpNumPartitionsStr(String numStr) {
+ return getIntStrSysEnv("DEFAULT_NDP_NUM_PARTITIONS", numStr);
+ }
+
+ public static int getCountTaskTotal(int taskTotal) {
+ return getIntSysEnv("COUNT_TASK_TOTAL", taskTotal);
+ }
+
+ public static String getCountMaxPartSize(String size) {
+ return System.getenv("COUNT_MAX_PART_SIZE") != null ?
+ System.getenv("COUNT_MAX_PART_SIZE") : size;
+ }
+
+ public static int getCountDistinctTaskTotal(int taskTotal) {
+ return getIntSysEnv("COUNT_DISTINCT_TASK_TOTAL", taskTotal);
+ }
+
+ public static String getSMJMaxPartSize(String size) {
+ return System.getenv("SMJ_MAX_PART_SIZE") != null ?
+ System.getenv("SMJ_MAX_PART_SIZE") : size;
+ }
+
+ public static int getSMJNumPartitions(int numPartitions) {
+ return getIntSysEnv("SMJ_NUM_PARTITIONS", numPartitions);
+ }
+
+ public static int getOmniColumnarNumPartitions(int numPartitions) {
+ return getIntSysEnv("OMNI_COLUMNAR_PARTITIONS", numPartitions);
+ }
+
+ public static int getOmniColumnarTaskCount(int taskTotal) {
+ return getIntSysEnv("OMNI_COLUMNAR_TASK_TOTAL", taskTotal);
+ }
+
+ public static int getFilterPartitions(int numPartitions) {
+ return getIntSysEnv("FILTER_COLUMNAR_PARTITIONS", numPartitions);
+ }
+
+ public static int getFilterTaskCount(int taskTotal) {
+ return getIntSysEnv("FILTER_TASK_TOTAL", taskTotal);
+ }
+
+ public static String getSortRepartitionSizeStr(String sizeStr) {
+ return System.getenv("SORT_REPARTITION_SIZE") != null ?
+ System.getenv("SORT_REPARTITION_SIZE") : sizeStr;
+ }
+
+ public static String getCastDecimalPrecisionStr(String numStr) {
+ return System.getenv("CAST_DECIMAL_PRECISION") != null ?
+ System.getenv("CAST_DECIMAL_PRECISION") : numStr;
+ }
+
+ public static String getNdpMaxPtFactorStr(String numStr) {
+ return System.getenv("NDP_MAX_PART_FACTOR") != null ?
+ System.getenv("NDP_MAX_PART_FACTOR") : numStr;
+ }
+
+ public static String getCountAggMaxFilePtBytesStr(String BytesStr) {
+ return System.getenv("COUNT_AGG_MAX_FILE_BYTES") != null ?
+ System.getenv("COUNT_AGG_MAX_FILE_BYTES") : BytesStr;
+ }
+
+ public static String getAvgAggMaxFilePtBytesStr(String BytesStr) {
+ return System.getenv("AVG_AGG_MAX_FILE_BYTES") != null ?
+ System.getenv("AVG_AGG_MAX_FILE_BYTES") : BytesStr;
+ }
+
+ public static String getBhjMaxFilePtBytesStr(String BytesStr) {
+ return System.getenv("BHJ_MAX_FILE_BYTES") != null ?
+ System.getenv("BHJ_MAX_FILE_BYTES") : BytesStr;
+ }
+
+ public static String getGroupMaxFilePtBytesStr(String BytesStr) {
+ return System.getenv("GROUP_MAX_FILE_BYTES") != null ?
+ System.getenv("GROUP_MAX_FILE_BYTES") : BytesStr;
+ }
+
+ public static String getMixSqlBaseMaxFilePtBytesStr(String BytesStr) {
+ return System.getenv("MIX_SQL_BASE_MAX_FILE_BYTES") != null ?
+ System.getenv("MIX_SQL_BASE_MAX_FILE_BYTES") : BytesStr;
+ }
+
+ public static String getMixSqlAccurateMaxFilePtBytesStr(String BytesStr) {
+ return System.getenv("MIX_SQL_ACCURATE_MAX_FILE_BYTES") != null ?
+ System.getenv("MIX_SQL_ACCURATE_MAX_FILE_BYTES") : BytesStr;
+ }
+
+ public static String getAggShufflePartitionsStr(String BytesStr) {
+ return System.getenv("AGG_SHUFFLE_PARTITIONS") != null ?
+ System.getenv("AGG_SHUFFLE_PARTITIONS") : BytesStr;
+ }
+
+ public static String getShufflePartitionsStr(String BytesStr) {
+ return System.getenv("SHUFFLE_PARTITIONS") != null ?
+ System.getenv("SHUFFLE_PARTITIONS") : BytesStr;
+ }
+
+ public static String getSortShufflePartitionsStr(String BytesStr) {
+ return System.getenv("SORT_SHUFFLE_PARTITIONS") != null ?
+ System.getenv("SORT_SHUFFLE_PARTITIONS") : BytesStr;
+ }
+}
diff --git a/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/OperatorPageDeRunLength.java b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/OperatorPageDeRunLength.java
new file mode 100644
index 0000000000000000000000000000000000000000..8dbde71f4428d026c0d0cea583c7d7a16efe411a
--- /dev/null
+++ b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/OperatorPageDeRunLength.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+ * 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 com.huawei.boostkit.omnidata.spark;
+
+import org.apache.spark.sql.execution.vectorized.OmniColumnVector;
+import org.apache.spark.sql.execution.vectorized.WritableColumnVector;
+
+/**
+ * DeCompress RunLength for combine with operator
+ *
+ * @since 2023-07-20
+ */
+public class OperatorPageDeRunLength extends PageDeRunLength {
+ @Override
+ protected WritableColumnVector getColumnVector(int positionCount, WritableColumnVector writableColumnVector) {
+ return new OmniColumnVector(positionCount, writableColumnVector.dataType(), true);
+ }
+}
\ No newline at end of file
diff --git a/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/OperatorPageDecoding.java b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/OperatorPageDecoding.java
new file mode 100644
index 0000000000000000000000000000000000000000..afaa26066f35457cf798b6ee7e1291c0842cecb7
--- /dev/null
+++ b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/OperatorPageDecoding.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+ * 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 com.huawei.boostkit.omnidata.spark;
+
+import com.huawei.boostkit.omnidata.decode.type.*;
+import io.airlift.slice.SliceInput;
+import org.apache.spark.sql.execution.util.SparkMemoryUtils;
+import org.apache.spark.sql.execution.vectorized.OmniColumnVector;
+import org.apache.spark.sql.execution.vectorized.WritableColumnVector;
+import org.apache.spark.sql.types.DataType;
+import org.apache.spark.sql.types.DataTypes;
+import org.apache.spark.sql.types.DecimalType;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Optional;
+
+/**
+ * Decode data to spark writableColumnVector for combine with operator
+ *
+ * @since 2023-07-20
+ */
+public class OperatorPageDecoding extends PageDecoding {
+
+ static {
+ SparkMemoryUtils.init();
+ }
+
+ public OperatorPageDecoding(String fileFormat) {
+ super(fileFormat);
+ }
+
+ @Override
+ public Optional decodeVariableWidth(Optional type, SliceInput sliceInput) {
+ int positionCount = sliceInput.readInt();
+ return decodeVariableWidthBase(type, sliceInput,
+ new OmniColumnVector(positionCount, DataTypes.StringType, true), positionCount);
+ }
+
+ @Override
+ public Optional decodeRunLength(Optional type, SliceInput sliceInput)
+ throws InvocationTargetException, IllegalAccessException {
+ return decodeRunLengthBase(type, sliceInput, new OperatorPageDeRunLength());
+ }
+
+ @Override
+ protected WritableColumnVector createColumnVectorForDecimal(int positionCount, DecimalType decimalType) {
+ return new OmniColumnVector(positionCount, decimalType, true);
+ }
+
+ @Override
+ protected Optional decodeSimple(
+ SliceInput sliceInput,
+ DataType dataType,
+ String dataTypeName) {
+ int positionCount = sliceInput.readInt();
+ WritableColumnVector columnVector = new OmniColumnVector(positionCount, dataType, true);
+ return getWritableColumnVector(sliceInput, positionCount, columnVector, dataTypeName);
+ }
+}
\ No newline at end of file
diff --git a/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/PageDeRunLength.java b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/PageDeRunLength.java
index 7802b7b5ab0fbd0880b123f6ae69ac6cf1acf546..0a3ca5db223d633996eeda21244798c3112c01c5 100644
--- a/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/PageDeRunLength.java
+++ b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/PageDeRunLength.java
@@ -20,7 +20,6 @@ package com.huawei.boostkit.omnidata.spark;
import org.apache.spark.sql.execution.vectorized.OnHeapColumnVector;
import org.apache.spark.sql.execution.vectorized.WritableColumnVector;
-import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.Decimal;
import org.apache.spark.sql.types.DecimalType;
@@ -54,7 +53,7 @@ public class PageDeRunLength {
public Optional decompressByteArray(int positionCount,
WritableColumnVector writableColumnVector) throws Exception {
byte value = writableColumnVector.getByte(0);
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, DataTypes.ByteType);
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
if (writableColumnVector.isNullAt(0)) {
columnVector.putNulls(0, positionCount);
} else {
@@ -78,7 +77,7 @@ public class PageDeRunLength {
public Optional decompressBooleanArray(int positionCount,
WritableColumnVector writableColumnVector) throws Exception {
boolean value = writableColumnVector.getBoolean(0);
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, DataTypes.BooleanType);
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
if (writableColumnVector.isNullAt(0)) {
columnVector.putNulls(0, positionCount);
} else {
@@ -102,7 +101,7 @@ public class PageDeRunLength {
public Optional decompressIntArray(int positionCount,
WritableColumnVector writableColumnVector) throws Exception {
int value = writableColumnVector.getInt(0);
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, DataTypes.IntegerType);
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
if (writableColumnVector.isNullAt(0)) {
columnVector.putNulls(0, positionCount);
} else {
@@ -126,7 +125,7 @@ public class PageDeRunLength {
public Optional decompressShortArray(int positionCount,
WritableColumnVector writableColumnVector) throws Exception {
short value = writableColumnVector.getShort(0);
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, DataTypes.ShortType);
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
if (writableColumnVector.isNullAt(0)) {
columnVector.putNulls(0, positionCount);
} else {
@@ -150,7 +149,7 @@ public class PageDeRunLength {
public Optional decompressLongArray(int positionCount,
WritableColumnVector writableColumnVector) throws Exception {
long value = writableColumnVector.getLong(0);
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, DataTypes.LongType);
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
if (writableColumnVector.isNullAt(0)) {
columnVector.putNulls(0, positionCount);
} else {
@@ -174,7 +173,7 @@ public class PageDeRunLength {
public Optional decompressFloatArray(int positionCount,
WritableColumnVector writableColumnVector) throws Exception {
float value = writableColumnVector.getFloat(0);
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, DataTypes.FloatType);
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
if (writableColumnVector.isNullAt(0)) {
columnVector.putNulls(0, positionCount);
} else {
@@ -198,7 +197,7 @@ public class PageDeRunLength {
public Optional decompressDoubleArray(int positionCount,
WritableColumnVector writableColumnVector) throws Exception {
double value = writableColumnVector.getDouble(0);
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, DataTypes.DoubleType);
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
if (writableColumnVector.isNullAt(0)) {
columnVector.putNulls(0, positionCount);
} else {
@@ -221,7 +220,7 @@ public class PageDeRunLength {
*/
public Optional decompressVariableWidth(int positionCount,
WritableColumnVector writableColumnVector) throws Exception {
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, DataTypes.StringType);
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
if (writableColumnVector.isNullAt(0)) {
columnVector.putNulls(0, positionCount);
} else {
@@ -247,11 +246,11 @@ public class PageDeRunLength {
int precision = ((DecimalType) writableColumnVector.dataType()).precision();
int scale = ((DecimalType) writableColumnVector.dataType()).scale();
Decimal value = writableColumnVector.getDecimal(0, precision, scale);
- WritableColumnVector columnVector = new OnHeapColumnVector(positionCount, writableColumnVector.dataType());
- for (int rowId = 0; rowId < positionCount; rowId++) {
- if (writableColumnVector.isNullAt(rowId)) {
- columnVector.putNull(rowId);
- } else {
+ WritableColumnVector columnVector = getColumnVector(positionCount, writableColumnVector);
+ if (writableColumnVector.isNullAt(0)) {
+ columnVector.putNulls(0, positionCount);
+ } else {
+ for (int rowId = 0; rowId < positionCount; rowId++) {
columnVector.putDecimal(rowId, value, precision);
}
}
@@ -262,4 +261,8 @@ public class PageDeRunLength {
}
return Optional.of(columnVector);
}
-}
+
+ protected WritableColumnVector getColumnVector(int positionCount, WritableColumnVector writableColumnVector) {
+ return PageDecoding.createColumnVector(positionCount, writableColumnVector.dataType());
+ }
+}
\ No newline at end of file
diff --git a/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/PageDecoding.java b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/PageDecoding.java
index 5d46338bdb5d2791491d53623dddc6725d588c55..e140dfd7c4125a9b7a18a125b49093e2ecab51a1 100644
--- a/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/PageDecoding.java
+++ b/omnidata/omnidata-spark-connector/connector/src/main/java/com/huawei/boostkit/omnidata/spark/PageDecoding.java
@@ -21,7 +21,6 @@ package com.huawei.boostkit.omnidata.spark;
import static io.airlift.slice.SizeOf.SIZE_OF_INT;
import static java.lang.Double.longBitsToDouble;
import static java.lang.Float.intBitsToFloat;
-import static org.apache.spark.sql.types.DataTypes.TimestampType;
import com.huawei.boostkit.omnidata.decode.AbstractDecoding;
import com.huawei.boostkit.omnidata.decode.type.*;
@@ -30,13 +29,19 @@ import com.huawei.boostkit.omnidata.exception.OmniDataException;
import io.airlift.slice.SliceInput;
import io.airlift.slice.Slices;
import io.prestosql.spi.type.DateType;
-
import io.prestosql.spi.type.Decimals;
+
+import org.apache.spark.sql.catalyst.util.RebaseDateTime;
+import org.apache.spark.sql.execution.vectorized.OffHeapColumnVector;
import org.apache.spark.sql.execution.vectorized.OnHeapColumnVector;
import org.apache.spark.sql.execution.vectorized.WritableColumnVector;
+import org.apache.spark.sql.internal.SQLConf;
+import org.apache.spark.sql.types.DataType;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.Decimal;
import org.apache.spark.sql.types.DecimalType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -53,7 +58,12 @@ import java.util.TimeZone;
* @since 2021-03-30
*/
public class PageDecoding extends AbstractDecoding