-
Notifications
You must be signed in to change notification settings - Fork 198
Snap 293 #310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Snap 293 #310
Changes from all commits
da5373e
2ffce11
66c8e7e
3dca0ed
451b882
d73fc7c
1071de8
08eed39
d4ae45b
bf7d61f
3fc761a
04bdb74
327bdef
1d1f87d
1b999fd
6bf1d2f
2ed90a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| /* | ||
| * Copyright (c) 2016 SnappyData, Inc. 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. See accompanying | ||
| * LICENSE file. | ||
| */ | ||
|
|
||
|
|
||
| package io.snappydata.cluster | ||
|
|
||
| import java.io.File | ||
| import java.sql.{Connection, DriverManager} | ||
| import io.snappydata.test.dunit.AvailablePortHelper | ||
| import org.apache.spark.sql.SnappyContext | ||
| import org.apache.spark.sql.collection.{Utils => Utility} | ||
| import org.apache.spark.util.SnappyUtils | ||
|
|
||
| class DynamicJarInstallationDUnitTest(val s: String) | ||
| extends ClusterManagerTestBase(s) { | ||
|
|
||
|
|
||
| override def tearDown2(): Unit = { | ||
| Array(vm3, vm2, vm1, vm0).foreach(_.invoke(getClass, "stopNetworkServers")) | ||
| bootProps.clear() | ||
| } | ||
|
|
||
| private def getANetConnection(netPort: Int): Connection = { | ||
| val driver = "com.pivotal.gemfirexd.jdbc.ClientDriver" | ||
| // scalastyle:off classforname | ||
| Class.forName(driver).newInstance | ||
| val url = "jdbc:snappydata://localhost:" + netPort + "/" | ||
| DriverManager.getConnection(url) | ||
| } | ||
|
|
||
| def testJarDeployedOnExecutors(): Unit = { | ||
| val snc = SnappyContext(sc) | ||
|
|
||
| sc.addJar(DynamicJarInstallationDUnitTest.original.getPath) | ||
|
|
||
| // loading Jar class after installing the jar. | ||
|
|
||
| var countInstances = Utility.mapExecutors(snc, | ||
| () => { | ||
| if (DynamicJarInstallationDUnitTest.loadClass("FakeClass1", "1", false)) { | ||
| Seq(1).iterator | ||
| } else Iterator.empty | ||
| }).count | ||
|
|
||
| assert(countInstances == 3) | ||
|
|
||
| // replace the jar file and load again | ||
|
|
||
| val modifiedJarPath = DynamicJarInstallationDUnitTest.modified | ||
|
|
||
| sc.addJar(modifiedJarPath.getPath) | ||
|
|
||
|
|
||
| // loading Jar class after installing the jar | ||
| countInstances = Utility.mapExecutors(snc, | ||
| () => { | ||
| if (DynamicJarInstallationDUnitTest.loadClass("FakeClass1", "1", true)) { | ||
| Seq(1).iterator | ||
| } else Iterator.empty | ||
| }).count | ||
|
|
||
| assert(countInstances == 0) | ||
|
|
||
| // try to verify another class. | ||
| countInstances = Utility.mapExecutors(snc, | ||
| () => { | ||
| if (DynamicJarInstallationDUnitTest.loadClass("FakeClass2", "2", false)) { | ||
| Seq(1).iterator | ||
| } else Iterator.empty | ||
| }).count | ||
|
|
||
| assert(countInstances == 3) | ||
| } | ||
|
|
||
| def testJarDeployementwithSnappyshell(): Unit = { | ||
| val snc = SnappyContext(sc) | ||
| val sqlJars = SnappyUtils.createJarWithClasses( | ||
| classNames = Seq("FakeClass4", "FakeClass5", "FakeClass6"), | ||
| toStringValue = "3" , | ||
| Seq.empty, Seq.empty , | ||
| "testJar_SNAPPY_JOB_SERVER_JAR_%s.jar".format(System.currentTimeMillis())) | ||
|
|
||
| // test basic operations on snappyContext | ||
| snc.sql("create table test (x int) using column") | ||
| snc.dropTable("test") | ||
|
|
||
| val netPort1 = AvailablePortHelper.getRandomAvailableTCPPort | ||
| vm2.invoke(classOf[ClusterManagerTestBase], "startNetServer", netPort1) | ||
| val conn = getANetConnection(netPort1) | ||
|
|
||
| val stmt = conn.createStatement() | ||
|
|
||
| stmt.execute("call sqlj.install_jar('" + sqlJars.getPath + "', 'app.sqlJars', 0)") | ||
|
|
||
| // look for jar inside the executors | ||
| var countInstances = Utility.mapExecutors(snc, | ||
| () => { | ||
| if (DynamicJarInstallationDUnitTest.loadClass("FakeClass5", "3")) { | ||
| Seq(1).iterator | ||
| } else Iterator.empty | ||
| }).count | ||
|
|
||
| assert(countInstances == 3) | ||
|
|
||
| // remove the jar and check again | ||
| stmt.execute("call sqlj.remove_jar('app.sqlJars', 0)") | ||
|
|
||
| // look for jar inside the executors | ||
| countInstances = Utility.mapExecutors(snc, | ||
| () => { | ||
| if (DynamicJarInstallationDUnitTest.loadClass("FakeClass5", "3", true)) { | ||
| Seq(1).iterator | ||
| } else Iterator.empty | ||
| }).count | ||
|
|
||
| assert(countInstances == 0) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| object DynamicJarInstallationDUnitTest { | ||
|
|
||
| val original = SnappyUtils.createJarWithClasses( | ||
| classNames = Seq("FakeClass1", "FakeClass2", "FakeClass3"), | ||
| toStringValue = "1", | ||
| Seq.empty, Seq.empty , | ||
| "testJar_SNAPPY_JOB_SERVER_JAR_%s.jar".format(System.currentTimeMillis())) | ||
|
|
||
| val modified = SnappyUtils.createJarWithClasses( | ||
| classNames = Seq("FakeClass2", "FakeClass3", "FakeClass4"), | ||
| toStringValue = "2", | ||
| Seq.empty, Seq.empty , | ||
| "testJar_SNAPPY_JOB_SERVER_JAR_%s.jar".format(System.currentTimeMillis())) | ||
|
|
||
| @throws[ClassNotFoundException] | ||
| def loadClass(className: String, | ||
| version: String = "", | ||
| catchExpectedException: Boolean = false): Boolean = { | ||
| val loader = Thread.currentThread().getContextClassLoader | ||
| assert(loader != null) | ||
| try { | ||
| val fakeClass = loader.loadClass(className).newInstance() | ||
| assert(fakeClass != null) | ||
| if (!version.isEmpty) assert(fakeClass.toString.equals(version)) | ||
| true | ||
| } catch { | ||
| case cnfe: ClassNotFoundException => | ||
| if (!catchExpectedException) throw cnfe | ||
| else false | ||
| } | ||
| } | ||
|
|
||
| def getModifiedJar: String = { | ||
| val oldFile = new File(original.getPath) | ||
| val newFile = new File(modified.getPath) | ||
| if (oldFile.exists()) { | ||
| assert( oldFile.delete() == true) | ||
| } | ||
| assert (newFile.renameTo(oldFile) == true) | ||
| oldFile.getAbsolutePath | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,28 +18,33 @@ | |
|
|
||
|
|
||
| import com.typesafe.config.Config; | ||
| import org.apache.spark.sql.JSparkJobValidation; | ||
| import org.apache.spark.sql.JavaJobValidate; | ||
| import org.apache.spark.sql.streaming.SnappyStreamingJob; | ||
| import org.apache.spark.sql.SnappyJobValidate; | ||
| import org.apache.spark.sql.SnappyJobValidation; | ||
| import org.apache.spark.streaming.api.java.JavaSnappyStreamingContext; | ||
|
|
||
| import spark.jobserver.SparkJobBase; | ||
| import spark.jobserver.SparkJobValidation; | ||
| import org.apache.spark.util.SnappyUtils; | ||
| import org.apache.spark.util.Utils; | ||
|
|
||
| public abstract class JavaSnappyStreamingJob implements SnappyStreamingJob { | ||
| public abstract class JavaSnappyStreamingJob implements SparkJobBase { | ||
|
|
||
| abstract public Object runJavaJob(JavaSnappyStreamingContext snc, Config jobConfig); | ||
| abstract public Object runSnappyJob(JavaSnappyStreamingContext snc, Config jobConfig); | ||
|
|
||
| abstract public JSparkJobValidation isValidJob(JavaSnappyStreamingContext snc, | ||
| abstract public SnappyJobValidation isValidJob(JavaSnappyStreamingContext snc, | ||
| Config jobConfig); | ||
|
|
||
| @Override | ||
| public Object runJob(Object sc, Config jobConfig) { | ||
| return runJavaJob(new JavaSnappyStreamingContext((SnappyStreamingContext)sc), jobConfig); | ||
| final public SparkJobValidation validate(Object sc, Config config) { | ||
| ClassLoader parentLoader = Utils.getContextOrSparkClassLoader(); | ||
| ClassLoader currentLoader = SnappyUtils.getSnappyStoreContextLoader(parentLoader); | ||
| Thread.currentThread().setContextClassLoader(currentLoader); | ||
| return SnappyJobValidate.validate(isValidJob(new JavaSnappyStreamingContext((SnappyStreamingContext)sc), config)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line looks too long; please break |
||
| } | ||
|
|
||
| @Override | ||
| public SparkJobValidation validate(Object sc, Config config) { | ||
| JSparkJobValidation status = | ||
| isValidJob(new JavaSnappyStreamingContext((SnappyStreamingContext)sc), config); | ||
| return JavaJobValidate.validate(status); | ||
| final public Object runJob(Object sc, Config jobConfig) { | ||
| return runSnappyJob(new JavaSnappyStreamingContext((SnappyStreamingContext)sc), jobConfig); | ||
| } | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* | ||
| * Copyright (c) 2016 SnappyData, Inc. 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. See accompanying | ||
| * LICENSE file. | ||
| */ | ||
| package org.apache.spark.executor | ||
|
|
||
| import java.net.URL | ||
|
|
||
| import org.apache.spark.SparkEnv | ||
| import org.apache.spark.util.{DynamicURLClassLoader, MutableURLClassLoader} | ||
|
|
||
| class SnappyExecutor( | ||
| executorId: String, | ||
| executorHostname: String, | ||
| env: SparkEnv, | ||
| userClassPath: Seq[URL] = Nil, | ||
| isLocal: Boolean = false) | ||
| extends Executor(executorId, executorHostname, env, userClassPath , isLocal) { | ||
|
|
||
| private val overwriteFiles = env.conf.getBoolean("spark.files.overwrite", false) | ||
|
|
||
| override def createClassLoader(urls: Array[URL], | ||
| parentLoader: ClassLoader, userClassPathFirst: Boolean): MutableURLClassLoader = { | ||
| new DynamicURLClassLoader(urls, parentLoader, parentFirst = !userClassPathFirst , overwriteFiles) | ||
| } | ||
|
|
||
| } | ||
|
|
||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This override can also be added for IsolatedClientLoader.classLoader. It is used for any external JDBC URLs apart from our gemxd drivers (e.g. if user wishes to use it to load data into gemxd). If it is not added there, we need docs on how user should go about doing it (perhaps JDBC drivers have to be in SPARK_DIST_CLASSPATH while other parts will be fine with dynamic install-jar).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will remove the following line as it is not needed after the changes in the job server. The Job server always create a new jar file where we have added our own suffix in the name so now executor knows that the jar belongs to the same job and it can reload it. executors can also copy this jar as it is a new jar for them. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this rename? I suppose the idea was to emphasize that the code needs to use the Java wrapper JavaSnappyStreamingContext (and not the regular SnappyStreamingContext). @rishitesh your thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was more to do with type resolution in case of scala generic type. The API proposed is looking cleaner if its running all the tests. As use only have to deal with two methods. Only input types will change.